@inference-net/otel-cf-workers 2.0.4 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"console-Cy5QdByD.js","sources":["../src/logs/console.ts"],"sourcesContent":["import { getLogger } from './provider.js'\nimport { SEVERITY_NUMBERS } from '../constants.js'\n\nconst severityMap = {\n\tdebug: SEVERITY_NUMBERS.DEBUG,\n\tlog: SEVERITY_NUMBERS.INFO,\n\tinfo: SEVERITY_NUMBERS.INFO,\n\twarn: SEVERITY_NUMBERS.WARN,\n\terror: SEVERITY_NUMBERS.ERROR,\n} as const\n\ntype ConsoleMethod = keyof typeof severityMap\n\n/**\n * Instrument console methods to emit OpenTelemetry log records\n * This is OPT-IN and must be explicitly enabled in configuration\n */\nexport function instrumentConsole() {\n\tconst logger = getLogger('console')\n\n\tfor (const [method, severityNumber] of Object.entries(severityMap)) {\n\t\tconst consoleMethod = method as ConsoleMethod\n\t\tconst original = console[consoleMethod]\n\n\t\tif (typeof original !== 'function') {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Replace console method with instrumented version\n\t\t;(console as any)[consoleMethod] = function (...args: any[]) {\n\t\t\ttry {\n\t\t\t\t// Emit log record\n\t\t\t\tlogger.emit({\n\t\t\t\t\tseverityNumber,\n\t\t\t\t\tseverityText: method.toUpperCase(),\n\t\t\t\t\tbody: args.length === 1 ? String(args[0]) : args.map(String).join(' '),\n\t\t\t\t\tattributes: {\n\t\t\t\t\t\t'log.source': 'console',\n\t\t\t\t\t\t'log.method': method,\n\t\t\t\t\t\t'log.args_count': args.length,\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t} catch (error) {\n\t\t\t\t// Don't break console if logging fails - but can't use console.error here!\n\t\t\t}\n\n\t\t\t// Always call original console method\n\t\t\treturn original.apply(console, args)\n\t\t}\n\t}\n}\n"],"names":[],"mappings":";;AAGA,MAAM,WAAA,GAAc;AAAA,EACnB,OAAO,gBAAA,CAAiB,KAAA;AAAA,EACxB,KAAK,gBAAA,CAAiB,IAAA;AAAA,EACtB,MAAM,gBAAA,CAAiB,IAAA;AAAA,EACvB,MAAM,gBAAA,CAAiB,IAAA;AAAA,EACvB,OAAO,gBAAA,CAAiB;AACzB,CAAA;AAQO,SAAS,iBAAA,GAAoB;AACnC,EAAA,MAAM,MAAA,GAAS,UAAU,SAAS,CAAA;AAElC,EAAA,KAAA,MAAW,CAAC,MAAA,EAAQ,cAAc,KAAK,MAAA,CAAO,OAAA,CAAQ,WAAW,CAAA,EAAG;AACnE,IAAA,MAAM,aAAA,GAAgB,MAAA;AACtB,IAAA,MAAM,QAAA,GAAW,QAAQ,aAAa,CAAA;AAEtC,IAAA,IAAI,OAAO,aAAa,UAAA,EAAY;AACnC,MAAA;AAAA,IACD;AAGC,IAAC,OAAA,CAAgB,aAAa,CAAA,GAAI,SAAA,GAAa,IAAA,EAAa;AAC5D,MAAA,IAAI;AAEH,QAAA,MAAA,CAAO,IAAA,CAAK;AAAA,UACX,cAAA;AAAA,UACA,YAAA,EAAc,OAAO,WAAA,EAAY;AAAA,UACjC,IAAA,EAAM,IAAA,CAAK,MAAA,KAAW,CAAA,GAAI,OAAO,IAAA,CAAK,CAAC,CAAC,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,MAAM,CAAA,CAAE,KAAK,GAAG,CAAA;AAAA,UACrE,UAAA,EAAY;AAAA,YACX,YAAA,EAAc,SAAA;AAAA,YACd,YAAA,EAAc,MAAA;AAAA,YACd,kBAAkB,IAAA,CAAK;AAAA;AACxB,SACA,CAAA;AAAA,MACF,SAAS,KAAA,EAAO;AAAA,MAEhB;AAGA,MAAA,OAAO,QAAA,CAAS,KAAA,CAAM,OAAA,EAAS,IAAI,CAAA;AAAA,IACpC,CAAA;AAAA,EACD;AACD;;;;"}
1
+ {"version":3,"file":"console-Cy5QdByD.js","sources":["../src/logs/console.ts"],"sourcesContent":["import { getLogger } from './provider'\nimport { SEVERITY_NUMBERS } from '../constants'\n\nconst severityMap = {\n\tdebug: SEVERITY_NUMBERS.DEBUG,\n\tlog: SEVERITY_NUMBERS.INFO,\n\tinfo: SEVERITY_NUMBERS.INFO,\n\twarn: SEVERITY_NUMBERS.WARN,\n\terror: SEVERITY_NUMBERS.ERROR,\n} as const\n\ntype ConsoleMethod = keyof typeof severityMap\n\n/**\n * Instrument console methods to emit OpenTelemetry log records\n * This is OPT-IN and must be explicitly enabled in configuration\n */\nexport function instrumentConsole() {\n\tconst logger = getLogger('console')\n\n\tfor (const [method, severityNumber] of Object.entries(severityMap)) {\n\t\tconst consoleMethod = method as ConsoleMethod\n\t\tconst original = console[consoleMethod]\n\n\t\tif (typeof original !== 'function') {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Replace console method with instrumented version\n\t\t;(console as any)[consoleMethod] = function (...args: any[]) {\n\t\t\ttry {\n\t\t\t\t// Emit log record\n\t\t\t\tlogger.emit({\n\t\t\t\t\tseverityNumber,\n\t\t\t\t\tseverityText: method.toUpperCase(),\n\t\t\t\t\tbody: args.length === 1 ? String(args[0]) : args.map(String).join(' '),\n\t\t\t\t\tattributes: {\n\t\t\t\t\t\t'log.source': 'console',\n\t\t\t\t\t\t'log.method': method,\n\t\t\t\t\t\t'log.args_count': args.length,\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t} catch (error) {\n\t\t\t\t// Don't break console if logging fails - but can't use console.error here!\n\t\t\t}\n\n\t\t\t// Always call original console method\n\t\t\treturn original.apply(console, args)\n\t\t}\n\t}\n}\n"],"names":[],"mappings":";;AAGA,MAAM,WAAA,GAAc;AAAA,EACnB,OAAO,gBAAA,CAAiB,KAAA;AAAA,EACxB,KAAK,gBAAA,CAAiB,IAAA;AAAA,EACtB,MAAM,gBAAA,CAAiB,IAAA;AAAA,EACvB,MAAM,gBAAA,CAAiB,IAAA;AAAA,EACvB,OAAO,gBAAA,CAAiB;AACzB,CAAA;AAQO,SAAS,iBAAA,GAAoB;AACnC,EAAA,MAAM,MAAA,GAAS,UAAU,SAAS,CAAA;AAElC,EAAA,KAAA,MAAW,CAAC,MAAA,EAAQ,cAAc,KAAK,MAAA,CAAO,OAAA,CAAQ,WAAW,CAAA,EAAG;AACnE,IAAA,MAAM,aAAA,GAAgB,MAAA;AACtB,IAAA,MAAM,QAAA,GAAW,QAAQ,aAAa,CAAA;AAEtC,IAAA,IAAI,OAAO,aAAa,UAAA,EAAY;AACnC,MAAA;AAAA,IACD;AAGC,IAAC,OAAA,CAAgB,aAAa,CAAA,GAAI,SAAA,GAAa,IAAA,EAAa;AAC5D,MAAA,IAAI;AAEH,QAAA,MAAA,CAAO,IAAA,CAAK;AAAA,UACX,cAAA;AAAA,UACA,YAAA,EAAc,OAAO,WAAA,EAAY;AAAA,UACjC,IAAA,EAAM,IAAA,CAAK,MAAA,KAAW,CAAA,GAAI,OAAO,IAAA,CAAK,CAAC,CAAC,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,MAAM,CAAA,CAAE,KAAK,GAAG,CAAA;AAAA,UACrE,UAAA,EAAY;AAAA,YACX,YAAA,EAAc,SAAA;AAAA,YACd,YAAA,EAAc,MAAA;AAAA,YACd,kBAAkB,IAAA,CAAK;AAAA;AACxB,SACA,CAAA;AAAA,MACF,SAAS,KAAA,EAAO;AAAA,MAEhB;AAGA,MAAA,OAAO,QAAA,CAAS,KAAA,CAAM,OAAA,EAAS,IAAI,CAAA;AAAA,IACpC,CAAA;AAAA,EACD;AACD;;;;"}
package/dist/index.d.ts CHANGED
@@ -105,7 +105,7 @@ export declare interface DOConstructorTrigger {
105
105
  name?: string;
106
106
  }
107
107
 
108
- declare type Env_2 = Record<string, any>;
108
+ declare type Env = Record<string, any>;
109
109
 
110
110
  export declare type ExporterConfig = OTLPExporterConfig | SpanExporter;
111
111
 
@@ -168,7 +168,7 @@ export declare interface InitialSpanInfo {
168
168
  context?: Context;
169
169
  }
170
170
 
171
- export declare function instrument<E extends Env_2, Q, C>(handler: ExportedHandler<E, Q, C>, config: ConfigurationOption): ExportedHandler<E, Q, C>;
171
+ export declare function instrument<E extends Env, Q, C>(handler: ExportedHandler<E, Q, C>, config: ConfigurationOption): ExportedHandler<E, Q, C>;
172
172
 
173
173
  export declare interface InstrumentationOptions {
174
174
  instrumentGlobalFetch?: boolean;
package/dist/index.js CHANGED
@@ -96,7 +96,7 @@ function passthroughGet(target, prop, thisArg) {
96
96
  }
97
97
  }
98
98
 
99
- const PACKAGE_VERSION = "2.0.4";
99
+ const PACKAGE_VERSION = "2.1.0";
100
100
  const PACKAGE_NAME = "@inference-net/otel-cf-workers";
101
101
  const ATTR_CLOUDFLARE_COLO = "cloudflare.colo";
102
102
  const ATTR_CLOUDFLARE_RAY_ID = "cloudflare.ray_id";
@@ -1284,14 +1284,6 @@ function getLogger(name, version, options) {
1284
1284
  return getGlobalLoggerProvider().getLogger(name, version, options);
1285
1285
  }
1286
1286
 
1287
- const provider = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty({
1288
- __proto__: null,
1289
- WorkerLoggerProvider,
1290
- getGlobalLoggerProvider,
1291
- getLogger,
1292
- setGlobalLoggerProvider
1293
- }, Symbol.toStringTag, { value: 'Module' }));
1294
-
1295
1287
  function isValidAttributeValue(value) {
1296
1288
  return typeof value === "string" || typeof value === "number" || typeof value === "boolean";
1297
1289
  }
@@ -1449,12 +1441,22 @@ function getParentContextFromRequest(request) {
1449
1441
  const acceptTraceContext = typeof workerConfig.handlers.fetch.acceptTraceContext === "function" ? workerConfig.handlers.fetch.acceptTraceContext(request) : workerConfig.handlers.fetch.acceptTraceContext ?? true;
1450
1442
  return acceptTraceContext ? getParentContextFromHeaders(request.headers) : context.active();
1451
1443
  }
1452
- function updateSpanNameOnRoute(span, request) {
1444
+ function updateSpanNameOnRoute(span, request, result) {
1453
1445
  const readable = span;
1454
1446
  if (readable.attributes["http.route"]) {
1455
1447
  const method = request.method.toUpperCase();
1456
1448
  span.updateName(`${method} ${readable.attributes["http.route"]}`);
1457
1449
  }
1450
+ if (result) {
1451
+ if (result.status >= 400) {
1452
+ span.setStatus({
1453
+ code: SpanStatusCode.ERROR,
1454
+ message: `HTTP ${result.status}: ${result.statusText}`
1455
+ });
1456
+ } else {
1457
+ span.setStatus({ code: SpanStatusCode.OK });
1458
+ }
1459
+ }
1458
1460
  }
1459
1461
  const fetchInstrumentation = {
1460
1462
  getInitialSpanInfo: (request) => {
@@ -1468,8 +1470,10 @@ const fetchInstrumentation = {
1468
1470
  Object.assign(attributes, gatherRootSpanAttributes(request, "fetch"));
1469
1471
  Object.assign(attributes, gatherUserAgentAttributes(request));
1470
1472
  const method = request.method.toUpperCase();
1473
+ const url = new URL(request.url);
1474
+ const route = url.pathname;
1471
1475
  return {
1472
- name: `fetchHandler ${method}`,
1476
+ name: `${method} ${route}`,
1473
1477
  options: {
1474
1478
  attributes,
1475
1479
  kind: SpanKind.SERVER
@@ -1478,7 +1482,10 @@ const fetchInstrumentation = {
1478
1482
  };
1479
1483
  },
1480
1484
  getAttributesFromResult: (response) => {
1481
- return gatherResponseAttributes(response);
1485
+ const attrs = gatherResponseAttributes(response);
1486
+ attrs["http.status_code"] = response.status;
1487
+ attrs["http.status_text"] = response.statusText;
1488
+ return attrs;
1482
1489
  },
1483
1490
  executionSucces: updateSpanNameOnRoute,
1484
1491
  executionFailed: updateSpanNameOnRoute
@@ -1512,6 +1519,18 @@ function instrumentClientFetch(fetchFn, configFn, attrs) {
1512
1519
  if (request.cf) span.setAttributes(gatherOutgoingCfAttributes(request.cf));
1513
1520
  const response = await Reflect.apply(target, thisArg, [request]);
1514
1521
  span.setAttributes(gatherResponseAttributes(response));
1522
+ span.setAttributes({
1523
+ "http.status_code": response.status,
1524
+ "http.status_text": response.statusText
1525
+ });
1526
+ if (response.status >= 400) {
1527
+ span.setStatus({
1528
+ code: SpanStatusCode.ERROR,
1529
+ message: `HTTP ${response.status}: ${response.statusText}`
1530
+ });
1531
+ } else {
1532
+ span.setStatus({ code: SpanStatusCode.OK });
1533
+ }
1515
1534
  return response;
1516
1535
  } catch (error) {
1517
1536
  span.recordException(error);
@@ -2870,7 +2889,7 @@ function instrumentSQLStorageExec(fn, operation) {
2870
2889
  const fnHandler = {
2871
2890
  apply: (target, thisArg, argArray) => {
2872
2891
  const query = argArray[0];
2873
- const bindings = argArray[1];
2892
+ const bindings = argArray.slice(1);
2874
2893
  const attributes = {
2875
2894
  [ATTR_DB_SYSTEM_NAME]: dbSystem,
2876
2895
  [ATTR_DB_OPERATION_NAME]: operation,
@@ -2883,58 +2902,74 @@ function instrumentSQLStorageExec(fn, operation) {
2883
2902
  kind: SpanKind.CLIENT,
2884
2903
  attributes
2885
2904
  };
2886
- return tracer.startActiveSpan(`Durable Object SQL ${operation}`, options, async (span) => {
2887
- const result = await Reflect.apply(target, thisArg, argArray);
2888
- if (result && typeof result === "object") {
2889
- if ("rowsRead" in result) {
2890
- span.setAttribute(ATTR_CLOUDFLARE_DO_SQL_RESPONSE_ROWS_READ, result.rowsRead);
2905
+ return tracer.startActiveSpan(`Durable Object SQL ${operation}`, options, (span) => {
2906
+ const cursor = Reflect.apply(target, thisArg, argArray);
2907
+ let spanEnded = false;
2908
+ const endSpanWithMetrics = () => {
2909
+ if (spanEnded) return;
2910
+ spanEnded = true;
2911
+ if (typeof cursor.rowsRead === "number") {
2912
+ span.setAttribute(ATTR_CLOUDFLARE_DO_SQL_RESPONSE_ROWS_READ, cursor.rowsRead);
2891
2913
  }
2892
- if ("rowsWritten" in result) {
2893
- span.setAttribute(ATTR_CLOUDFLARE_DO_SQL_RESPONSE_ROWS_WRITTEN, result.rowsWritten);
2914
+ if (typeof cursor.rowsWritten === "number") {
2915
+ span.setAttribute(ATTR_CLOUDFLARE_DO_SQL_RESPONSE_ROWS_WRITTEN, cursor.rowsWritten);
2894
2916
  }
2895
- }
2896
- span.end();
2897
- return result;
2898
- });
2899
- }
2900
- };
2901
- return wrap(fn, fnHandler);
2902
- }
2903
- function instrumentSQLStorageExecBatch(fn, operation) {
2904
- const tracer = trace.getTracer("do_sql_storage");
2905
- const fnHandler = {
2906
- apply: (target, thisArg, argArray) => {
2907
- const statements = argArray[0];
2908
- const attributes = {
2909
- [ATTR_DB_SYSTEM_NAME]: dbSystem,
2910
- [ATTR_DB_OPERATION_NAME]: operation,
2911
- [ATTR_DB_OPERATION_BATCH_SIZE]: statements.length
2912
- };
2913
- if (statements.length > 0 && statements[0]) {
2914
- attributes[ATTR_DB_QUERY_TEXT] = statements[0].query;
2915
- }
2916
- const options = {
2917
- kind: SpanKind.CLIENT,
2918
- attributes
2919
- };
2920
- return tracer.startActiveSpan(`Durable Object SQL ${operation}`, options, async (span) => {
2921
- const results = await Reflect.apply(target, thisArg, argArray);
2922
- let totalRowsRead = 0;
2923
- let totalRowsWritten = 0;
2924
- for (const result of results) {
2925
- if (result && typeof result === "object") {
2926
- if ("rowsRead" in result) {
2927
- totalRowsRead += result.rowsRead;
2917
+ span.end();
2918
+ };
2919
+ Promise.resolve().then(() => {
2920
+ if (!spanEnded) {
2921
+ endSpanWithMetrics();
2922
+ }
2923
+ });
2924
+ const wrappedCursor = new Proxy(cursor, {
2925
+ get(target2, prop, receiver) {
2926
+ const value = Reflect.get(target2, prop, receiver);
2927
+ if (prop === "toArray") {
2928
+ return function(...args) {
2929
+ const result = typeof value === "function" ? value.apply(target2, args) : value;
2930
+ endSpanWithMetrics();
2931
+ return result;
2932
+ };
2933
+ }
2934
+ if (prop === "one") {
2935
+ return function(...args) {
2936
+ const result = typeof value === "function" ? value.apply(target2, args) : value;
2937
+ endSpanWithMetrics();
2938
+ return result;
2939
+ };
2928
2940
  }
2929
- if ("rowsWritten" in result) {
2930
- totalRowsWritten += result.rowsWritten;
2941
+ if (prop === Symbol.iterator) {
2942
+ return function() {
2943
+ const iterator = typeof value === "function" ? value.apply(target2) : value;
2944
+ let iterationComplete = false;
2945
+ return {
2946
+ next() {
2947
+ const result = iterator.next();
2948
+ if (result.done && !iterationComplete) {
2949
+ iterationComplete = true;
2950
+ endSpanWithMetrics();
2951
+ }
2952
+ return result;
2953
+ },
2954
+ [Symbol.iterator]() {
2955
+ return this;
2956
+ }
2957
+ };
2958
+ };
2931
2959
  }
2960
+ if (prop === "next") {
2961
+ return function(...args) {
2962
+ const result = typeof value === "function" ? value.apply(target2, args) : value;
2963
+ if (result && result.done) {
2964
+ endSpanWithMetrics();
2965
+ }
2966
+ return result;
2967
+ };
2968
+ }
2969
+ return typeof value === "function" ? value.bind(target2) : value;
2932
2970
  }
2933
- }
2934
- span.setAttribute(ATTR_CLOUDFLARE_DO_SQL_RESPONSE_ROWS_READ, totalRowsRead);
2935
- span.setAttribute(ATTR_CLOUDFLARE_DO_SQL_RESPONSE_ROWS_WRITTEN, totalRowsWritten);
2936
- span.end();
2937
- return results;
2971
+ });
2972
+ return wrappedCursor;
2938
2973
  });
2939
2974
  }
2940
2975
  };
@@ -2950,8 +2985,6 @@ function instrumentSQLStorage(sql) {
2950
2985
  switch (prop) {
2951
2986
  case "exec":
2952
2987
  return instrumentSQLStorageExec(fn, "exec");
2953
- case "execBatch":
2954
- return instrumentSQLStorageExecBatch(fn, "execBatch");
2955
2988
  default:
2956
2989
  return fn;
2957
2990
  }
@@ -3016,7 +3049,8 @@ function instrumentRpcMethod(method, methodName, nsName, stubId) {
3016
3049
  kind: SpanKind.CLIENT,
3017
3050
  attributes
3018
3051
  };
3019
- const spanName = `RPC ${nsName}.${methodName}`;
3052
+ const serviceName = stubId.name || nsName;
3053
+ const spanName = `RPC ${serviceName}.${methodName}`;
3020
3054
  return tracer.startActiveSpan(spanName, options, async (span) => {
3021
3055
  try {
3022
3056
  const contextCarrier = injectRpcContext(context.active(), stubId.name);
@@ -3203,15 +3237,6 @@ function instrumentRpcHandlerMethod(fn, methodName, initialiser, env, id) {
3203
3237
  const [extractedContext, cleanedArgs] = extractAndRemoveRpcContext(argArray);
3204
3238
  const carrierDoName = argArray.length > 0 && extractedContext ? argArray[0].doName : void 0;
3205
3239
  const doName = carrierDoName || id.name || void 0;
3206
- console.log("[DO RPC Server]", {
3207
- methodName,
3208
- hasExtractedContext: !!extractedContext,
3209
- carrierDoName,
3210
- idName: id.name,
3211
- finalDoName: doName,
3212
- argArrayLength: argArray.length,
3213
- cleanedArgsLength: cleanedArgs.length
3214
- });
3215
3240
  let context$1 = extractedContext || context.active();
3216
3241
  context$1 = setConfig(config, context$1);
3217
3242
  const tracer = trace.getTracer("do_rpc_handler");
@@ -3231,7 +3256,7 @@ function instrumentRpcHandlerMethod(fn, methodName, initialiser, env, id) {
3231
3256
  attributes
3232
3257
  };
3233
3258
  const spanName = doName ? `${doName}.${methodName}` : `${attributes["do.id"]}.${methodName}`;
3234
- return tracer.startActiveSpan(spanName, options, async (span) => {
3259
+ return tracer.startActiveSpan(spanName, options, context.active(), async (span) => {
3235
3260
  try {
3236
3261
  const bound = target.bind(thisArg);
3237
3262
  const result = await bound.apply(thisArg, cleanedArgs);
@@ -3486,7 +3511,6 @@ function createInitialiser(config) {
3486
3511
  }
3487
3512
  async function exportTelemetry(traceId, tracker) {
3488
3513
  const tracer = trace.getTracer("export");
3489
- const { getLogger } = await Promise.resolve().then(() => provider);
3490
3514
  const logger = getLogger("export");
3491
3515
  if (tracer instanceof WorkerTracer) {
3492
3516
  await scheduler.wait(1);