Skip to content

Commit 48f4762

Browse files
author
cod1k
committed
Refactor Durable Object method wrapping for Sentry integration
Introduce `instrumentPrototype` to enhance Sentry instrumentation by proxying prototypes and managing method wrapping at a granular level. Improves maintainability and modularity of the code for durable objects.
1 parent 13ceb0e commit 48f4762

File tree

1 file changed

+56
-1
lines changed

1 file changed

+56
-1
lines changed

packages/cloudflare/src/durableobject.ts

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ type MethodWrapperOptions = {
2525
};
2626

2727
// eslint-disable-next-line @typescript-eslint/no-explicit-any
28-
function wrapMethodWithSentry<T extends (...args: any[]) => any>(
28+
type OriginalMethod = (...args: any[]) => any;
29+
30+
function wrapMethodWithSentry<T extends OriginalMethod>(
2931
wrapperOptions: MethodWrapperOptions,
3032
handler: T,
3133
callback?: (...args: Parameters<T>) => void,
@@ -221,8 +223,61 @@ export function instrumentDurableObjectWithSentry<
221223
);
222224
}
223225
}
226+
const instrumentedPrototype = instrumentPrototype(target, options, context);
227+
Object.setPrototypeOf(obj, instrumentedPrototype);
224228

225229
return obj;
226230
},
227231
});
228232
}
233+
234+
function instrumentPrototype<T extends NewableFunction>(
235+
target: T,
236+
options: CloudflareOptions,
237+
context: MethodWrapperOptions['context'],
238+
): typeof target.prototype {
239+
const sentryMethods = new Map<string | symbol, OriginalMethod>();
240+
let proto = target.prototype;
241+
const instrumentedPrototype = new Proxy(proto, {
242+
get(target, prop, receiver) {
243+
if (sentryMethods.has(prop)) {
244+
return sentryMethods.get(prop);
245+
}
246+
return Reflect.get(target, prop, receiver);
247+
},
248+
});
249+
while (proto && proto !== Object.prototype) {
250+
for (const method of Object.getOwnPropertyNames(proto)) {
251+
if (method === 'constructor' || sentryMethods.has(method)) {
252+
continue;
253+
}
254+
255+
const value = Reflect.get(proto, method, proto);
256+
if (typeof value === 'function') {
257+
sentryMethods.set(
258+
method,
259+
wrapMethodWithSentry(
260+
{
261+
options,
262+
context,
263+
spanName: method,
264+
spanOp: 'rpc',
265+
},
266+
// <editor-fold desc="Disable __SENTRY_INSTRUMENTED__ for prototype methods">
267+
new Proxy(value, {
268+
set(target, p, newValue, receiver): boolean {
269+
if ('__SENTRY_INSTRUMENTED__' === p) {
270+
return true;
271+
}
272+
return Reflect.set(target, p, newValue, receiver);
273+
},
274+
}),
275+
// </editor-fold>
276+
),
277+
);
278+
}
279+
}
280+
proto = Object.getPrototypeOf(proto);
281+
}
282+
return instrumentedPrototype;
283+
}

0 commit comments

Comments
 (0)