@latitude-data/telemetry 3.0.0-alpha.0 → 3.0.0-alpha.2
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/README.md +415 -115
- package/dist/index.cjs +405 -325
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +142 -96
- package/dist/index.d.ts +142 -96
- package/dist/index.js +403 -314
- package/dist/index.js.map +1 -1
- package/package.json +10 -11
package/dist/index.js
CHANGED
|
@@ -1,3 +1,165 @@
|
|
|
1
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
+
}) : x)(function(x) {
|
|
4
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
5
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
// src/sdk/context.ts
|
|
9
|
+
import { context, createContextKey, trace } from "@opentelemetry/api";
|
|
10
|
+
var LATITUDE_CONTEXT_KEY = createContextKey("latitude-internal-context");
|
|
11
|
+
var CAPTURE_TRACER_NAME = "so.latitude.instrumentation.capture";
|
|
12
|
+
function getLatitudeContext(ctx) {
|
|
13
|
+
return ctx.getValue(LATITUDE_CONTEXT_KEY);
|
|
14
|
+
}
|
|
15
|
+
function mergeArrays(a, b) {
|
|
16
|
+
if (!a && !b) return void 0;
|
|
17
|
+
if (!a) return b;
|
|
18
|
+
if (!b) return a;
|
|
19
|
+
return [.../* @__PURE__ */ new Set([...a, ...b])];
|
|
20
|
+
}
|
|
21
|
+
function capture(name, fn, options = {}) {
|
|
22
|
+
const currentContext = context.active();
|
|
23
|
+
const existingData = getLatitudeContext(currentContext);
|
|
24
|
+
const mergedData = {
|
|
25
|
+
name: options.name ?? name,
|
|
26
|
+
tags: mergeArrays(existingData?.tags, options.tags),
|
|
27
|
+
metadata: { ...existingData?.metadata, ...options.metadata },
|
|
28
|
+
sessionId: options.sessionId ?? existingData?.sessionId,
|
|
29
|
+
userId: options.userId ?? existingData?.userId
|
|
30
|
+
};
|
|
31
|
+
const newContext = currentContext.setValue(LATITUDE_CONTEXT_KEY, mergedData);
|
|
32
|
+
const existingSpan = trace.getSpan(currentContext);
|
|
33
|
+
if (existingSpan) {
|
|
34
|
+
return context.with(newContext, fn);
|
|
35
|
+
}
|
|
36
|
+
const tracer = trace.getTracer(CAPTURE_TRACER_NAME);
|
|
37
|
+
return tracer.startActiveSpan(name, { attributes: { "latitude.capture.root": true } }, newContext, (span) => {
|
|
38
|
+
let result;
|
|
39
|
+
try {
|
|
40
|
+
result = fn();
|
|
41
|
+
} catch (error) {
|
|
42
|
+
span.recordException(error);
|
|
43
|
+
span.end();
|
|
44
|
+
throw error;
|
|
45
|
+
}
|
|
46
|
+
if (result instanceof Promise) {
|
|
47
|
+
return result.catch((error) => {
|
|
48
|
+
span.recordException(error);
|
|
49
|
+
throw error;
|
|
50
|
+
}).finally(() => {
|
|
51
|
+
span.end();
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
span.end();
|
|
55
|
+
return result;
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// src/sdk/init.ts
|
|
60
|
+
import { context as context2, propagation } from "@opentelemetry/api";
|
|
61
|
+
import { AsyncLocalStorageContextManager } from "@opentelemetry/context-async-hooks";
|
|
62
|
+
import { CompositePropagator, W3CBaggagePropagator, W3CTraceContextPropagator } from "@opentelemetry/core";
|
|
63
|
+
import { resourceFromAttributes } from "@opentelemetry/resources";
|
|
64
|
+
import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
|
|
65
|
+
import { ATTR_SERVICE_NAME } from "@opentelemetry/semantic-conventions";
|
|
66
|
+
|
|
67
|
+
// src/sdk/instrumentations.ts
|
|
68
|
+
import { registerInstrumentations } from "@opentelemetry/instrumentation";
|
|
69
|
+
import { AnthropicInstrumentation } from "@traceloop/instrumentation-anthropic";
|
|
70
|
+
import { BedrockInstrumentation } from "@traceloop/instrumentation-bedrock";
|
|
71
|
+
import { CohereInstrumentation } from "@traceloop/instrumentation-cohere";
|
|
72
|
+
import { LangChainInstrumentation } from "@traceloop/instrumentation-langchain";
|
|
73
|
+
import { LlamaIndexInstrumentation } from "@traceloop/instrumentation-llamaindex";
|
|
74
|
+
import { OpenAIInstrumentation } from "@traceloop/instrumentation-openai";
|
|
75
|
+
import { TogetherInstrumentation } from "@traceloop/instrumentation-together";
|
|
76
|
+
import { AIPlatformInstrumentation, VertexAIInstrumentation } from "@traceloop/instrumentation-vertexai";
|
|
77
|
+
var INSTRUMENTATION_MAP = {
|
|
78
|
+
openai: { ctor: OpenAIInstrumentation, moduleName: "openai", defaultEnrichTokens: true },
|
|
79
|
+
anthropic: { ctor: AnthropicInstrumentation, moduleName: "@anthropic-ai/sdk" },
|
|
80
|
+
bedrock: { ctor: BedrockInstrumentation, moduleName: "@aws-sdk/client-bedrock-runtime" },
|
|
81
|
+
cohere: { ctor: CohereInstrumentation, moduleName: "cohere-ai" },
|
|
82
|
+
langchain: { ctor: LangChainInstrumentation, moduleName: "langchain" },
|
|
83
|
+
llamaindex: { ctor: LlamaIndexInstrumentation, moduleName: "llamaindex" },
|
|
84
|
+
togetherai: { ctor: TogetherInstrumentation, moduleName: "together-ai", defaultEnrichTokens: false },
|
|
85
|
+
vertexai: { ctor: VertexAIInstrumentation, moduleName: "@google-cloud/vertexai" },
|
|
86
|
+
aiplatform: { ctor: AIPlatformInstrumentation, moduleName: "@google-cloud/aiplatform" }
|
|
87
|
+
};
|
|
88
|
+
async function createLatitudeInstrumentations(options) {
|
|
89
|
+
const result = [];
|
|
90
|
+
for (const type of options.instrumentations) {
|
|
91
|
+
const config = INSTRUMENTATION_MAP[type];
|
|
92
|
+
if (!config) {
|
|
93
|
+
console.warn(`[Latitude] Unknown instrumentation type: ${type}`);
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
const enrichTokens = options.enrichTokens?.[type] ?? config.defaultEnrichTokens;
|
|
97
|
+
const inst = new config.ctor(enrichTokens !== void 0 ? { enrichTokens } : void 0);
|
|
98
|
+
const moduleRef = options.modules?.[type] ?? await tryRequire(config.moduleName);
|
|
99
|
+
if (!moduleRef) {
|
|
100
|
+
console.warn(
|
|
101
|
+
`[Latitude] Module not found for ${type}: ${config.moduleName}. Install it or pass it explicitly in 'modules'.`
|
|
102
|
+
);
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
inst.manuallyInstrument?.(moduleRef);
|
|
106
|
+
result.push(inst);
|
|
107
|
+
}
|
|
108
|
+
return result;
|
|
109
|
+
}
|
|
110
|
+
async function tryRequire(moduleName) {
|
|
111
|
+
try {
|
|
112
|
+
return __require(moduleName);
|
|
113
|
+
} catch {
|
|
114
|
+
try {
|
|
115
|
+
const mod = await import(moduleName);
|
|
116
|
+
return mod.default ?? mod;
|
|
117
|
+
} catch {
|
|
118
|
+
return void 0;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
async function registerLatitudeInstrumentations(options) {
|
|
123
|
+
const instrumentations = await createLatitudeInstrumentations(options);
|
|
124
|
+
registerInstrumentations({
|
|
125
|
+
instrumentations,
|
|
126
|
+
tracerProvider: options.tracerProvider
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// src/sdk/processor.ts
|
|
131
|
+
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
|
|
132
|
+
import {
|
|
133
|
+
BatchSpanProcessor,
|
|
134
|
+
SimpleSpanProcessor
|
|
135
|
+
} from "@opentelemetry/sdk-trace-node";
|
|
136
|
+
|
|
137
|
+
// src/constants/attributes.ts
|
|
138
|
+
var ATTRIBUTES = {
|
|
139
|
+
name: "latitude.capture.name",
|
|
140
|
+
tags: "latitude.tags",
|
|
141
|
+
metadata: "latitude.metadata",
|
|
142
|
+
sessionId: "session.id",
|
|
143
|
+
userId: "user.id"
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
// src/constants/scope.ts
|
|
147
|
+
var SCOPE_LATITUDE = "so.latitude.instrumentation";
|
|
148
|
+
|
|
149
|
+
// src/env/env.ts
|
|
150
|
+
var DEFAULT_EXPORTER_URL = {
|
|
151
|
+
production: "https://ingest.latitude.so",
|
|
152
|
+
development: "http://localhost:3002",
|
|
153
|
+
test: "http://localhost:3002"
|
|
154
|
+
}[process.env.NODE_ENV ?? "development"] ?? "http://localhost:3002";
|
|
155
|
+
function getExporterUrl() {
|
|
156
|
+
if (process.env.LATITUDE_TELEMETRY_URL) {
|
|
157
|
+
return process.env.LATITUDE_TELEMETRY_URL;
|
|
158
|
+
}
|
|
159
|
+
return DEFAULT_EXPORTER_URL;
|
|
160
|
+
}
|
|
161
|
+
var env = { EXPORTER_URL: getExporterUrl() };
|
|
162
|
+
|
|
1
163
|
// src/sdk/redact.ts
|
|
2
164
|
var RedactSpanProcessor = class {
|
|
3
165
|
options;
|
|
@@ -48,349 +210,276 @@ var RedactSpanProcessor = class {
|
|
|
48
210
|
};
|
|
49
211
|
var DEFAULT_REDACT_SPAN_PROCESSOR = () => new RedactSpanProcessor({
|
|
50
212
|
attributes: [
|
|
213
|
+
// HTTP security headers
|
|
51
214
|
/^http\.request\.header\.authorization$/i,
|
|
52
215
|
/^http\.request\.header\.cookie$/i,
|
|
53
216
|
/^http\.request\.header\.x[-_]api[-_]key$/i,
|
|
217
|
+
// Database statements may contain sensitive data
|
|
54
218
|
/^db\.statement$/i
|
|
55
219
|
]
|
|
56
220
|
});
|
|
57
221
|
|
|
58
|
-
// src/sdk/
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
var SCOPE_LATITUDE = "so.latitude.instrumentation";
|
|
92
|
-
|
|
93
|
-
// src/env/env.ts
|
|
94
|
-
var DEFAULT_EXPORTER_URL = {
|
|
95
|
-
production: "https://ingest.latitude.so",
|
|
96
|
-
development: "http://localhost:3002",
|
|
97
|
-
test: "http://localhost:3002"
|
|
98
|
-
}[process.env.NODE_ENV ?? "development"] ?? "http://localhost:3002";
|
|
99
|
-
function getExporterUrl() {
|
|
100
|
-
if (process.env.LATITUDE_TELEMETRY_URL) {
|
|
101
|
-
return process.env.LATITUDE_TELEMETRY_URL;
|
|
102
|
-
}
|
|
103
|
-
return DEFAULT_EXPORTER_URL;
|
|
222
|
+
// src/sdk/span-filter.ts
|
|
223
|
+
var GEN_AI_PREFIX = "gen_ai.";
|
|
224
|
+
var LLM_PREFIX = "llm.";
|
|
225
|
+
var OPENINFERENCE_KIND = "openinference.span.kind";
|
|
226
|
+
var OTEL_LLM_INSTRUMENTATION_SCOPE_PREFIXES = [
|
|
227
|
+
"opentelemetry.instrumentation.alephalpha",
|
|
228
|
+
"opentelemetry.instrumentation.anthropic",
|
|
229
|
+
"opentelemetry.instrumentation.bedrock",
|
|
230
|
+
"opentelemetry.instrumentation.cohere",
|
|
231
|
+
"opentelemetry.instrumentation.crewai",
|
|
232
|
+
"opentelemetry.instrumentation.google_generativeai",
|
|
233
|
+
"opentelemetry.instrumentation.groq",
|
|
234
|
+
"opentelemetry.instrumentation.haystack",
|
|
235
|
+
"opentelemetry.instrumentation.langchain",
|
|
236
|
+
"opentelemetry.instrumentation.llamaindex",
|
|
237
|
+
"opentelemetry.instrumentation.mistralai",
|
|
238
|
+
"opentelemetry.instrumentation.ollama",
|
|
239
|
+
"opentelemetry.instrumentation.openai",
|
|
240
|
+
"opentelemetry.instrumentation.replicate",
|
|
241
|
+
"opentelemetry.instrumentation.sagemaker",
|
|
242
|
+
"opentelemetry.instrumentation.together",
|
|
243
|
+
"opentelemetry.instrumentation.transformers",
|
|
244
|
+
"opentelemetry.instrumentation.vertexai",
|
|
245
|
+
"opentelemetry.instrumentation.watsonx",
|
|
246
|
+
"openinference.instrumentation"
|
|
247
|
+
];
|
|
248
|
+
var LLM_SCOPE_SUBSTRINGS = ["openinference", "traceloop", "langsmith", "litellm"];
|
|
249
|
+
function buildShouldExportSpanFromFields(fields) {
|
|
250
|
+
return buildShouldExportSpan({
|
|
251
|
+
...fields.disableSmartFilter !== void 0 ? { disableSmartFilter: fields.disableSmartFilter } : {},
|
|
252
|
+
...fields.shouldExportSpan !== void 0 ? { shouldExportSpan: fields.shouldExportSpan } : {},
|
|
253
|
+
...fields.blockedInstrumentationScopes !== void 0 ? { blockedInstrumentationScopes: fields.blockedInstrumentationScopes } : {}
|
|
254
|
+
});
|
|
104
255
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
return
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
if (parts.length !== 4) {
|
|
132
|
-
return otel.ROOT_CONTEXT;
|
|
133
|
-
}
|
|
134
|
-
const [, traceId, spanId, flags] = parts;
|
|
135
|
-
if (!traceId || !spanId) {
|
|
136
|
-
return otel.ROOT_CONTEXT;
|
|
137
|
-
}
|
|
138
|
-
const spanContext = {
|
|
139
|
-
traceId,
|
|
140
|
-
spanId,
|
|
141
|
-
traceFlags: parseInt(flags ?? "01", 16),
|
|
142
|
-
isRemote: true
|
|
143
|
-
};
|
|
144
|
-
let context2 = trace.setSpanContext(otel.ROOT_CONTEXT, spanContext);
|
|
145
|
-
if (ctx.baggage) {
|
|
146
|
-
const baggageEntries = {};
|
|
147
|
-
for (const pair of ctx.baggage.split(",")) {
|
|
148
|
-
const [key, value] = pair.split("=", 2);
|
|
149
|
-
if (key && value) {
|
|
150
|
-
baggageEntries[decodeURIComponent(key)] = { value: decodeURIComponent(value) };
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
const baggage = propagation.createBaggage(baggageEntries);
|
|
154
|
-
context2 = propagation.setBaggage(context2, baggage);
|
|
155
|
-
}
|
|
156
|
-
return context2;
|
|
256
|
+
function attributeKeys(span) {
|
|
257
|
+
const attrs = span.attributes;
|
|
258
|
+
if (!attrs || typeof attrs !== "object") return [];
|
|
259
|
+
return Object.keys(attrs);
|
|
260
|
+
}
|
|
261
|
+
function instrumentationScopeName(span) {
|
|
262
|
+
return span.instrumentationScope?.name ?? "";
|
|
263
|
+
}
|
|
264
|
+
function isGenAiOrLlmAttributeSpan(span) {
|
|
265
|
+
for (const key of attributeKeys(span)) {
|
|
266
|
+
if (key.startsWith(GEN_AI_PREFIX) || key.startsWith(LLM_PREFIX)) return true;
|
|
267
|
+
if (key === OPENINFERENCE_KIND || key.startsWith("openinference.")) return true;
|
|
268
|
+
if (key.startsWith("ai.")) return true;
|
|
269
|
+
if (key.startsWith("latitude.")) return true;
|
|
270
|
+
}
|
|
271
|
+
return false;
|
|
272
|
+
}
|
|
273
|
+
function isLatitudeInstrumentationSpan(span) {
|
|
274
|
+
const name = instrumentationScopeName(span);
|
|
275
|
+
return name === SCOPE_LATITUDE || name.startsWith(`${SCOPE_LATITUDE}.`);
|
|
276
|
+
}
|
|
277
|
+
function isKnownLlmInstrumentationScope(span) {
|
|
278
|
+
const name = instrumentationScopeName(span);
|
|
279
|
+
if (!name) return false;
|
|
280
|
+
for (const prefix of OTEL_LLM_INSTRUMENTATION_SCOPE_PREFIXES) {
|
|
281
|
+
if (name === prefix || name.startsWith(`${prefix}.`)) return true;
|
|
157
282
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
var TRACES_URL = `${env.EXPORTER_URL}/v1/traces`;
|
|
162
|
-
var SERVICE_NAME = process.env.npm_package_name || "unknown";
|
|
163
|
-
var SCOPE_VERSION = process.env.npm_package_version || "unknown";
|
|
164
|
-
var ContextManager = class {
|
|
165
|
-
telemetry;
|
|
166
|
-
constructor(telemetry) {
|
|
167
|
-
this.telemetry = telemetry;
|
|
283
|
+
const lower = name.toLowerCase();
|
|
284
|
+
for (const part of LLM_SCOPE_SUBSTRINGS) {
|
|
285
|
+
if (lower.includes(part)) return true;
|
|
168
286
|
}
|
|
169
|
-
|
|
170
|
-
|
|
287
|
+
return false;
|
|
288
|
+
}
|
|
289
|
+
function isDefaultExportSpan(span) {
|
|
290
|
+
if (isLatitudeInstrumentationSpan(span)) return true;
|
|
291
|
+
if (isGenAiOrLlmAttributeSpan(span)) return true;
|
|
292
|
+
if (isKnownLlmInstrumentationScope(span)) return true;
|
|
293
|
+
return false;
|
|
294
|
+
}
|
|
295
|
+
function buildShouldExportSpan(options) {
|
|
296
|
+
if (options.disableSmartFilter) return () => true;
|
|
297
|
+
const blocked = new Set(options.blockedInstrumentationScopes ?? []);
|
|
298
|
+
const extra = options.shouldExportSpan;
|
|
299
|
+
return (span) => {
|
|
300
|
+
const scope = instrumentationScopeName(span);
|
|
301
|
+
if (blocked.has(scope)) return false;
|
|
302
|
+
if (isDefaultExportSpan(span)) return true;
|
|
303
|
+
if (extra?.(span)) return true;
|
|
304
|
+
return false;
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
var ExportFilterSpanProcessor = class {
|
|
308
|
+
shouldExport;
|
|
309
|
+
inner;
|
|
310
|
+
constructor(shouldExport, inner) {
|
|
311
|
+
this.shouldExport = shouldExport;
|
|
312
|
+
this.inner = inner;
|
|
171
313
|
}
|
|
172
|
-
|
|
173
|
-
|
|
314
|
+
onStart(span, parentContext) {
|
|
315
|
+
this.inner.onStart(span, parentContext);
|
|
174
316
|
}
|
|
175
|
-
|
|
176
|
-
|
|
317
|
+
onEnd(span) {
|
|
318
|
+
if (!this.shouldExport(span)) return;
|
|
319
|
+
this.inner.onEnd(span);
|
|
177
320
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
instrumentations;
|
|
181
|
-
constructor(instrumentations) {
|
|
182
|
-
this.instrumentations = instrumentations;
|
|
183
|
-
}
|
|
184
|
-
enable() {
|
|
185
|
-
for (const instrumentation of this.instrumentations) {
|
|
186
|
-
if (!instrumentation.isEnabled()) instrumentation.enable();
|
|
187
|
-
}
|
|
321
|
+
forceFlush() {
|
|
322
|
+
return this.inner.forceFlush();
|
|
188
323
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
if (instrumentation.isEnabled()) instrumentation.disable();
|
|
192
|
-
}
|
|
324
|
+
shutdown() {
|
|
325
|
+
return this.inner.shutdown();
|
|
193
326
|
}
|
|
194
327
|
};
|
|
195
|
-
var
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
constructor(
|
|
199
|
-
this.
|
|
200
|
-
this.
|
|
328
|
+
var RedactThenExportSpanProcessor = class {
|
|
329
|
+
redact;
|
|
330
|
+
exportProcessor;
|
|
331
|
+
constructor(redact, exportProcessor) {
|
|
332
|
+
this.redact = redact;
|
|
333
|
+
this.exportProcessor = exportProcessor;
|
|
201
334
|
}
|
|
202
|
-
|
|
203
|
-
|
|
335
|
+
onStart(span, parentContext) {
|
|
336
|
+
this.redact?.onStart(span, parentContext);
|
|
337
|
+
this.exportProcessor.onStart(span, parentContext);
|
|
204
338
|
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
};
|
|
209
|
-
var ScopedTracerProvider = class {
|
|
210
|
-
scope;
|
|
211
|
-
version;
|
|
212
|
-
provider;
|
|
213
|
-
constructor(scope, version, provider) {
|
|
214
|
-
this.scope = scope;
|
|
215
|
-
this.version = version;
|
|
216
|
-
this.provider = provider;
|
|
217
|
-
}
|
|
218
|
-
getTracer(_name, _version, options) {
|
|
219
|
-
return this.provider.getTracer(this.scope, this.version, options);
|
|
220
|
-
}
|
|
221
|
-
};
|
|
222
|
-
var LifecycleManager = class {
|
|
223
|
-
nodeProvider;
|
|
224
|
-
exporter;
|
|
225
|
-
constructor(nodeProvider, exporter) {
|
|
226
|
-
this.nodeProvider = nodeProvider;
|
|
227
|
-
this.exporter = exporter;
|
|
339
|
+
onEnd(span) {
|
|
340
|
+
this.redact?.onEnd(span);
|
|
341
|
+
this.exportProcessor.onEnd(span);
|
|
228
342
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
await this.exporter.forceFlush?.();
|
|
343
|
+
forceFlush() {
|
|
344
|
+
return this.exportProcessor.forceFlush();
|
|
232
345
|
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
await this.nodeProvider.shutdown();
|
|
236
|
-
await this.exporter.shutdown?.();
|
|
346
|
+
shutdown() {
|
|
347
|
+
return this.exportProcessor.shutdown();
|
|
237
348
|
}
|
|
238
349
|
};
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
"Content-Type": "application/json",
|
|
244
|
-
"X-Latitude-Project": projectSlug
|
|
245
|
-
},
|
|
246
|
-
timeoutMillis: 30 * 1e3
|
|
247
|
-
});
|
|
248
|
-
var Instrumentation = /* @__PURE__ */ ((Instrumentation2) => {
|
|
249
|
-
Instrumentation2["Anthropic"] = "anthropic";
|
|
250
|
-
Instrumentation2["AIPlatform"] = "aiplatform";
|
|
251
|
-
Instrumentation2["Bedrock"] = "bedrock";
|
|
252
|
-
Instrumentation2["Cohere"] = "cohere";
|
|
253
|
-
Instrumentation2["Langchain"] = "langchain";
|
|
254
|
-
Instrumentation2["LlamaIndex"] = "llamaindex";
|
|
255
|
-
Instrumentation2["Manual"] = "manual";
|
|
256
|
-
Instrumentation2["OpenAI"] = "openai";
|
|
257
|
-
Instrumentation2["TogetherAI"] = "togetherai";
|
|
258
|
-
Instrumentation2["VertexAI"] = "vertexai";
|
|
259
|
-
return Instrumentation2;
|
|
260
|
-
})(Instrumentation || {});
|
|
261
|
-
var LatitudeTelemetry = class {
|
|
262
|
-
options;
|
|
263
|
-
nodeProvider;
|
|
264
|
-
instrumentationsList;
|
|
265
|
-
/** OpenTelemetry tracer for creating custom spans. */
|
|
266
|
-
tracer;
|
|
267
|
-
context;
|
|
268
|
-
instrumentation;
|
|
269
|
-
lifecycle;
|
|
350
|
+
|
|
351
|
+
// src/sdk/processor.ts
|
|
352
|
+
var LatitudeSpanProcessor = class {
|
|
353
|
+
tail;
|
|
270
354
|
constructor(apiKey, projectSlug, options) {
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
this.options.exporter = DEFAULT_SPAN_EXPORTER(apiKey, projectSlug);
|
|
274
|
-
}
|
|
275
|
-
context.setGlobalContextManager(new AsyncLocalStorageContextManager().enable());
|
|
276
|
-
propagation2.setGlobalPropagator(
|
|
277
|
-
new CompositePropagator({
|
|
278
|
-
propagators: [...this.options.propagators || [], new W3CTraceContextPropagator(), new W3CBaggagePropagator()]
|
|
279
|
-
})
|
|
280
|
-
);
|
|
281
|
-
const spanProcessors = [
|
|
282
|
-
// Must run before the exporter span processors
|
|
283
|
-
new BaggageSpanProcessor(ALLOW_ALL_BAGGAGE_KEYS),
|
|
284
|
-
...this.options.processors ?? [DEFAULT_REDACT_SPAN_PROCESSOR()],
|
|
285
|
-
this.options.disableBatch ? new SimpleSpanProcessor(this.options.exporter) : new BatchSpanProcessor(this.options.exporter)
|
|
286
|
-
];
|
|
287
|
-
this.nodeProvider = new NodeTracerProvider({
|
|
288
|
-
resource: new Resource({ [ATTR_SERVICE_NAME]: this.options.serviceName || SERVICE_NAME }),
|
|
289
|
-
spanProcessors
|
|
290
|
-
});
|
|
291
|
-
this.lifecycle = new LifecycleManager(this.nodeProvider, this.options.exporter);
|
|
292
|
-
this.nodeProvider.register();
|
|
293
|
-
process.on("SIGTERM", () => this.shutdown());
|
|
294
|
-
process.on("SIGINT", () => this.shutdown());
|
|
295
|
-
this.instrumentationsList = [];
|
|
296
|
-
const tracerManager = new TracerManager(this.nodeProvider, SCOPE_VERSION);
|
|
297
|
-
const manualTracer = tracerManager.get("manual" /* Manual */);
|
|
298
|
-
const manualInstrumentation = new ManualInstrumentation(manualTracer);
|
|
299
|
-
this.instrumentationsList.push(manualInstrumentation);
|
|
300
|
-
this.tracer = manualTracer;
|
|
301
|
-
this.initProviderInstrumentations(tracerManager);
|
|
302
|
-
this.instrumentation = new InstrumentationManager(this.instrumentationsList);
|
|
303
|
-
this.instrumentation.enable();
|
|
304
|
-
this.context = new ContextManager(manualInstrumentation);
|
|
305
|
-
}
|
|
306
|
-
async flush() {
|
|
307
|
-
await this.lifecycle.flush();
|
|
308
|
-
}
|
|
309
|
-
async shutdown() {
|
|
310
|
-
await this.lifecycle.shutdown();
|
|
311
|
-
}
|
|
312
|
-
initProviderInstrumentations(tracerManager) {
|
|
313
|
-
const configure = (type, Ctor, opts) => {
|
|
314
|
-
const providerPkg = this.options.instrumentations?.[type];
|
|
315
|
-
if (!providerPkg) return;
|
|
316
|
-
const provider = tracerManager.provider(type);
|
|
317
|
-
const inst = new Ctor(opts);
|
|
318
|
-
inst.setTracerProvider(provider);
|
|
319
|
-
inst.manuallyInstrument(providerPkg);
|
|
320
|
-
registerInstrumentations({
|
|
321
|
-
instrumentations: [inst],
|
|
322
|
-
tracerProvider: provider
|
|
323
|
-
});
|
|
324
|
-
this.instrumentationsList.push(inst);
|
|
325
|
-
};
|
|
326
|
-
configure("anthropic" /* Anthropic */, AnthropicInstrumentation);
|
|
327
|
-
configure("aiplatform" /* AIPlatform */, AIPlatformInstrumentation);
|
|
328
|
-
configure("bedrock" /* Bedrock */, BedrockInstrumentation);
|
|
329
|
-
configure("cohere" /* Cohere */, CohereInstrumentation);
|
|
330
|
-
configure("langchain" /* Langchain */, LangChainInstrumentation);
|
|
331
|
-
configure("llamaindex" /* LlamaIndex */, LlamaIndexInstrumentation);
|
|
332
|
-
configure("openai" /* OpenAI */, OpenAIInstrumentation, { enrichTokens: true });
|
|
333
|
-
configure("togetherai" /* TogetherAI */, TogetherInstrumentation, { enrichTokens: false });
|
|
334
|
-
configure("vertexai" /* VertexAI */, VertexAIInstrumentation);
|
|
335
|
-
}
|
|
336
|
-
/**
|
|
337
|
-
* Wrap a block of code with trace-wide context attributes.
|
|
338
|
-
* Baggage entries (tags, metadata, sessionId, userId) are propagated
|
|
339
|
-
* to all spans created within the callback via BaggageSpanProcessor.
|
|
340
|
-
*
|
|
341
|
-
* If there is no active span, a root span is created so all child spans
|
|
342
|
-
* are grouped under a single trace. If a span is already active, only
|
|
343
|
-
* baggage is set without creating an extra wrapper span.
|
|
344
|
-
*/
|
|
345
|
-
async capture(options, fn) {
|
|
346
|
-
const baggageEntries = {};
|
|
347
|
-
if (options.tags?.length) {
|
|
348
|
-
baggageEntries[ATTRIBUTES.tags] = { value: JSON.stringify(options.tags) };
|
|
349
|
-
}
|
|
350
|
-
if (options.metadata) {
|
|
351
|
-
baggageEntries[ATTRIBUTES.metadata] = { value: JSON.stringify(options.metadata) };
|
|
352
|
-
}
|
|
353
|
-
if (options.sessionId) {
|
|
354
|
-
baggageEntries[ATTRIBUTES.sessionId] = { value: options.sessionId };
|
|
355
|
+
if (!apiKey || apiKey.trim() === "") {
|
|
356
|
+
throw new Error("[Latitude] apiKey is required and cannot be empty");
|
|
355
357
|
}
|
|
356
|
-
if (
|
|
357
|
-
|
|
358
|
+
if (!projectSlug || projectSlug.trim() === "") {
|
|
359
|
+
throw new Error("[Latitude] projectSlug is required and cannot be empty");
|
|
358
360
|
}
|
|
359
|
-
const
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
361
|
+
const exporter = options?.exporter ?? new OTLPTraceExporter({
|
|
362
|
+
url: `${env.EXPORTER_URL}/v1/traces`,
|
|
363
|
+
headers: {
|
|
364
|
+
Authorization: `Bearer ${apiKey}`,
|
|
365
|
+
"Content-Type": "application/json",
|
|
366
|
+
"X-Latitude-Project": projectSlug
|
|
367
|
+
},
|
|
368
|
+
timeoutMillis: 3e4
|
|
369
|
+
});
|
|
370
|
+
const redact = options?.disableRedact ? null : options?.redact ? new RedactSpanProcessor(options.redact) : DEFAULT_REDACT_SPAN_PROCESSOR();
|
|
371
|
+
const batchOrSimple = options?.disableBatch ? new SimpleSpanProcessor(exporter) : new BatchSpanProcessor(exporter);
|
|
372
|
+
const shouldExport = buildShouldExportSpanFromFields({
|
|
373
|
+
disableSmartFilter: options?.disableSmartFilter,
|
|
374
|
+
shouldExportSpan: options?.shouldExportSpan,
|
|
375
|
+
blockedInstrumentationScopes: options?.blockedInstrumentationScopes
|
|
376
|
+
});
|
|
377
|
+
const redactThenExport = new RedactThenExportSpanProcessor(redact, batchOrSimple);
|
|
378
|
+
this.tail = new ExportFilterSpanProcessor(shouldExport, redactThenExport);
|
|
379
|
+
}
|
|
380
|
+
onStart(span, parentContext) {
|
|
381
|
+
const latitudeData = getLatitudeContext(parentContext);
|
|
382
|
+
if (latitudeData) {
|
|
383
|
+
if (latitudeData.name) {
|
|
384
|
+
span.setAttribute(ATTRIBUTES.name, latitudeData.name);
|
|
385
|
+
if (span.attributes["latitude.capture.root"]) {
|
|
386
|
+
span.updateName(latitudeData.name);
|
|
384
387
|
}
|
|
385
388
|
}
|
|
386
|
-
|
|
389
|
+
if (latitudeData.tags && latitudeData.tags.length > 0) {
|
|
390
|
+
span.setAttribute(ATTRIBUTES.tags, JSON.stringify(latitudeData.tags));
|
|
391
|
+
}
|
|
392
|
+
if (latitudeData.metadata && Object.keys(latitudeData.metadata).length > 0) {
|
|
393
|
+
span.setAttribute(ATTRIBUTES.metadata, JSON.stringify(latitudeData.metadata));
|
|
394
|
+
}
|
|
395
|
+
if (latitudeData.sessionId) {
|
|
396
|
+
span.setAttribute(ATTRIBUTES.sessionId, latitudeData.sessionId);
|
|
397
|
+
}
|
|
398
|
+
if (latitudeData.userId) {
|
|
399
|
+
span.setAttribute(ATTRIBUTES.userId, latitudeData.userId);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
this.tail.onStart(span, parentContext);
|
|
403
|
+
}
|
|
404
|
+
onEnd(span) {
|
|
405
|
+
this.tail.onEnd(span);
|
|
406
|
+
}
|
|
407
|
+
async forceFlush() {
|
|
408
|
+
await this.tail.forceFlush();
|
|
409
|
+
}
|
|
410
|
+
async shutdown() {
|
|
411
|
+
await this.tail.shutdown();
|
|
387
412
|
}
|
|
388
413
|
};
|
|
414
|
+
|
|
415
|
+
// src/sdk/init.ts
|
|
416
|
+
var SERVICE_NAME = process.env.npm_package_name || "unknown";
|
|
417
|
+
var shutdownHandlersRegistered = false;
|
|
418
|
+
function initLatitude(options) {
|
|
419
|
+
const { apiKey, projectSlug, instrumentations = [], ...processorOptions } = options;
|
|
420
|
+
if (!apiKey || apiKey.trim() === "") {
|
|
421
|
+
throw new Error("[Latitude] apiKey is required and cannot be empty");
|
|
422
|
+
}
|
|
423
|
+
if (!projectSlug || projectSlug.trim() === "") {
|
|
424
|
+
throw new Error("[Latitude] projectSlug is required and cannot be empty");
|
|
425
|
+
}
|
|
426
|
+
const contextManager = new AsyncLocalStorageContextManager();
|
|
427
|
+
contextManager.enable();
|
|
428
|
+
const propagator = new CompositePropagator({
|
|
429
|
+
propagators: [new W3CTraceContextPropagator(), new W3CBaggagePropagator()]
|
|
430
|
+
});
|
|
431
|
+
context2.setGlobalContextManager(contextManager);
|
|
432
|
+
propagation.setGlobalPropagator(propagator);
|
|
433
|
+
const provider = new NodeTracerProvider({
|
|
434
|
+
resource: resourceFromAttributes({
|
|
435
|
+
[ATTR_SERVICE_NAME]: SERVICE_NAME
|
|
436
|
+
}),
|
|
437
|
+
spanProcessors: [new LatitudeSpanProcessor(apiKey, projectSlug, processorOptions)]
|
|
438
|
+
});
|
|
439
|
+
provider.register();
|
|
440
|
+
const ready = registerLatitudeInstrumentations({
|
|
441
|
+
instrumentations,
|
|
442
|
+
tracerProvider: provider
|
|
443
|
+
}).catch((err) => {
|
|
444
|
+
console.warn("[Latitude] Failed to register instrumentations:", err);
|
|
445
|
+
});
|
|
446
|
+
const shutdown = async () => {
|
|
447
|
+
await provider.shutdown();
|
|
448
|
+
};
|
|
449
|
+
const flush = async () => {
|
|
450
|
+
await provider.forceFlush();
|
|
451
|
+
};
|
|
452
|
+
const handleShutdown = async () => {
|
|
453
|
+
try {
|
|
454
|
+
await shutdown();
|
|
455
|
+
} catch (err) {
|
|
456
|
+
console.error("Error during Latitude Telemetry shutdown:", err);
|
|
457
|
+
}
|
|
458
|
+
};
|
|
459
|
+
if (!shutdownHandlersRegistered) {
|
|
460
|
+
process.once("SIGTERM", handleShutdown);
|
|
461
|
+
process.once("SIGINT", handleShutdown);
|
|
462
|
+
shutdownHandlersRegistered = true;
|
|
463
|
+
}
|
|
464
|
+
return {
|
|
465
|
+
provider,
|
|
466
|
+
flush,
|
|
467
|
+
shutdown,
|
|
468
|
+
ready
|
|
469
|
+
};
|
|
470
|
+
}
|
|
389
471
|
export {
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
472
|
+
ExportFilterSpanProcessor,
|
|
473
|
+
LatitudeSpanProcessor,
|
|
474
|
+
RedactSpanProcessor,
|
|
475
|
+
RedactThenExportSpanProcessor,
|
|
476
|
+
buildShouldExportSpan,
|
|
477
|
+
buildShouldExportSpanFromFields,
|
|
478
|
+
capture,
|
|
479
|
+
initLatitude,
|
|
480
|
+
isDefaultExportSpan,
|
|
481
|
+
isGenAiOrLlmAttributeSpan,
|
|
482
|
+
isLatitudeInstrumentationSpan,
|
|
483
|
+
registerLatitudeInstrumentations
|
|
395
484
|
};
|
|
396
485
|
//# sourceMappingURL=index.js.map
|