@blaxel/telemetry 0.2.18-dev.142 → 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 +45 -43
- 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
|
@@ -192,67 +192,72 @@ class TelemetryManager {
|
|
|
192
192
|
});
|
|
193
193
|
}
|
|
194
194
|
instrumentApp() {
|
|
195
|
-
// Setup telemetry provider first
|
|
196
195
|
core_1.telemetryRegistry.registerProvider(new telemetry_provider_1.OtelTelemetryProvider());
|
|
197
|
-
// Setup TracerProvider and other providers BEFORE instrumentation
|
|
198
|
-
this.setupProviders();
|
|
199
196
|
const httpInstrumentation = new instrumentation_http_1.HttpInstrumentation({
|
|
200
|
-
requireParentforOutgoingSpans:
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
const
|
|
206
|
-
if (
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
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,
|
|
211
209
|
});
|
|
212
210
|
}
|
|
213
211
|
else {
|
|
214
|
-
|
|
212
|
+
core_1.logger.debug("Incoming request without traceparent header", {
|
|
213
|
+
url: request.url,
|
|
214
|
+
method: request.method,
|
|
215
|
+
headers: Object.keys(headers || {}),
|
|
216
|
+
});
|
|
215
217
|
}
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
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) : [],
|
|
220
246
|
});
|
|
221
|
-
console.log("=== END HTTP INSTRUMENTATION REQUEST HOOK ===");
|
|
222
247
|
},
|
|
223
248
|
});
|
|
224
249
|
(0, instrumentation_1.registerInstrumentations)({
|
|
225
250
|
instrumentations: [httpInstrumentation],
|
|
226
251
|
});
|
|
227
252
|
}
|
|
228
|
-
setupProviders() {
|
|
229
|
-
const resource = new BlaxelResource(this.resourceAttributes);
|
|
230
|
-
// Setup TracerProvider first - this is critical for context propagation
|
|
231
|
-
this.nodeTracerProvider = new sdk_trace_node_1.NodeTracerProvider({
|
|
232
|
-
resource,
|
|
233
|
-
sampler: new sdk_trace_node_1.AlwaysOnSampler(),
|
|
234
|
-
spanProcessors: [
|
|
235
|
-
new DefaultAttributesSpanProcessor({
|
|
236
|
-
"workload.id": core_1.settings.name || "",
|
|
237
|
-
"workload.type": core_1.settings.type ? core_1.settings.type + "s" : "",
|
|
238
|
-
workspace: core_1.settings.workspace || "",
|
|
239
|
-
}),
|
|
240
|
-
],
|
|
241
|
-
});
|
|
242
|
-
// Register the tracer provider BEFORE any instrumentation
|
|
243
|
-
this.nodeTracerProvider.register();
|
|
244
|
-
console.log("TracerProvider registered - ready for context propagation");
|
|
245
|
-
}
|
|
246
253
|
setExporters() {
|
|
247
254
|
const resource = new BlaxelResource(this.resourceAttributes);
|
|
248
|
-
// Setup logging
|
|
249
255
|
const logExporter = this.getLogExporter();
|
|
250
256
|
this.loggerProvider = new sdk_logs_1.LoggerProvider({
|
|
251
257
|
resource,
|
|
252
258
|
});
|
|
253
259
|
this.loggerProvider.addLogRecordProcessor(new sdk_logs_1.BatchLogRecordProcessor(logExporter));
|
|
254
260
|
api_logs_1.logs.setGlobalLoggerProvider(this.loggerProvider);
|
|
255
|
-
// Recreate TracerProvider with exporters - this ensures proper initialization
|
|
256
261
|
const traceExporter = this.getTraceExporter();
|
|
257
262
|
this.nodeTracerProvider = new sdk_trace_node_1.NodeTracerProvider({
|
|
258
263
|
resource,
|
|
@@ -267,10 +272,7 @@ class TelemetryManager {
|
|
|
267
272
|
new HasBeenProcessedSpanProcessor(traceExporter),
|
|
268
273
|
],
|
|
269
274
|
});
|
|
270
|
-
// Re-register the tracer provider with exporters
|
|
271
275
|
this.nodeTracerProvider.register();
|
|
272
|
-
console.log("TracerProvider re-registered with exporters");
|
|
273
|
-
// Setup metrics
|
|
274
276
|
const metricExporter = this.getMetricExporter();
|
|
275
277
|
this.meterProvider = new sdk_metrics_1.MeterProvider({
|
|
276
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",
|