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