@blaxel/telemetry 0.2.18-dev.141 → 0.2.18-dev.145

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.
@@ -34,7 +34,6 @@ declare class TelemetryManager {
34
34
  private configured;
35
35
  constructor();
36
36
  initialize(): void;
37
- setupBasicTracerProvider(): void;
38
37
  setConfiguration(): Promise<void>;
39
38
  get tracer(): import("@opentelemetry/api").Tracer;
40
39
  get enabled(): boolean;
package/dist/telemetry.js CHANGED
@@ -78,49 +78,13 @@ class TelemetryManager {
78
78
  if (!this.enabled || this.initialized) {
79
79
  return;
80
80
  }
81
- // Setup basic TracerProvider first - this is critical for context propagation
82
- this.setupBasicTracerProvider();
83
- // Now setup instrumentation - it can now extract traceparent headers
84
81
  this.instrumentApp();
85
82
  this.setupSignalHandler();
86
83
  this.initialized = true;
87
- // Add exporters later asynchronously
88
84
  this.setConfiguration().catch((error) => {
89
85
  core_1.logger.error("Error setting configuration:", error);
90
86
  });
91
87
  }
92
- setupBasicTracerProvider() {
93
- const resource = new BlaxelResource(this.resourceAttributes);
94
- // Create TracerProvider with complete setup including exporters
95
- // This ensures we don't need to recreate it later, preserving context
96
- const spanProcessors = [
97
- new DefaultAttributesSpanProcessor({
98
- "workload.id": core_1.settings.name || "",
99
- "workload.type": core_1.settings.type ? core_1.settings.type + "s" : "",
100
- workspace: core_1.settings.workspace || "",
101
- }),
102
- ];
103
- // Try to add exporters if authentication is available
104
- try {
105
- if (core_1.settings.authorization) {
106
- const traceExporter = this.getTraceExporter();
107
- spanProcessors.push(new sdk_trace_node_1.BatchSpanProcessor(traceExporter));
108
- spanProcessors.push(new HasBeenProcessedSpanProcessor(traceExporter));
109
- console.log("🚀 TracerProvider created with exporters from the start");
110
- }
111
- }
112
- catch {
113
- console.log("🚀 TracerProvider created without exporters - will be added later");
114
- }
115
- this.nodeTracerProvider = new sdk_trace_node_1.NodeTracerProvider({
116
- resource,
117
- sampler: new sdk_trace_node_1.AlwaysOnSampler(),
118
- spanProcessors,
119
- });
120
- // Register immediately - this enables context propagation
121
- this.nodeTracerProvider.register();
122
- console.log("🚀 TracerProvider registered BEFORE instrumentation - context propagation enabled");
123
- }
124
88
  async setConfiguration() {
125
89
  if (!this.enabled || this.configured) {
126
90
  return;
@@ -228,48 +192,58 @@ class TelemetryManager {
228
192
  });
229
193
  }
230
194
  instrumentApp() {
231
- // Setup telemetry provider first
232
195
  core_1.telemetryRegistry.registerProvider(new telemetry_provider_1.OtelTelemetryProvider());
233
196
  const httpInstrumentation = new instrumentation_http_1.HttpInstrumentation({
234
- requireParentforOutgoingSpans: true, // Maintain parent-child relationships
235
- requestHook: (span) => {
236
- // Debug incoming trace headers
237
- console.log("=== HTTP INSTRUMENTATION REQUEST HOOK ===");
238
- // Check if TracerProvider is registered
239
- const tracer = api_1.trace.getTracer("debug");
240
- console.log("TracerProvider available:", !!tracer);
241
- // Check active context
242
- const activeContext = api_1.context.active();
243
- const spanContext = api_1.trace.getSpanContext(activeContext);
244
- console.log("Span context from active context:", spanContext
245
- ? {
246
- traceId: spanContext.traceId,
247
- spanId: spanContext.spanId,
248
- traceFlags: spanContext.traceFlags,
249
- }
250
- : "null");
251
- // Check current span context after HTTP instrumentation processes headers
252
- const activeSpan = api_1.trace.getActiveSpan();
253
- if (activeSpan) {
254
- console.log("✅ Active span found in request hook:", {
255
- traceId: activeSpan.spanContext().traceId,
256
- spanId: activeSpan.spanContext().spanId,
257
- traceFlags: activeSpan.spanContext().traceFlags,
197
+ requireParentforOutgoingSpans: true,
198
+ // Add hooks to debug context propagation
199
+ startIncomingSpanHook: (request) => {
200
+ const headers = request.headers;
201
+ const traceparent = headers?.traceparent;
202
+ const tracestate = headers?.tracestate;
203
+ if (traceparent) {
204
+ core_1.logger.debug("Incoming request with traceparent header", {
205
+ traceparent,
206
+ tracestate,
207
+ url: request.url,
208
+ method: request.method,
258
209
  });
259
210
  }
260
211
  else {
261
- console.log(" No active span found in request hook");
262
- console.log("Possible causes:");
263
- console.log("1. TracerProvider not registered before HTTP instrumentation");
264
- console.log("2. Traceparent header not properly extracted");
265
- console.log("3. Context lost across async boundaries");
212
+ core_1.logger.debug("Incoming request without traceparent header", {
213
+ url: request.url,
214
+ method: request.method,
215
+ headers: Object.keys(headers || {}),
216
+ });
266
217
  }
267
- console.log("Current span from hook parameter:", {
268
- traceId: span.spanContext().traceId,
269
- spanId: span.spanContext().spanId,
270
- traceFlags: span.spanContext().traceFlags,
218
+ // Return attributes object as expected by the hook
219
+ return {};
220
+ },
221
+ startOutgoingSpanHook: (request) => {
222
+ core_1.logger.debug("Starting outgoing request span", {
223
+ path: request.path,
224
+ method: request.method,
225
+ });
226
+ // Return attributes object as expected by the hook
227
+ return {};
228
+ },
229
+ // Add additional hooks for debugging
230
+ responseHook: (span, response) => {
231
+ const statusCode = "statusCode" in response ? response.statusCode : undefined;
232
+ const headers = "headers" in response ? response.headers : undefined;
233
+ core_1.logger.debug("HTTP response received", {
234
+ statusCode,
235
+ headers: headers ? Object.keys(headers) : [],
236
+ });
237
+ },
238
+ requestHook: (span, request) => {
239
+ const url = "url" in request ? request.url : undefined;
240
+ const method = "method" in request ? request.method : undefined;
241
+ const headers = "headers" in request ? request.headers : undefined;
242
+ core_1.logger.debug("HTTP request being made", {
243
+ url,
244
+ method,
245
+ headers: headers ? Object.keys(headers) : [],
271
246
  });
272
- console.log("=== END HTTP INSTRUMENTATION REQUEST HOOK ===");
273
247
  },
274
248
  });
275
249
  (0, instrumentation_1.registerInstrumentations)({
@@ -278,46 +252,27 @@ class TelemetryManager {
278
252
  }
279
253
  setExporters() {
280
254
  const resource = new BlaxelResource(this.resourceAttributes);
281
- // Setup logging
282
255
  const logExporter = this.getLogExporter();
283
256
  this.loggerProvider = new sdk_logs_1.LoggerProvider({
284
257
  resource,
285
258
  });
286
259
  this.loggerProvider.addLogRecordProcessor(new sdk_logs_1.BatchLogRecordProcessor(logExporter));
287
260
  api_logs_1.logs.setGlobalLoggerProvider(this.loggerProvider);
288
- // Check if we need to add exporters to existing TracerProvider
289
- if (this.nodeTracerProvider && !core_1.settings.authorization) {
290
- // If we didn't have authorization before but we do now, recreate with exporters
291
- // But only if we didn't already have them
292
- try {
293
- const traceExporter = this.getTraceExporter();
294
- // Unfortunately, we need to recreate the TracerProvider to add exporters
295
- // This is a limitation of OpenTelemetry SDK
296
- const newTracerProvider = new sdk_trace_node_1.NodeTracerProvider({
297
- resource,
298
- sampler: new sdk_trace_node_1.AlwaysOnSampler(),
299
- spanProcessors: [
300
- new DefaultAttributesSpanProcessor({
301
- "workload.id": core_1.settings.name || "",
302
- "workload.type": core_1.settings.type ? core_1.settings.type + "s" : "",
303
- workspace: core_1.settings.workspace || "",
304
- }),
305
- new sdk_trace_node_1.BatchSpanProcessor(traceExporter),
306
- new HasBeenProcessedSpanProcessor(traceExporter),
307
- ],
308
- });
309
- this.nodeTracerProvider = newTracerProvider;
310
- this.nodeTracerProvider.register();
311
- console.log("📡 TracerProvider updated with exporters");
312
- }
313
- catch {
314
- console.log("📡 Could not add exporters to TracerProvider");
315
- }
316
- }
317
- else {
318
- console.log("📡 TracerProvider already has exporters or no changes needed");
319
- }
320
- // Setup metrics
261
+ const traceExporter = this.getTraceExporter();
262
+ this.nodeTracerProvider = new sdk_trace_node_1.NodeTracerProvider({
263
+ resource,
264
+ sampler: new sdk_trace_node_1.AlwaysOnSampler(),
265
+ spanProcessors: [
266
+ new DefaultAttributesSpanProcessor({
267
+ "workload.id": core_1.settings.name || "",
268
+ "workload.type": core_1.settings.type ? core_1.settings.type + "s" : "",
269
+ workspace: core_1.settings.workspace || "",
270
+ }),
271
+ new sdk_trace_node_1.BatchSpanProcessor(traceExporter),
272
+ new HasBeenProcessedSpanProcessor(traceExporter),
273
+ ],
274
+ });
275
+ this.nodeTracerProvider.register();
321
276
  const metricExporter = this.getMetricExporter();
322
277
  this.meterProvider = new sdk_metrics_1.MeterProvider({
323
278
  resource,
@@ -1,5 +1,10 @@
1
1
  import { BlaxelSpan, BlaxelSpanOptions, BlaxelTelemetryProvider } from "@blaxel/core";
2
2
  export declare class OtelTelemetryProvider implements BlaxelTelemetryProvider {
3
3
  startSpan(name: string, options?: BlaxelSpanOptions): BlaxelSpan;
4
+ /**
5
+ * Extract context from headers manually
6
+ * This can be used when automatic context propagation isn't working
7
+ */
8
+ extractContextFromHeaders(headers: Record<string, string | string[]>): unknown;
4
9
  flush(): Promise<void>;
5
10
  }
@@ -1,11 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.OtelTelemetryProvider = void 0;
4
+ const core_1 = require("@blaxel/core");
4
5
  const api_1 = require("@opentelemetry/api");
5
6
  const telemetry_1 = require("./telemetry");
6
7
  class OtelSpan {
7
8
  span;
8
- closed = false;
9
9
  constructor(span) {
10
10
  this.span = span;
11
11
  }
@@ -26,7 +26,6 @@ class OtelSpan {
26
26
  });
27
27
  }
28
28
  end() {
29
- this.closed = true;
30
29
  this.span.end();
31
30
  }
32
31
  getContext() {
@@ -35,39 +34,127 @@ class OtelSpan {
35
34
  }
36
35
  class OtelTelemetryProvider {
37
36
  startSpan(name, options) {
37
+ // Use the tracer from the registered NodeTracerProvider
38
38
  const tracer = api_1.trace.getTracer("blaxel");
39
- // Get the current active context - this will include any traceparent propagation
40
- const activeContext = api_1.context.active();
39
+ // Get the current active context
40
+ let ctx = api_1.context.active();
41
41
  const activeSpan = api_1.trace.getActiveSpan();
42
- // Debug logging to help understand context propagation
43
- console.log("=== CREATING NEW SPAN ===");
44
- console.log("Span name:", name);
45
- console.log("Active context span:", activeSpan
46
- ? {
47
- traceId: activeSpan.spanContext().traceId,
48
- spanId: activeSpan.spanContext().spanId,
49
- traceFlags: activeSpan.spanContext().traceFlags,
42
+ // Log context information for debugging
43
+ if (activeSpan) {
44
+ const spanContext = activeSpan.spanContext();
45
+ core_1.logger.debug("Creating span with active parent context", {
46
+ spanName: name,
47
+ parentTraceId: spanContext.traceId,
48
+ parentSpanId: spanContext.spanId,
49
+ isRoot: options?.isRoot,
50
+ });
51
+ }
52
+ else {
53
+ core_1.logger.debug("Creating span without active parent context", {
54
+ spanName: name,
55
+ isRoot: options?.isRoot,
56
+ contextProvided: !!options?.parentContext,
57
+ });
58
+ // Try to extract context from headers if available in the environment
59
+ // This is a fallback when HttpInstrumentation doesn't set the context properly
60
+ if (typeof globalThis !== "undefined" && globalThis.process?.env) {
61
+ const headers = {};
62
+ // Check if there are any trace headers in the environment
63
+ if (process.env.TRACEPARENT) {
64
+ headers["traceparent"] = process.env.TRACEPARENT;
65
+ }
66
+ if (process.env.TRACESTATE) {
67
+ headers["tracestate"] = process.env.TRACESTATE;
68
+ }
69
+ if (headers.traceparent) {
70
+ core_1.logger.debug("Found traceparent in environment, attempting to extract context", {
71
+ traceparent: headers.traceparent,
72
+ tracestate: headers.tracestate,
73
+ });
74
+ try {
75
+ const extractedContext = api_1.propagation.extract(api_1.context.active(), headers);
76
+ const extractedSpan = api_1.trace.getSpan(extractedContext);
77
+ if (extractedSpan) {
78
+ ctx = extractedContext;
79
+ core_1.logger.debug("Successfully extracted context from traceparent", {
80
+ extractedTraceId: extractedSpan.spanContext().traceId,
81
+ extractedSpanId: extractedSpan.spanContext().spanId,
82
+ });
83
+ }
84
+ }
85
+ catch (error) {
86
+ core_1.logger.debug("Failed to extract context from traceparent", {
87
+ error: error instanceof Error ? error.message : String(error),
88
+ });
89
+ }
90
+ }
50
91
  }
51
- : "null");
52
- // Check if there's a span context in the active context (from traceparent headers)
53
- const spanContext = api_1.trace.getSpanContext(activeContext);
54
- if (spanContext) {
55
- console.log("Span context from active context:", {
56
- traceId: spanContext.traceId,
57
- spanId: spanContext.spanId,
58
- traceFlags: spanContext.traceFlags,
92
+ }
93
+ // Handle parent context if provided
94
+ if (options?.parentContext) {
95
+ ctx = options.parentContext;
96
+ core_1.logger.debug("Using provided parent context for span", {
97
+ spanName: name,
59
98
  });
60
99
  }
100
+ // Prepare OpenTelemetry span options
61
101
  const otelOptions = {
62
102
  attributes: options?.attributes,
63
103
  root: options?.isRoot,
64
104
  };
65
- // Use the active context unless explicitly requesting a root span
66
- const contextToUse = options?.isRoot ? api_1.ROOT_CONTEXT : activeContext;
67
- const span = new OtelSpan(tracer.startSpan(name, otelOptions, contextToUse));
68
- console.log("Created span context:", span.getContext());
69
- console.log("=== END CREATING NEW SPAN ===");
70
- return span;
105
+ // Start the span
106
+ const span = tracer.startSpan(name, otelOptions, ctx);
107
+ const spanContext = span.spanContext();
108
+ core_1.logger.debug("Span created successfully", {
109
+ spanName: name,
110
+ traceId: spanContext.traceId,
111
+ spanId: spanContext.spanId,
112
+ isRoot: options?.isRoot,
113
+ });
114
+ return new OtelSpan(span);
115
+ }
116
+ /**
117
+ * Extract context from headers manually
118
+ * This can be used when automatic context propagation isn't working
119
+ */
120
+ extractContextFromHeaders(headers) {
121
+ try {
122
+ // Normalize headers to string values
123
+ const normalizedHeaders = {};
124
+ Object.entries(headers).forEach(([key, value]) => {
125
+ if (Array.isArray(value)) {
126
+ normalizedHeaders[key.toLowerCase()] = value[0] || "";
127
+ }
128
+ else if (typeof value === "string") {
129
+ normalizedHeaders[key.toLowerCase()] = value;
130
+ }
131
+ });
132
+ core_1.logger.debug("Attempting to extract context from headers", {
133
+ headers: Object.keys(normalizedHeaders),
134
+ traceparent: normalizedHeaders.traceparent,
135
+ tracestate: normalizedHeaders.tracestate,
136
+ });
137
+ const extractedContext = api_1.propagation.extract(api_1.context.active(), normalizedHeaders);
138
+ const extractedSpan = api_1.trace.getSpan(extractedContext);
139
+ if (extractedSpan) {
140
+ const spanContext = extractedSpan.spanContext();
141
+ core_1.logger.debug("Successfully extracted context from headers", {
142
+ traceId: spanContext.traceId,
143
+ spanId: spanContext.spanId,
144
+ });
145
+ return extractedContext;
146
+ }
147
+ else {
148
+ core_1.logger.debug("No span found in extracted context");
149
+ return null;
150
+ }
151
+ }
152
+ catch (error) {
153
+ core_1.logger.debug("Failed to extract context from headers", {
154
+ error: error instanceof Error ? error.message : String(error),
155
+ });
156
+ return null;
157
+ }
71
158
  }
72
159
  async flush() {
73
160
  await telemetry_1.blaxelTelemetry.flush();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blaxel/telemetry",
3
- "version": "0.2.18-dev.141",
3
+ "version": "0.2.18-dev.145",
4
4
  "description": "Blaxel SDK for TypeScript",
5
5
  "license": "MIT",
6
6
  "author": "Blaxel, INC (https://blaxel.ai)",
@@ -71,7 +71,7 @@
71
71
  "@opentelemetry/sdk-trace-base": "^2.0.0",
72
72
  "@opentelemetry/sdk-trace-node": "^2.0.0",
73
73
  "ai": "^4.3.13",
74
- "@blaxel/core": "0.2.18-dev.141"
74
+ "@blaxel/core": "0.2.18-dev.145"
75
75
  },
76
76
  "devDependencies": {
77
77
  "@eslint/js": "^9.26.0",