Skip to content

Commit a658fcd

Browse files
committed
Update PR #2275
1 parent c45c117 commit a658fcd

6 files changed

Lines changed: 106 additions & 50 deletions

File tree

js/src/auto-instrumentations/bundler/plugin.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,13 @@ export interface BundlerPluginOptions {
2525
browser?: boolean;
2626

2727
/**
28-
* Previously replaced Node's `diagnostics_channel` implementation with a
29-
* browser-compatible shim in transformed code.
28+
* Marks transformed source as targeting a browser or edge-like environment.
3029
*
31-
* Global instrumentation hooks do not use `diagnostics_channel`, so this
32-
* option no longer does anything. It is retained for backwards
33-
* compatibility.
30+
* This retains the previous browser-target behavior of the option. Global
31+
* instrumentation hooks are runtime-independent, so no diagnostics-channel
32+
* compatibility shim is injected.
3433
*
35-
* @deprecated This option no longer does anything. Use `browser` to mark
36-
* browser or edge-like bundles.
34+
* @deprecated Use `browser` instead.
3735
*/
3836
useDiagnosticChannelCompatShim?: boolean;
3937
}
@@ -56,7 +54,8 @@ function getModuleVersion(basedir: string): string | undefined {
5654
}
5755

5856
export const unplugin = createUnplugin<BundlerPluginOptions>((options = {}) => {
59-
const browser = options.browser ?? false;
57+
const browser =
58+
options.browser ?? options.useDiagnosticChannelCompatShim ?? false;
6059
const allInstrumentations = getDefaultInstrumentationConfigs({
6160
additionalInstrumentations: options.instrumentations,
6261
});

js/src/auto-instrumentations/bundler/webpack-loader.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ function codeTransformerLoader(
128128
modulePath: normalizedModulePath,
129129
source: code,
130130
format: isModule ? "esm" : "cjs",
131-
browser: options.browser ?? false,
131+
browser: options.browser ?? options.useDiagnosticChannelCompatShim ?? false,
132132
});
133133
if (patched !== null) {
134134
return callback(null, patched);

js/src/auto-instrumentations/orchestrion-js/transformer.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,6 @@ export class Transformer {
8888
const query = astQuery || this.fromFunctionQuery(resolvedFunctionQuery);
8989
const state: TransformState = {
9090
...config,
91-
moduleType,
9291
moduleVersion: this.version,
9392
functionQuery: resolvedFunctionQuery,
9493
operator: this.getOperator(resolvedFunctionQuery.kind),

js/src/auto-instrumentations/orchestrion-js/transforms.ts

Lines changed: 45 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
GLOBAL_INSTRUMENTATION_HOOKS_PROTOCOL_VERSION,
1212
GLOBAL_INSTRUMENTATION_HOOKS_REGISTRY_BRAND,
1313
} from "../../global-instrumentation-hooks";
14-
import type { FunctionQuery, InstrumentationConfig, ModuleType } from "./types";
14+
import type { FunctionQuery, InstrumentationConfig } from "./types";
1515

1616
type AnyNode = any;
1717
type TransformFn = (
@@ -23,14 +23,14 @@ type TransformFn = (
2323
type TraceOperator = "traceCallback" | "tracePromise" | "traceSync";
2424

2525
export interface TransformState extends InstrumentationConfig {
26-
moduleType: ModuleType;
2726
moduleVersion: string;
2827
functionQuery: FunctionQuery;
2928
operator: TraceOperator;
3029
functionIndex?: number;
3130
}
3231

3332
const CHANNEL_REGEX = /[^\w]/g;
33+
const SHARED_HOOK_LOOKUP = "tr_ch_apm$get_hook";
3434

3535
function formatChannelVariable(channelName: string): string {
3636
return `tr_ch_apm$${channelName.replace(CHANNEL_REGEX, "_")}`;
@@ -49,6 +49,10 @@ export const transforms: Record<string, TransformFn> = {
4949
} = state;
5050
const channelVariable = formatChannelVariable(channelName);
5151
const channelGetter = formatChannelGetter(channelName);
52+
const hasSharedHookLookup = node.body.some(
53+
(child: AnyNode) =>
54+
child.declarations?.[0]?.id?.name === SHARED_HOOK_LOOKUP,
55+
);
5256

5357
if (
5458
node.body.some(
@@ -58,12 +62,10 @@ export const transforms: Record<string, TransformFn> = {
5862
return;
5963
}
6064

61-
const index = node.body.findIndex(
62-
(child: AnyNode) => child.directive === "use strict",
63-
);
64-
const code = `
65-
let ${channelVariable};
66-
const ${channelGetter} = () => {
65+
const sharedHookLookup = hasSharedHookLookup
66+
? ""
67+
: `
68+
const ${SHARED_HOOK_LOOKUP} = (__apm$hookName, __apm$operator) => {
6769
try {
6870
const __apm$hooks = globalThis[${JSON.stringify(
6971
GLOBAL_INSTRUMENTATION_HOOKS_KEY,
@@ -76,7 +78,7 @@ export const transforms: Record<string, TransformFn> = {
7678
) return undefined;
7779
const __apm$hook = Map.prototype.get.call(
7880
__apm$hooks,
79-
"orchestrion:${name}:${channelName}"
81+
__apm$hookName
8082
);
8183
if (
8284
(__apm$hook === null ||
@@ -86,15 +88,34 @@ export const transforms: Record<string, TransformFn> = {
8688
GLOBAL_INSTRUMENTATION_HOOK_BRAND,
8789
)})] !== ${GLOBAL_INSTRUMENTATION_HOOKS_PROTOCOL_VERSION} ||
8890
typeof __apm$hook.hasSubscribers !== "boolean" ||
89-
typeof __apm$hook[${JSON.stringify(operator)}] !== "function"
91+
typeof __apm$hook[__apm$operator] !== "function"
9092
) return undefined;
91-
return ${channelVariable} ??= __apm$hook;
93+
return __apm$hook;
9294
} catch {
9395
return undefined;
9496
}
9597
};
9698
`;
99+
const code = `
100+
${sharedHookLookup}
101+
let ${channelVariable};
102+
const ${channelGetter} = () =>
103+
${channelVariable} ??= ${SHARED_HOOK_LOOKUP}(
104+
${JSON.stringify(`orchestrion:${name}:${channelName}`)},
105+
${JSON.stringify(operator)}
106+
);
107+
`;
97108

109+
const sharedHookLookupIndex = node.body.findIndex(
110+
(child: AnyNode) =>
111+
child.declarations?.[0]?.id?.name === SHARED_HOOK_LOOKUP,
112+
);
113+
const index =
114+
sharedHookLookupIndex === -1
115+
? node.body.findIndex(
116+
(child: AnyNode) => child.directive === "use strict",
117+
)
118+
: sharedHookLookupIndex;
98119
node.body.splice(index + 1, 0, ...parse(code).body);
99120
},
100121

@@ -139,18 +160,14 @@ function traceFunction(
139160
(!methodName && !privateMethodName && !functionName);
140161
const type = isConstructor ? "ArrowFunctionExpression" : "FunctionExpression";
141162

142-
node.body = wrap(
143-
state,
144-
{
145-
type,
146-
params: node.params,
147-
body: node.body,
148-
async: node.async,
149-
expression: false,
150-
generator: node.generator,
151-
},
152-
program,
153-
);
163+
node.body = wrap(state, {
164+
type,
165+
params: node.params,
166+
body: node.body,
167+
async: node.async,
168+
expression: false,
169+
generator: node.generator,
170+
});
154171

155172
node.generator = false;
156173
node.async = false;
@@ -202,22 +219,17 @@ function traceInstanceMethod(
202219
const fn = ctorBody[1].expression.right;
203220

204221
fn.async = operator === "tracePromise";
205-
fn.body = wrap(
206-
state,
207-
{ type: "Identifier", name: `__apm$${methodName}` },
208-
program,
209-
);
222+
fn.body = wrap(state, {
223+
type: "Identifier",
224+
name: `__apm$${methodName}`,
225+
});
210226

211227
wrapSuper(fn);
212228

213229
ctor.value.body.body.push(...ctorBody);
214230
}
215231

216-
function wrap(
217-
state: TransformState,
218-
node: AnyNode,
219-
program?: AnyNode,
220-
): AnyNode {
232+
function wrap(state: TransformState, node: AnyNode): AnyNode {
221233
const { operator, moduleVersion } = state;
222234

223235
const wrapper =

js/src/global-instrumentation-hooks.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -137,20 +137,16 @@ function setContextValue(
137137
}
138138
}
139139

140-
function defaultTransform<M>(message: M): M {
141-
return message;
142-
}
143-
144140
function wrapStoreRun<M>(
145141
store: GlobalHookAsyncLocalStorage<unknown>,
146142
message: M,
147143
next: () => unknown,
148-
transform: GlobalHookTransformFunction<M, unknown> = defaultTransform,
144+
transform?: GlobalHookTransformFunction<M, unknown>,
149145
): () => unknown {
150146
return () => {
151147
let context: unknown;
152148
try {
153-
context = transform(message);
149+
context = transform ? transform(message) : message;
154150
} catch (error) {
155151
reportError(error);
156152
return next();

js/tests/auto-instrumentations/transformation.test.ts

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,48 @@ describe("Orchestrion Transformation Tests", () => {
369369
);
370370
});
371371

372+
it("injects one shared global hook lookup for multiple channels", () => {
373+
const matcher = create([
374+
{
375+
...testConfig({ functionName: "first", kind: "Sync" }),
376+
channelName: "first",
377+
},
378+
{
379+
...testConfig({ functionName: "second", kind: "Async" }),
380+
channelName: "second",
381+
},
382+
]);
383+
const transformer = matcher.getTransformer(
384+
"test-sdk",
385+
"1.0.0",
386+
"index.mjs",
387+
);
388+
389+
expect(transformer).toBeDefined();
390+
const result = transformer!.transform(
391+
`
392+
export function first() {
393+
return "first";
394+
}
395+
export async function second() {
396+
return "second";
397+
}
398+
`,
399+
"esm",
400+
);
401+
402+
expect(result.code.match(/const tr_ch_apm\$get_hook =/g)).toHaveLength(1);
403+
expect(
404+
result.code.match(
405+
/braintrust\.global-instrumentation-hooks\.registry/g,
406+
),
407+
).toHaveLength(1);
408+
expect(result.code).toContain("orchestrion:test-sdk:first");
409+
expect(result.code).toContain("orchestrion:test-sdk:second");
410+
expect(result.code).toContain("__apm$hook.traceSync");
411+
expect(result.code).toContain("__apm$hook.tracePromise");
412+
});
413+
372414
it("generates source maps", () => {
373415
const result = transformTestCode(
374416
{ functionName: "query", kind: "Sync" },
@@ -449,6 +491,7 @@ describe("Orchestrion Transformation Tests", () => {
449491

450492
it.each([
451493
["browser", "browser", { browser: true }],
494+
["legacy-browser", "browser", { useDiagnosticChannelCompatShim: true }],
452495
["edge", "neutral", { browser: true }],
453496
] as const)(
454497
"should keep Mastra %s bundles free of Node-only patches",
@@ -715,8 +758,15 @@ describe("Orchestrion Transformation Tests", () => {
715758
});
716759

717760
it.each([
718-
["apply", "node", "node", { useDiagnosticChannelCompatShim: true }, true],
761+
[
762+
"skip",
763+
"legacy browser",
764+
"web",
765+
{ useDiagnosticChannelCompatShim: true },
766+
false,
767+
],
719768
["skip", "browser", "web", { browser: true }, false],
769+
["apply", "node", "node", { browser: false }, true],
720770
] as const)(
721771
"should %s special-case patches for %s turbopack loader targets",
722772
async (_action, runtime, target, options, shouldPatch) => {

0 commit comments

Comments
 (0)