Skip to content

Commit 24c9db3

Browse files
committed
ref stuff
1 parent 5934cf9 commit 24c9db3

10 files changed

Lines changed: 72 additions & 92 deletions

File tree

dev-packages/e2e-tests/test-applications/create-remix-app-v2/instrument.server.cjs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,4 @@ Sentry.init({
1515
environment: 'qa', // dynamic sampling bias to keep transactions
1616
dsn: process.env.E2E_TEST_DSN,
1717
tunnel: 'http://localhost:3031/', // proxy server
18-
// In the orchestrion variant, the channel-based Remix integration replaces the default
19-
// OpenTelemetry one (same `Remix` name, so it overwrites the default).
20-
integrations: injectOrchestrion ? [Sentry.remixChannelIntegration()] : [],
2118
});

dev-packages/e2e-tests/test-applications/create-remix-app-v2/tests/build-injection.test.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,7 @@ test.describe('orchestrion build-time injection', () => {
3333

3434
test('injects the diagnostics-channel publishers into @remix-run/server-runtime', () => {
3535
// Remix's own instrumentation is orchestrion-based too: the transform force-bundles
36-
// and injects channels into `@remix-run/server-runtime` (the subscriber is
37-
// `remixChannelIntegration`).
36+
// and injects channels into `@remix-run/server-runtime`
3837
expect(serverBundle).toMatch(
3938
/tracingChannel(\$?\d)?\(["']orchestrion:@remix-run\/server-runtime:requestHandler["']\)/,
4039
);

packages/remix/src/server/index.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,5 +145,4 @@ export { init, getRemixDefaultIntegrations } from './sdk';
145145
export { captureRemixServerException } from './errors';
146146
export { sentryHandleError, wrapHandleErrorWithSentry, instrumentBuild } from './instrumentServer';
147147
export { generateSentryServerTimingHeader } from './serverTimingTracePropagation';
148-
export { remixChannelIntegration } from './integrations/tracing-channel';
149-
export { remixIntegration } from './integrations/opentelemetry';
148+
export { remixIntegration } from './integrations';
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import type { IntegrationFn } from '@sentry/core';
2+
import { defineIntegration, getClient } from '@sentry/core';
3+
import { isOrchestrionInjected } from '@sentry/server-utils/orchestrion';
4+
import { instrumentRemix } from './tracing-channel';
5+
import { addRemixSpanAttributes, instrumentRemixWithOpenTelemetry } from './opentelemetry';
6+
import type { RemixOptions } from '../../utils/remixOptions';
7+
8+
const INTEGRATION_NAME = 'Remix' as const;
9+
10+
const _remixIntegration = (() => {
11+
return {
12+
name: INTEGRATION_NAME,
13+
setupOnce() {
14+
const client = getClient();
15+
const options = client?.getOptions() as RemixOptions | undefined;
16+
const actionFormDataAttributes = client?.getDataCollectionOptions().httpBodies.includes('incomingRequest')
17+
? options?.captureActionFormDataKeys
18+
: undefined;
19+
20+
if (isOrchestrionInjected()) {
21+
instrumentRemix(actionFormDataAttributes);
22+
} else {
23+
instrumentRemixWithOpenTelemetry(actionFormDataAttributes);
24+
}
25+
},
26+
setup(client) {
27+
if (!isOrchestrionInjected()) {
28+
client.on('spanStart', span => {
29+
addRemixSpanAttributes(span);
30+
});
31+
}
32+
},
33+
};
34+
}) satisfies IntegrationFn;
35+
36+
/**
37+
* Instrument server-side Remix requests to emit spans.
38+
*/
39+
export const remixIntegration = defineIntegration(_remixIntegration);
Lines changed: 11 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import type { Client, IntegrationFn, Span } from '@sentry/core';
2-
import { defineIntegration, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/core';
3-
import { generateInstrumentOnce, getClient, spanToJSON } from '@sentry/node';
4-
import type { RemixOptions } from '../../utils/remixOptions';
1+
import type { Span } from '@sentry/core';
2+
import { SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/core';
3+
import { generateInstrumentOnce, spanToJSON } from '@sentry/node';
54
import { RemixInstrumentation } from '../../vendor/instrumentation';
65

76
const INTEGRATION_NAME = 'Remix';
@@ -10,33 +9,14 @@ interface RemixInstrumentationOptions {
109
actionFormDataAttributes?: Record<string, string | boolean>;
1110
}
1211

13-
const instrumentRemix = generateInstrumentOnce(INTEGRATION_NAME, (options?: RemixInstrumentationOptions) => {
14-
return new RemixInstrumentation(options);
15-
});
12+
export const instrumentRemixWithOpenTelemetry = generateInstrumentOnce(
13+
INTEGRATION_NAME,
14+
(options?: RemixInstrumentationOptions) => {
15+
return new RemixInstrumentation(options);
16+
},
17+
);
1618

17-
const _remixIntegration = (() => {
18-
return {
19-
name: 'Remix' as const,
20-
setupOnce() {
21-
const client = getClient();
22-
const options = client?.getOptions() as RemixOptions | undefined;
23-
24-
instrumentRemix({
25-
actionFormDataAttributes: client?.getDataCollectionOptions().httpBodies.includes('incomingRequest')
26-
? options?.captureActionFormDataKeys
27-
: undefined,
28-
});
29-
},
30-
31-
setup(client: Client) {
32-
client.on('spanStart', span => {
33-
addRemixSpanAttributes(span);
34-
});
35-
},
36-
};
37-
}) satisfies IntegrationFn;
38-
39-
const addRemixSpanAttributes = (span: Span): void => {
19+
export function addRemixSpanAttributes(span: Span): void {
4020
const attributes = spanToJSON(span).data;
4121

4222
// this is one of: loader, action, requestHandler
@@ -57,9 +37,4 @@ const addRemixSpanAttributes = (span: Span): void => {
5737
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.otel.remix',
5838
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,
5939
});
60-
};
61-
62-
/**
63-
* Instrumentation for aws-sdk package
64-
*/
65-
export const remixIntegration = defineIntegration(_remixIntegration);
40+
}

packages/remix/src/server/integrations/tracing-channel.ts

Lines changed: 15 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import * as diagnosticsChannel from 'node:diagnostics_channel';
2-
import type { IntegrationFn, Span, SpanAttributes } from '@sentry/core';
2+
import type { Span, SpanAttributes } from '@sentry/core';
33
import {
4-
defineIntegration,
54
getActiveSpan,
65
isObjectLike,
76
SEMANTIC_ATTRIBUTE_SENTRY_OP,
@@ -12,11 +11,8 @@ import {
1211
} from '@sentry/core';
1312
import { bindTracingChannelToSpan } from '@sentry/server-utils';
1413
import { CODE_FUNCTION, HTTP_METHOD, HTTP_ROUTE, HTTP_STATUS_CODE, HTTP_URL } from '@sentry/conventions/attributes';
15-
import { getClient } from '@sentry/node';
16-
import type { RemixOptions } from '../../utils/remixOptions';
1714
import { remixChannels } from '@sentry/server-utils/orchestrion';
1815

19-
const INTEGRATION_NAME = 'Remix' as const;
2016
const ORIGIN = 'auto.http.orchestrion.remix';
2117

2218
const NOOP = (): void => {};
@@ -237,43 +233,18 @@ function applyFormDataAttributes(
237233
});
238234
}
239235

240-
function instrumentRemix(actionFormDataAttributes: Record<string, string | boolean> | undefined): void {
241-
subscribeRequestHandler();
242-
subscribeMatchServerRoutes();
243-
subscribeCallRouteLoader();
244-
// Always instrument actions; `actionFormDataAttributes` only gates the optional form-data
245-
// attribute extraction, not whether ACTION spans are created.
246-
subscribeCallRouteAction(actionFormDataAttributes);
247-
}
248-
249-
const _remixChannelIntegration = (() => {
250-
return {
251-
name: INTEGRATION_NAME,
252-
setupOnce() {
253-
// `tracingChannel` is unavailable before Node 18.19, so do nothing in that case.
254-
if (!diagnosticsChannel.tracingChannel) {
255-
return;
256-
}
257-
258-
const client = getClient();
259-
const options = client?.getOptions() as RemixOptions | undefined;
260-
const actionFormDataAttributes = client?.getDataCollectionOptions().httpBodies.includes('incomingRequest')
261-
? options?.captureActionFormDataKeys
262-
: undefined;
263-
264-
waitForTracingChannelBinding(() => {
265-
instrumentRemix(actionFormDataAttributes);
266-
});
267-
},
268-
};
269-
}) satisfies IntegrationFn;
236+
export function instrumentRemix(actionFormDataAttributes: Record<string, string | boolean> | undefined): void {
237+
// `tracingChannel` is unavailable before Node 18.19, so do nothing in that case.
238+
if (!diagnosticsChannel.tracingChannel) {
239+
return;
240+
}
270241

271-
/**
272-
* Orchestrion-driven Remix integration.
273-
*
274-
* Ports the vendored `RemixInstrumentation` (an OTel `InstrumentationBase`) to diagnostics-channel
275-
* listeners, with orchestrion injecting the channels into `@remix-run/server-runtime`. Creates the
276-
* `remix.request` server span plus `LOADER`/`ACTION` spans, and enriches the request span with the
277-
* matched route. Requires the orchestrion runtime hook or bundler plugin to be active.
278-
*/
279-
export const remixChannelIntegration = defineIntegration(_remixChannelIntegration);
242+
waitForTracingChannelBinding(() => {
243+
subscribeRequestHandler();
244+
subscribeMatchServerRoutes();
245+
subscribeCallRouteLoader();
246+
// Always instrument actions; `actionFormDataAttributes` only gates the optional form-data
247+
// attribute extraction, not whether ACTION spans are created.
248+
subscribeCallRouteAction(actionFormDataAttributes);
249+
});
250+
}

packages/remix/src/server/sdk.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { DEBUG_BUILD } from '../utils/debug-build';
66
import type { RemixOptions } from '../utils/remixOptions';
77
import { instrumentServer } from './instrumentServer';
88
import { httpIntegration } from './integrations/http';
9-
import { remixIntegration } from './integrations/opentelemetry';
9+
import { remixIntegration } from './integrations';
1010

1111
/**
1212
* Returns the default Remix integrations.

packages/remix/test/server/tracing-channel-no-form-data.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
// Runs in its own file so the channel subscriptions register with NO form-data capture configured -
1414
// the default for most apps. `captureActionFormDataKeys` gates only the optional attribute
1515
// extraction, so ACTION spans must still be created.
16-
describe('remixChannelIntegration (no form-data capture configured)', () => {
16+
describe('remixIntegration with orchestrion (no form-data capture configured)', () => {
1717
let startInactiveSpanSpy: MockInstance;
1818
let getActiveSpanSpy: MockInstance;
1919
let span: Span;

packages/remix/test/server/tracing-channel-test-utils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
import * as SentryNode from '@sentry/node';
1010
import type { NodeClient } from '@sentry/node';
1111
import { vi } from 'vitest';
12-
import { remixChannelIntegration } from '../../src/server/integrations/tracing-channel';
12+
import { instrumentRemix } from '../../src/server/integrations/tracing-channel';
1313

1414
export const CHANNELS = {
1515
REQUEST_HANDLER: 'orchestrion:@remix-run/server-runtime:requestHandler',
@@ -113,5 +113,5 @@ export function setupRemixChannelIntegration(captureActionFormDataKeys?: Record<
113113
getDataCollectionOptions: () => ({ httpBodies: captureActionFormDataKeys ? ['incomingRequest'] : [] }),
114114
} as unknown as NodeClient);
115115

116-
remixChannelIntegration().setupOnce?.();
116+
instrumentRemix(captureActionFormDataKeys);
117117
}

packages/server-utils/src/orchestrion/config/remix.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { InstrumentationConfig } from '@apm-js-collab/code-transformer';
22

33
// Ports the vendored `RemixInstrumentation` (an OTel `InstrumentationBase` that patched
44
// `@remix-run/server-runtime`) to orchestrion channel injection. The subscriber lives in
5-
// `@sentry/remix` (`remixChannelIntegration`), because it needs remix-specific SDK options.
5+
// `@sentry/remix` (`instrumentRemix`), because it needs remix-specific SDK options.
66
//
77
// Four concepts, one channel each. Where a function was renamed across the supported range, both
88
// names publish to the same channel so the subscriber only ever knows one name per concept:

0 commit comments

Comments
 (0)