@xylabs/telemetry 4.9.18 → 4.10.1

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.
@@ -3,8 +3,10 @@ import {
3
3
  context,
4
4
  propagation,
5
5
  ROOT_CONTEXT,
6
- trace
6
+ SpanStatusCode,
7
+ trace as TRACE_API
7
8
  } from "@opentelemetry/api";
9
+ import { isDefined } from "@xylabs/typeof";
8
10
  function cloneContextWithoutSpan(activeCtx, configKeys = []) {
9
11
  let newCtx = ROOT_CONTEXT;
10
12
  const baggage = propagation.getBaggage(activeCtx);
@@ -20,11 +22,19 @@ function cloneContextWithoutSpan(activeCtx, configKeys = []) {
20
22
  return newCtx;
21
23
  }
22
24
  function span(name, fn, tracer) {
23
- if (tracer) {
24
- const span2 = tracer.startSpan(name);
25
- return context.with(trace.setSpan(context.active(), span2), () => {
25
+ const activeTracer = tracer ?? TRACE_API.getTracer(name);
26
+ if (isDefined(activeTracer)) {
27
+ const span2 = activeTracer.startSpan(name);
28
+ return context.with(TRACE_API.setSpan(context.active(), span2), () => {
26
29
  try {
27
- return fn();
30
+ const result = fn();
31
+ span2.setStatus({ code: SpanStatusCode.OK });
32
+ return result;
33
+ } catch (ex) {
34
+ const error = ex;
35
+ span2.recordException(error);
36
+ span2.setStatus({ code: SpanStatusCode.ERROR, message: error.message });
37
+ throw ex;
28
38
  } finally {
29
39
  span2.end();
30
40
  }
@@ -34,13 +44,21 @@ function span(name, fn, tracer) {
34
44
  }
35
45
  }
36
46
  function spanRoot(name, fn, tracer) {
37
- if (tracer) {
47
+ const activeTracer = tracer ?? TRACE_API.getTracer(name);
48
+ if (isDefined(activeTracer)) {
38
49
  const activeContext = context.active();
39
50
  const noSpanContext = cloneContextWithoutSpan(activeContext);
40
- const span2 = tracer.startSpan(name, {}, noSpanContext);
41
- return context.with(trace.setSpan(noSpanContext, span2), () => {
51
+ const span2 = activeTracer.startSpan(name, {}, noSpanContext);
52
+ return context.with(TRACE_API.setSpan(noSpanContext, span2), () => {
42
53
  try {
43
- return fn();
54
+ const result = fn();
55
+ span2.setStatus({ code: SpanStatusCode.OK });
56
+ return result;
57
+ } catch (ex) {
58
+ const error = ex;
59
+ span2.recordException(error);
60
+ span2.setStatus({ code: SpanStatusCode.ERROR, message: error.message });
61
+ throw ex;
44
62
  } finally {
45
63
  span2.end();
46
64
  }
@@ -50,11 +68,19 @@ function spanRoot(name, fn, tracer) {
50
68
  }
51
69
  }
52
70
  async function spanAsync(name, fn, tracer) {
53
- if (tracer) {
54
- const span2 = tracer.startSpan(name);
55
- return await context.with(trace.setSpan(context.active(), span2), async () => {
71
+ const activeTracer = tracer ?? TRACE_API.getTracer(name);
72
+ if (isDefined(activeTracer)) {
73
+ const span2 = activeTracer.startSpan(name);
74
+ return await context.with(TRACE_API.setSpan(context.active(), span2), async () => {
56
75
  try {
57
- return await fn();
76
+ const result = await fn();
77
+ span2.setStatus({ code: SpanStatusCode.OK });
78
+ return result;
79
+ } catch (ex) {
80
+ const error = ex;
81
+ span2.recordException(error);
82
+ span2.setStatus({ code: SpanStatusCode.ERROR, message: error.message });
83
+ throw ex;
58
84
  } finally {
59
85
  span2.end();
60
86
  }
@@ -64,13 +90,21 @@ async function spanAsync(name, fn, tracer) {
64
90
  }
65
91
  }
66
92
  async function spanRootAsync(name, fn, tracer) {
67
- if (tracer) {
93
+ const activeTracer = tracer ?? TRACE_API.getTracer(name);
94
+ if (isDefined(activeTracer)) {
68
95
  const activeContext = context.active();
69
96
  const noSpanContext = cloneContextWithoutSpan(activeContext);
70
- const span2 = tracer.startSpan(name, {}, noSpanContext);
71
- return await context.with(trace.setSpan(noSpanContext, span2), async () => {
97
+ const span2 = activeTracer.startSpan(name, {}, noSpanContext);
98
+ return await context.with(TRACE_API.setSpan(noSpanContext, span2), async () => {
72
99
  try {
73
- return await fn();
100
+ const result = await fn();
101
+ span2.setStatus({ code: SpanStatusCode.OK });
102
+ return result;
103
+ } catch (ex) {
104
+ const error = ex;
105
+ span2.recordException(error);
106
+ span2.setStatus({ code: SpanStatusCode.ERROR, message: error.message });
107
+ throw ex;
74
108
  } finally {
75
109
  span2.end();
76
110
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/span.ts"],"sourcesContent":["import type {\n Context,\n Tracer,\n} from '@opentelemetry/api'\nimport {\n context, propagation, ROOT_CONTEXT, trace,\n} from '@opentelemetry/api'\n\nexport function cloneContextWithoutSpan(activeCtx: Context, configKeys: symbol[] = []): Context {\n // Start from root to ensure no span is propagated\n let newCtx = ROOT_CONTEXT\n\n // Copy baggage\n const baggage = propagation.getBaggage(activeCtx)\n if (baggage) {\n newCtx = propagation.setBaggage(newCtx, baggage)\n }\n\n // Copy custom config keys\n for (const key of configKeys) {\n const value = activeCtx.getValue(key)\n if (value !== undefined) {\n newCtx = newCtx.setValue(key, value)\n }\n }\n\n return newCtx\n}\n\nexport function span<T>(name: string, fn: () => T, tracer?: Tracer): T {\n if (tracer) {\n const span = tracer.startSpan(name)\n return context.with(trace.setSpan(context.active(), span), () => {\n try {\n return fn()\n } finally {\n span.end()\n }\n })\n } else {\n return fn()\n }\n}\n\nexport function spanRoot<T>(name: string, fn: () => T, tracer?: Tracer): T {\n if (tracer) {\n // Get current active context for configuration\n const activeContext = context.active()\n\n // Create a new context with no active span\n const noSpanContext = cloneContextWithoutSpan(activeContext)\n\n // Create a new span in the context without an active span\n const span = tracer.startSpan(name, {}, noSpanContext)\n\n // Use the active context but replace its span with our new root span\n return context.with(trace.setSpan(noSpanContext, span), () => {\n try {\n return fn()\n } finally {\n span.end()\n }\n })\n } else {\n return fn()\n }\n}\n\nexport async function spanAsync<T>(\n name: string,\n fn: () => Promise<T>,\n tracer?: Tracer,\n): Promise<T> {\n if (tracer) {\n const span = tracer.startSpan(name)\n return await context.with(trace.setSpan(context.active(), span), async () => {\n try {\n return await fn()\n } finally {\n span.end()\n }\n })\n } else {\n return await fn()\n }\n}\n\nexport async function spanRootAsync<T>(\n name: string,\n fn: () => Promise<T>,\n tracer?: Tracer,\n): Promise<T> {\n if (tracer) {\n const activeContext = context.active()\n\n const noSpanContext = cloneContextWithoutSpan(activeContext)\n\n // Create a new span in the context without an active span\n const span = tracer.startSpan(name, {}, noSpanContext)\n\n // Use the active context but replace its span with our new root span\n return await context.with(trace.setSpan(noSpanContext, span), async () => {\n try {\n return await fn()\n } finally {\n span.end()\n }\n })\n } else {\n return await fn()\n }\n}\n"],"mappings":";AAIA;AAAA,EACE;AAAA,EAAS;AAAA,EAAa;AAAA,EAAc;AAAA,OAC/B;AAEA,SAAS,wBAAwB,WAAoB,aAAuB,CAAC,GAAY;AAE9F,MAAI,SAAS;AAGb,QAAM,UAAU,YAAY,WAAW,SAAS;AAChD,MAAI,SAAS;AACX,aAAS,YAAY,WAAW,QAAQ,OAAO;AAAA,EACjD;AAGA,aAAW,OAAO,YAAY;AAC5B,UAAM,QAAQ,UAAU,SAAS,GAAG;AACpC,QAAI,UAAU,QAAW;AACvB,eAAS,OAAO,SAAS,KAAK,KAAK;AAAA,IACrC;AAAA,EACF;AAEA,SAAO;AACT;AAEO,SAAS,KAAQ,MAAc,IAAa,QAAoB;AACrE,MAAI,QAAQ;AACV,UAAMA,QAAO,OAAO,UAAU,IAAI;AAClC,WAAO,QAAQ,KAAK,MAAM,QAAQ,QAAQ,OAAO,GAAGA,KAAI,GAAG,MAAM;AAC/D,UAAI;AACF,eAAO,GAAG;AAAA,MACZ,UAAE;AACA,QAAAA,MAAK,IAAI;AAAA,MACX;AAAA,IACF,CAAC;AAAA,EACH,OAAO;AACL,WAAO,GAAG;AAAA,EACZ;AACF;AAEO,SAAS,SAAY,MAAc,IAAa,QAAoB;AACzE,MAAI,QAAQ;AAEV,UAAM,gBAAgB,QAAQ,OAAO;AAGrC,UAAM,gBAAgB,wBAAwB,aAAa;AAG3D,UAAMA,QAAO,OAAO,UAAU,MAAM,CAAC,GAAG,aAAa;AAGrD,WAAO,QAAQ,KAAK,MAAM,QAAQ,eAAeA,KAAI,GAAG,MAAM;AAC5D,UAAI;AACF,eAAO,GAAG;AAAA,MACZ,UAAE;AACA,QAAAA,MAAK,IAAI;AAAA,MACX;AAAA,IACF,CAAC;AAAA,EACH,OAAO;AACL,WAAO,GAAG;AAAA,EACZ;AACF;AAEA,eAAsB,UACpB,MACA,IACA,QACY;AACZ,MAAI,QAAQ;AACV,UAAMA,QAAO,OAAO,UAAU,IAAI;AAClC,WAAO,MAAM,QAAQ,KAAK,MAAM,QAAQ,QAAQ,OAAO,GAAGA,KAAI,GAAG,YAAY;AAC3E,UAAI;AACF,eAAO,MAAM,GAAG;AAAA,MAClB,UAAE;AACA,QAAAA,MAAK,IAAI;AAAA,MACX;AAAA,IACF,CAAC;AAAA,EACH,OAAO;AACL,WAAO,MAAM,GAAG;AAAA,EAClB;AACF;AAEA,eAAsB,cACpB,MACA,IACA,QACY;AACZ,MAAI,QAAQ;AACV,UAAM,gBAAgB,QAAQ,OAAO;AAErC,UAAM,gBAAgB,wBAAwB,aAAa;AAG3D,UAAMA,QAAO,OAAO,UAAU,MAAM,CAAC,GAAG,aAAa;AAGrD,WAAO,MAAM,QAAQ,KAAK,MAAM,QAAQ,eAAeA,KAAI,GAAG,YAAY;AACxE,UAAI;AACF,eAAO,MAAM,GAAG;AAAA,MAClB,UAAE;AACA,QAAAA,MAAK,IAAI;AAAA,MACX;AAAA,IACF,CAAC;AAAA,EACH,OAAO;AACL,WAAO,MAAM,GAAG;AAAA,EAClB;AACF;","names":["span"]}
1
+ {"version":3,"sources":["../../src/span.ts"],"sourcesContent":["import type {\n Context,\n Tracer,\n} from '@opentelemetry/api'\nimport {\n context, propagation, ROOT_CONTEXT, SpanStatusCode, trace as TRACE_API,\n} from '@opentelemetry/api'\nimport { isDefined } from '@xylabs/typeof'\n\nexport function cloneContextWithoutSpan(activeCtx: Context, configKeys: symbol[] = []): Context {\n // Start from root to ensure no span is propagated\n let newCtx = ROOT_CONTEXT\n\n // Copy baggage\n const baggage = propagation.getBaggage(activeCtx)\n if (baggage) {\n newCtx = propagation.setBaggage(newCtx, baggage)\n }\n\n // Copy custom config keys\n for (const key of configKeys) {\n const value = activeCtx.getValue(key)\n if (value !== undefined) {\n newCtx = newCtx.setValue(key, value)\n }\n }\n\n return newCtx\n}\n\nexport function span<T>(name: string, fn: () => T, tracer?: Tracer): T {\n const activeTracer = tracer ?? TRACE_API.getTracer(name)\n if (isDefined(activeTracer)) {\n const span = activeTracer.startSpan(name)\n return context.with(TRACE_API.setSpan(context.active(), span), () => {\n try {\n const result = fn()\n span.setStatus({ code: SpanStatusCode.OK })\n return result\n } catch (ex) {\n const error = ex as Error\n span.recordException(error)\n span.setStatus({ code: SpanStatusCode.ERROR, message: error.message })\n throw ex\n } finally {\n span.end()\n }\n })\n } else {\n return fn()\n }\n}\n\nexport function spanRoot<T>(name: string, fn: () => T, tracer?: Tracer): T {\n const activeTracer = tracer ?? TRACE_API.getTracer(name)\n if (isDefined(activeTracer)) {\n // Get current active context for configuration\n const activeContext = context.active()\n\n // Create a new context with no active span\n const noSpanContext = cloneContextWithoutSpan(activeContext)\n\n // Create a new span in the context without an active span\n const span = activeTracer.startSpan(name, {}, noSpanContext)\n\n // Use the active context but replace its span with our new root span\n return context.with(TRACE_API.setSpan(noSpanContext, span), () => {\n try {\n const result = fn()\n span.setStatus({ code: SpanStatusCode.OK })\n return result\n } catch (ex) {\n const error = ex as Error\n span.recordException(error)\n span.setStatus({ code: SpanStatusCode.ERROR, message: error.message })\n throw ex\n } finally {\n span.end()\n }\n })\n } else {\n return fn()\n }\n}\n\nexport async function spanAsync<T>(\n name: string,\n fn: () => Promise<T>,\n tracer?: Tracer,\n): Promise<T> {\n const activeTracer = tracer ?? TRACE_API.getTracer(name)\n if (isDefined(activeTracer)) {\n const span = activeTracer.startSpan(name)\n return await context.with(TRACE_API.setSpan(context.active(), span), async () => {\n try {\n const result = await fn()\n span.setStatus({ code: SpanStatusCode.OK })\n return result\n } catch (ex) {\n const error = ex as Error\n span.recordException(error)\n span.setStatus({ code: SpanStatusCode.ERROR, message: error.message })\n throw ex\n } finally {\n span.end()\n }\n })\n } else {\n return await fn()\n }\n}\n\nexport async function spanRootAsync<T>(\n name: string,\n fn: () => Promise<T>,\n tracer?: Tracer,\n): Promise<T> {\n const activeTracer = tracer ?? TRACE_API.getTracer(name)\n if (isDefined(activeTracer)) {\n const activeContext = context.active()\n\n const noSpanContext = cloneContextWithoutSpan(activeContext)\n\n // Create a new span in the context without an active span\n const span = activeTracer.startSpan(name, {}, noSpanContext)\n\n // Use the active context but replace its span with our new root span\n return await context.with(TRACE_API.setSpan(noSpanContext, span), async () => {\n try {\n const result = await fn()\n span.setStatus({ code: SpanStatusCode.OK })\n return result\n } catch (ex) {\n const error = ex as Error\n span.recordException(error)\n span.setStatus({ code: SpanStatusCode.ERROR, message: error.message })\n throw ex\n } finally {\n span.end()\n }\n })\n } else {\n return await fn()\n }\n}\n"],"mappings":";AAIA;AAAA,EACE;AAAA,EAAS;AAAA,EAAa;AAAA,EAAc;AAAA,EAAgB,SAAS;AAAA,OACxD;AACP,SAAS,iBAAiB;AAEnB,SAAS,wBAAwB,WAAoB,aAAuB,CAAC,GAAY;AAE9F,MAAI,SAAS;AAGb,QAAM,UAAU,YAAY,WAAW,SAAS;AAChD,MAAI,SAAS;AACX,aAAS,YAAY,WAAW,QAAQ,OAAO;AAAA,EACjD;AAGA,aAAW,OAAO,YAAY;AAC5B,UAAM,QAAQ,UAAU,SAAS,GAAG;AACpC,QAAI,UAAU,QAAW;AACvB,eAAS,OAAO,SAAS,KAAK,KAAK;AAAA,IACrC;AAAA,EACF;AAEA,SAAO;AACT;AAEO,SAAS,KAAQ,MAAc,IAAa,QAAoB;AACrE,QAAM,eAAe,UAAU,UAAU,UAAU,IAAI;AACvD,MAAI,UAAU,YAAY,GAAG;AAC3B,UAAMA,QAAO,aAAa,UAAU,IAAI;AACxC,WAAO,QAAQ,KAAK,UAAU,QAAQ,QAAQ,OAAO,GAAGA,KAAI,GAAG,MAAM;AACnE,UAAI;AACF,cAAM,SAAS,GAAG;AAClB,QAAAA,MAAK,UAAU,EAAE,MAAM,eAAe,GAAG,CAAC;AAC1C,eAAO;AAAA,MACT,SAAS,IAAI;AACX,cAAM,QAAQ;AACd,QAAAA,MAAK,gBAAgB,KAAK;AAC1B,QAAAA,MAAK,UAAU,EAAE,MAAM,eAAe,OAAO,SAAS,MAAM,QAAQ,CAAC;AACrE,cAAM;AAAA,MACR,UAAE;AACA,QAAAA,MAAK,IAAI;AAAA,MACX;AAAA,IACF,CAAC;AAAA,EACH,OAAO;AACL,WAAO,GAAG;AAAA,EACZ;AACF;AAEO,SAAS,SAAY,MAAc,IAAa,QAAoB;AACzE,QAAM,eAAe,UAAU,UAAU,UAAU,IAAI;AACvD,MAAI,UAAU,YAAY,GAAG;AAE3B,UAAM,gBAAgB,QAAQ,OAAO;AAGrC,UAAM,gBAAgB,wBAAwB,aAAa;AAG3D,UAAMA,QAAO,aAAa,UAAU,MAAM,CAAC,GAAG,aAAa;AAG3D,WAAO,QAAQ,KAAK,UAAU,QAAQ,eAAeA,KAAI,GAAG,MAAM;AAChE,UAAI;AACF,cAAM,SAAS,GAAG;AAClB,QAAAA,MAAK,UAAU,EAAE,MAAM,eAAe,GAAG,CAAC;AAC1C,eAAO;AAAA,MACT,SAAS,IAAI;AACX,cAAM,QAAQ;AACd,QAAAA,MAAK,gBAAgB,KAAK;AAC1B,QAAAA,MAAK,UAAU,EAAE,MAAM,eAAe,OAAO,SAAS,MAAM,QAAQ,CAAC;AACrE,cAAM;AAAA,MACR,UAAE;AACA,QAAAA,MAAK,IAAI;AAAA,MACX;AAAA,IACF,CAAC;AAAA,EACH,OAAO;AACL,WAAO,GAAG;AAAA,EACZ;AACF;AAEA,eAAsB,UACpB,MACA,IACA,QACY;AACZ,QAAM,eAAe,UAAU,UAAU,UAAU,IAAI;AACvD,MAAI,UAAU,YAAY,GAAG;AAC3B,UAAMA,QAAO,aAAa,UAAU,IAAI;AACxC,WAAO,MAAM,QAAQ,KAAK,UAAU,QAAQ,QAAQ,OAAO,GAAGA,KAAI,GAAG,YAAY;AAC/E,UAAI;AACF,cAAM,SAAS,MAAM,GAAG;AACxB,QAAAA,MAAK,UAAU,EAAE,MAAM,eAAe,GAAG,CAAC;AAC1C,eAAO;AAAA,MACT,SAAS,IAAI;AACX,cAAM,QAAQ;AACd,QAAAA,MAAK,gBAAgB,KAAK;AAC1B,QAAAA,MAAK,UAAU,EAAE,MAAM,eAAe,OAAO,SAAS,MAAM,QAAQ,CAAC;AACrE,cAAM;AAAA,MACR,UAAE;AACA,QAAAA,MAAK,IAAI;AAAA,MACX;AAAA,IACF,CAAC;AAAA,EACH,OAAO;AACL,WAAO,MAAM,GAAG;AAAA,EAClB;AACF;AAEA,eAAsB,cACpB,MACA,IACA,QACY;AACZ,QAAM,eAAe,UAAU,UAAU,UAAU,IAAI;AACvD,MAAI,UAAU,YAAY,GAAG;AAC3B,UAAM,gBAAgB,QAAQ,OAAO;AAErC,UAAM,gBAAgB,wBAAwB,aAAa;AAG3D,UAAMA,QAAO,aAAa,UAAU,MAAM,CAAC,GAAG,aAAa;AAG3D,WAAO,MAAM,QAAQ,KAAK,UAAU,QAAQ,eAAeA,KAAI,GAAG,YAAY;AAC5E,UAAI;AACF,cAAM,SAAS,MAAM,GAAG;AACxB,QAAAA,MAAK,UAAU,EAAE,MAAM,eAAe,GAAG,CAAC;AAC1C,eAAO;AAAA,MACT,SAAS,IAAI;AACX,cAAM,QAAQ;AACd,QAAAA,MAAK,gBAAgB,KAAK;AAC1B,QAAAA,MAAK,UAAU,EAAE,MAAM,eAAe,OAAO,SAAS,MAAM,QAAQ,CAAC;AACrE,cAAM;AAAA,MACR,UAAE;AACA,QAAAA,MAAK,IAAI;AAAA,MACX;AAAA,IACF,CAAC;AAAA,EACH,OAAO;AACL,WAAO,MAAM,GAAG;AAAA,EAClB;AACF;","names":["span"]}
@@ -1 +1 @@
1
- {"version":3,"file":"span.d.ts","sourceRoot":"","sources":["../../src/span.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EACP,MAAM,EACP,MAAM,oBAAoB,CAAA;AAK3B,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,OAAO,EAAE,UAAU,GAAE,MAAM,EAAO,GAAG,OAAO,CAmB9F;AAED,wBAAgB,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,CAAC,CAarE;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,CAAC,CAsBzE;AAED,wBAAsB,SAAS,CAAC,CAAC,EAC/B,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,CAAC,CAAC,CAaZ;AAED,wBAAsB,aAAa,CAAC,CAAC,EACnC,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,CAAC,CAAC,CAoBZ"}
1
+ {"version":3,"file":"span.d.ts","sourceRoot":"","sources":["../../src/span.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EACP,MAAM,EACP,MAAM,oBAAoB,CAAA;AAM3B,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,OAAO,EAAE,UAAU,GAAE,MAAM,EAAO,GAAG,OAAO,CAmB9F;AAED,wBAAgB,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,CAAC,CAqBrE;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,CAAC,CA8BzE;AAED,wBAAsB,SAAS,CAAC,CAAC,EAC/B,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,CAAC,CAAC,CAqBZ;AAED,wBAAsB,aAAa,CAAC,CAAC,EACnC,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,CAAC,CAAC,CA4BZ"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xylabs/telemetry",
3
- "version": "4.9.18",
3
+ "version": "4.10.1",
4
4
  "description": "Base functionality used throughout XY Labs TypeScript/JavaScript libraries",
5
5
  "keywords": [
6
6
  "hex",
@@ -39,11 +39,12 @@
39
39
  "packages/**/*"
40
40
  ],
41
41
  "dependencies": {
42
- "@opentelemetry/api": "^1.9.0"
42
+ "@opentelemetry/api": "^1.9.0",
43
+ "@xylabs/typeof": "^4.10.1"
43
44
  },
44
45
  "devDependencies": {
45
- "@xylabs/ts-scripts-yarn3": "^6.5.5",
46
- "@xylabs/tsconfig": "^6.5.5",
46
+ "@xylabs/ts-scripts-yarn3": "^6.5.7",
47
+ "@xylabs/tsconfig": "^6.5.7",
47
48
  "typescript": "^5.8.3"
48
49
  },
49
50
  "engines": {
package/src/span.ts CHANGED
@@ -3,8 +3,9 @@ import type {
3
3
  Tracer,
4
4
  } from '@opentelemetry/api'
5
5
  import {
6
- context, propagation, ROOT_CONTEXT, trace,
6
+ context, propagation, ROOT_CONTEXT, SpanStatusCode, trace as TRACE_API,
7
7
  } from '@opentelemetry/api'
8
+ import { isDefined } from '@xylabs/typeof'
8
9
 
9
10
  export function cloneContextWithoutSpan(activeCtx: Context, configKeys: symbol[] = []): Context {
10
11
  // Start from root to ensure no span is propagated
@@ -28,11 +29,19 @@ export function cloneContextWithoutSpan(activeCtx: Context, configKeys: symbol[]
28
29
  }
29
30
 
30
31
  export function span<T>(name: string, fn: () => T, tracer?: Tracer): T {
31
- if (tracer) {
32
- const span = tracer.startSpan(name)
33
- return context.with(trace.setSpan(context.active(), span), () => {
32
+ const activeTracer = tracer ?? TRACE_API.getTracer(name)
33
+ if (isDefined(activeTracer)) {
34
+ const span = activeTracer.startSpan(name)
35
+ return context.with(TRACE_API.setSpan(context.active(), span), () => {
34
36
  try {
35
- return fn()
37
+ const result = fn()
38
+ span.setStatus({ code: SpanStatusCode.OK })
39
+ return result
40
+ } catch (ex) {
41
+ const error = ex as Error
42
+ span.recordException(error)
43
+ span.setStatus({ code: SpanStatusCode.ERROR, message: error.message })
44
+ throw ex
36
45
  } finally {
37
46
  span.end()
38
47
  }
@@ -43,7 +52,8 @@ export function span<T>(name: string, fn: () => T, tracer?: Tracer): T {
43
52
  }
44
53
 
45
54
  export function spanRoot<T>(name: string, fn: () => T, tracer?: Tracer): T {
46
- if (tracer) {
55
+ const activeTracer = tracer ?? TRACE_API.getTracer(name)
56
+ if (isDefined(activeTracer)) {
47
57
  // Get current active context for configuration
48
58
  const activeContext = context.active()
49
59
 
@@ -51,12 +61,19 @@ export function spanRoot<T>(name: string, fn: () => T, tracer?: Tracer): T {
51
61
  const noSpanContext = cloneContextWithoutSpan(activeContext)
52
62
 
53
63
  // Create a new span in the context without an active span
54
- const span = tracer.startSpan(name, {}, noSpanContext)
64
+ const span = activeTracer.startSpan(name, {}, noSpanContext)
55
65
 
56
66
  // Use the active context but replace its span with our new root span
57
- return context.with(trace.setSpan(noSpanContext, span), () => {
67
+ return context.with(TRACE_API.setSpan(noSpanContext, span), () => {
58
68
  try {
59
- return fn()
69
+ const result = fn()
70
+ span.setStatus({ code: SpanStatusCode.OK })
71
+ return result
72
+ } catch (ex) {
73
+ const error = ex as Error
74
+ span.recordException(error)
75
+ span.setStatus({ code: SpanStatusCode.ERROR, message: error.message })
76
+ throw ex
60
77
  } finally {
61
78
  span.end()
62
79
  }
@@ -71,11 +88,19 @@ export async function spanAsync<T>(
71
88
  fn: () => Promise<T>,
72
89
  tracer?: Tracer,
73
90
  ): Promise<T> {
74
- if (tracer) {
75
- const span = tracer.startSpan(name)
76
- return await context.with(trace.setSpan(context.active(), span), async () => {
91
+ const activeTracer = tracer ?? TRACE_API.getTracer(name)
92
+ if (isDefined(activeTracer)) {
93
+ const span = activeTracer.startSpan(name)
94
+ return await context.with(TRACE_API.setSpan(context.active(), span), async () => {
77
95
  try {
78
- return await fn()
96
+ const result = await fn()
97
+ span.setStatus({ code: SpanStatusCode.OK })
98
+ return result
99
+ } catch (ex) {
100
+ const error = ex as Error
101
+ span.recordException(error)
102
+ span.setStatus({ code: SpanStatusCode.ERROR, message: error.message })
103
+ throw ex
79
104
  } finally {
80
105
  span.end()
81
106
  }
@@ -90,18 +115,26 @@ export async function spanRootAsync<T>(
90
115
  fn: () => Promise<T>,
91
116
  tracer?: Tracer,
92
117
  ): Promise<T> {
93
- if (tracer) {
118
+ const activeTracer = tracer ?? TRACE_API.getTracer(name)
119
+ if (isDefined(activeTracer)) {
94
120
  const activeContext = context.active()
95
121
 
96
122
  const noSpanContext = cloneContextWithoutSpan(activeContext)
97
123
 
98
124
  // Create a new span in the context without an active span
99
- const span = tracer.startSpan(name, {}, noSpanContext)
125
+ const span = activeTracer.startSpan(name, {}, noSpanContext)
100
126
 
101
127
  // Use the active context but replace its span with our new root span
102
- return await context.with(trace.setSpan(noSpanContext, span), async () => {
128
+ return await context.with(TRACE_API.setSpan(noSpanContext, span), async () => {
103
129
  try {
104
- return await fn()
130
+ const result = await fn()
131
+ span.setStatus({ code: SpanStatusCode.OK })
132
+ return result
133
+ } catch (ex) {
134
+ const error = ex as Error
135
+ span.recordException(error)
136
+ span.setStatus({ code: SpanStatusCode.ERROR, message: error.message })
137
+ throw ex
105
138
  } finally {
106
139
  span.end()
107
140
  }