@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.
- package/dist/telemetry.d.ts +0 -1
- package/dist/telemetry.js +60 -105
- package/dist/telemetry_provider.d.ts +5 -0
- package/dist/telemetry_provider.js +113 -26
- package/package.json +2 -2
package/dist/telemetry.d.ts
CHANGED
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,
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
const
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
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
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
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
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
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
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
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
|
|
40
|
-
|
|
39
|
+
// Get the current active context
|
|
40
|
+
let ctx = api_1.context.active();
|
|
41
41
|
const activeSpan = api_1.trace.getActiveSpan();
|
|
42
|
-
//
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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
|
-
|
|
52
|
-
//
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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
|
-
//
|
|
66
|
-
const
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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.
|
|
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.
|
|
74
|
+
"@blaxel/core": "0.2.18-dev.145"
|
|
75
75
|
},
|
|
76
76
|
"devDependencies": {
|
|
77
77
|
"@eslint/js": "^9.26.0",
|