@latitude-data/telemetry 3.0.0-alpha.1 → 3.0.0-alpha.3
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/index.cjs +12 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +13 -5
- package/dist/index.js.map +1 -1
- package/package.json +9 -9
package/dist/index.cjs
CHANGED
|
@@ -92,7 +92,7 @@ var import_context_async_hooks = require("@opentelemetry/context-async-hooks");
|
|
|
92
92
|
var import_core = require("@opentelemetry/core");
|
|
93
93
|
var import_resources = require("@opentelemetry/resources");
|
|
94
94
|
var import_sdk_trace_node2 = require("@opentelemetry/sdk-trace-node");
|
|
95
|
-
var
|
|
95
|
+
var import_semantic_conventions2 = require("@opentelemetry/semantic-conventions");
|
|
96
96
|
|
|
97
97
|
// src/sdk/instrumentations.ts
|
|
98
98
|
var import_instrumentation = require("@opentelemetry/instrumentation");
|
|
@@ -160,6 +160,7 @@ async function registerLatitudeInstrumentations(options) {
|
|
|
160
160
|
// src/sdk/processor.ts
|
|
161
161
|
var import_exporter_trace_otlp_http = require("@opentelemetry/exporter-trace-otlp-http");
|
|
162
162
|
var import_sdk_trace_node = require("@opentelemetry/sdk-trace-node");
|
|
163
|
+
var import_semantic_conventions = require("@opentelemetry/semantic-conventions");
|
|
163
164
|
|
|
164
165
|
// src/constants/attributes.ts
|
|
165
166
|
var ATTRIBUTES = {
|
|
@@ -286,7 +287,7 @@ function attributeKeys(span) {
|
|
|
286
287
|
return Object.keys(attrs);
|
|
287
288
|
}
|
|
288
289
|
function instrumentationScopeName(span) {
|
|
289
|
-
return span.
|
|
290
|
+
return span.instrumentationScope?.name ?? "";
|
|
290
291
|
}
|
|
291
292
|
function isGenAiOrLlmAttributeSpan(span) {
|
|
292
293
|
for (const key of attributeKeys(span)) {
|
|
@@ -378,6 +379,7 @@ var RedactThenExportSpanProcessor = class {
|
|
|
378
379
|
// src/sdk/processor.ts
|
|
379
380
|
var LatitudeSpanProcessor = class {
|
|
380
381
|
tail;
|
|
382
|
+
serviceName;
|
|
381
383
|
constructor(apiKey, projectSlug, options) {
|
|
382
384
|
if (!apiKey || apiKey.trim() === "") {
|
|
383
385
|
throw new Error("[Latitude] apiKey is required and cannot be empty");
|
|
@@ -403,8 +405,13 @@ var LatitudeSpanProcessor = class {
|
|
|
403
405
|
});
|
|
404
406
|
const redactThenExport = new RedactThenExportSpanProcessor(redact, batchOrSimple);
|
|
405
407
|
this.tail = new ExportFilterSpanProcessor(shouldExport, redactThenExport);
|
|
408
|
+
const rawServiceName = options?.serviceName?.trim();
|
|
409
|
+
this.serviceName = rawServiceName === "" ? void 0 : rawServiceName;
|
|
406
410
|
}
|
|
407
411
|
onStart(span, parentContext) {
|
|
412
|
+
if (this.serviceName !== void 0) {
|
|
413
|
+
span.setAttribute(import_semantic_conventions.ATTR_SERVICE_NAME, this.serviceName);
|
|
414
|
+
}
|
|
408
415
|
const latitudeData = getLatitudeContext(parentContext);
|
|
409
416
|
if (latitudeData) {
|
|
410
417
|
if (latitudeData.name) {
|
|
@@ -457,9 +464,10 @@ function initLatitude(options) {
|
|
|
457
464
|
});
|
|
458
465
|
import_api2.context.setGlobalContextManager(contextManager);
|
|
459
466
|
import_api2.propagation.setGlobalPropagator(propagator);
|
|
467
|
+
const resourceServiceName = typeof processorOptions.serviceName === "string" && processorOptions.serviceName.trim() !== "" ? processorOptions.serviceName.trim() : SERVICE_NAME;
|
|
460
468
|
const provider = new import_sdk_trace_node2.NodeTracerProvider({
|
|
461
|
-
resource:
|
|
462
|
-
[
|
|
469
|
+
resource: (0, import_resources.resourceFromAttributes)({
|
|
470
|
+
[import_semantic_conventions2.ATTR_SERVICE_NAME]: resourceServiceName
|
|
463
471
|
}),
|
|
464
472
|
spanProcessors: [new LatitudeSpanProcessor(apiKey, projectSlug, processorOptions)]
|
|
465
473
|
});
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/sdk/context.ts","../src/sdk/init.ts","../src/sdk/instrumentations.ts","../src/sdk/processor.ts","../src/constants/attributes.ts","../src/constants/scope.ts","../src/env/env.ts","../src/sdk/redact.ts","../src/sdk/span-filter.ts"],"sourcesContent":["export * from \"./sdk/index.ts\"\n","import { type Context, context, createContextKey, trace } from \"@opentelemetry/api\"\nimport type { ContextOptions } from \"./types.ts\"\n\nexport const LATITUDE_CONTEXT_KEY = createContextKey(\"latitude-internal-context\")\nconst CAPTURE_TRACER_NAME = \"so.latitude.instrumentation.capture\"\n\ntype LatitudeContextData = {\n name: string | undefined\n tags: string[] | undefined\n metadata: Record<string, unknown> | undefined\n sessionId: string | undefined\n userId: string | undefined\n}\n\nexport function getLatitudeContext(ctx: Context): LatitudeContextData | undefined {\n return ctx.getValue(LATITUDE_CONTEXT_KEY) as LatitudeContextData | undefined\n}\n\nfunction mergeArrays<T>(a: T[] | undefined, b: T[] | undefined): T[] | undefined {\n if (!a && !b) return undefined\n if (!a) return b\n if (!b) return a\n return [...new Set([...a, ...b])]\n}\n\nexport function capture<T>(name: string, fn: () => T | Promise<T>, options: ContextOptions = {}): T | Promise<T> {\n const currentContext = context.active()\n const existingData = getLatitudeContext(currentContext)\n\n const mergedData: LatitudeContextData = {\n name: options.name ?? name,\n tags: mergeArrays(existingData?.tags, options.tags),\n metadata: { ...existingData?.metadata, ...options.metadata },\n sessionId: options.sessionId ?? existingData?.sessionId,\n userId: options.userId ?? existingData?.userId,\n }\n\n const newContext = currentContext.setValue(LATITUDE_CONTEXT_KEY, mergedData)\n const existingSpan = trace.getSpan(currentContext)\n\n if (existingSpan) {\n return context.with(newContext, fn)\n }\n\n const tracer = trace.getTracer(CAPTURE_TRACER_NAME)\n\n return tracer.startActiveSpan(name, { attributes: { \"latitude.capture.root\": true } }, newContext, (span) => {\n let result: T | Promise<T>\n try {\n result = fn()\n } catch (error) {\n span.recordException(error as Error)\n span.end()\n throw error\n }\n\n if (result instanceof Promise) {\n return result\n .catch((error) => {\n span.recordException(error as Error)\n throw error\n })\n .finally(() => {\n span.end()\n }) as T | Promise<T>\n }\n\n span.end()\n return result\n })\n}\n","import { context, propagation } from \"@opentelemetry/api\"\nimport { AsyncLocalStorageContextManager } from \"@opentelemetry/context-async-hooks\"\nimport { CompositePropagator, W3CBaggagePropagator, W3CTraceContextPropagator } from \"@opentelemetry/core\"\nimport { Resource } from \"@opentelemetry/resources\"\nimport { NodeTracerProvider } from \"@opentelemetry/sdk-trace-node\"\nimport { ATTR_SERVICE_NAME } from \"@opentelemetry/semantic-conventions\"\nimport { registerLatitudeInstrumentations } from \"./instrumentations.ts\"\nimport { LatitudeSpanProcessor } from \"./processor.ts\"\nimport type { InitLatitudeOptions } from \"./types.ts\"\n\nconst SERVICE_NAME = process.env.npm_package_name || \"unknown\"\n\n/** Module-level flag to prevent duplicate signal handler registration on repeated initLatitude calls */\nlet shutdownHandlersRegistered = false\n\nexport function initLatitude(options: InitLatitudeOptions): {\n provider: NodeTracerProvider\n flush: () => Promise<void>\n shutdown: () => Promise<void>\n ready: Promise<void>\n} {\n const { apiKey, projectSlug, instrumentations = [], ...processorOptions } = options\n\n if (!apiKey || apiKey.trim() === \"\") {\n throw new Error(\"[Latitude] apiKey is required and cannot be empty\")\n }\n if (!projectSlug || projectSlug.trim() === \"\") {\n throw new Error(\"[Latitude] projectSlug is required and cannot be empty\")\n }\n\n const contextManager = new AsyncLocalStorageContextManager()\n contextManager.enable()\n\n const propagator = new CompositePropagator({\n propagators: [new W3CTraceContextPropagator(), new W3CBaggagePropagator()],\n })\n\n context.setGlobalContextManager(contextManager)\n propagation.setGlobalPropagator(propagator)\n\n const provider = new NodeTracerProvider({\n resource: new Resource({\n [ATTR_SERVICE_NAME]: SERVICE_NAME,\n }),\n spanProcessors: [new LatitudeSpanProcessor(apiKey, projectSlug, processorOptions)],\n })\n\n provider.register()\n\n const ready = registerLatitudeInstrumentations({\n instrumentations,\n tracerProvider: provider,\n }).catch((err) => {\n console.warn(\"[Latitude] Failed to register instrumentations:\", err)\n })\n\n const shutdown = async (): Promise<void> => {\n await provider.shutdown()\n }\n\n const flush = async (): Promise<void> => {\n await provider.forceFlush()\n }\n\n const handleShutdown = async () => {\n try {\n await shutdown()\n } catch (err) {\n console.error(\"Error during Latitude Telemetry shutdown:\", err)\n }\n }\n\n if (!shutdownHandlersRegistered) {\n process.once(\"SIGTERM\", handleShutdown)\n process.once(\"SIGINT\", handleShutdown)\n shutdownHandlersRegistered = true\n }\n\n return {\n provider,\n flush,\n shutdown,\n ready,\n }\n}\n","import type { TracerProvider } from \"@opentelemetry/api\"\nimport { type Instrumentation, registerInstrumentations } from \"@opentelemetry/instrumentation\"\nimport { AnthropicInstrumentation } from \"@traceloop/instrumentation-anthropic\"\nimport { BedrockInstrumentation } from \"@traceloop/instrumentation-bedrock\"\nimport { CohereInstrumentation } from \"@traceloop/instrumentation-cohere\"\nimport { LangChainInstrumentation } from \"@traceloop/instrumentation-langchain\"\nimport { LlamaIndexInstrumentation } from \"@traceloop/instrumentation-llamaindex\"\nimport { OpenAIInstrumentation } from \"@traceloop/instrumentation-openai\"\nimport { TogetherInstrumentation } from \"@traceloop/instrumentation-together\"\nimport { AIPlatformInstrumentation, VertexAIInstrumentation } from \"@traceloop/instrumentation-vertexai\"\n\n/**\n * Supported LLM instrumentation types.\n * Use these string identifiers to enable auto-instrumentation.\n */\nexport type InstrumentationType =\n | \"openai\"\n | \"anthropic\"\n | \"bedrock\"\n | \"cohere\"\n | \"langchain\"\n | \"llamaindex\"\n | \"togetherai\"\n | \"vertexai\"\n | \"aiplatform\"\n\n/**\n * Minimal interface for LLM instrumentation instances.\n * Extends OpenTelemetry's Instrumentation interface.\n */\ninterface LlmInstrumentation extends Instrumentation {\n manuallyInstrument?(module: unknown): void\n}\n\n/**\n * Options for creating LLM instrumentations.\n */\ninterface CreateInstrumentationsOptions {\n /** List of instrumentation types to enable. */\n instrumentations: InstrumentationType[]\n /**\n * Optional module references for auto-instrumentation.\n * If not provided, the instrumentation will attempt to require the module.\n * Used for Traceloop-based instrumentations.\n */\n modules?: Partial<Record<InstrumentationType, unknown>>\n /**\n * Per-instrumentation token enrichment settings.\n * @default { openai: true }\n */\n enrichTokens?: Partial<Record<InstrumentationType, boolean>>\n}\n\ninterface InstrumentationConfig {\n ctor: new (config?: Record<string, unknown>) => LlmInstrumentation\n moduleName: string\n defaultEnrichTokens?: boolean\n}\n\nconst INSTRUMENTATION_MAP: Record<InstrumentationType, InstrumentationConfig> = {\n openai: { ctor: OpenAIInstrumentation, moduleName: \"openai\", defaultEnrichTokens: true },\n anthropic: { ctor: AnthropicInstrumentation, moduleName: \"@anthropic-ai/sdk\" },\n bedrock: { ctor: BedrockInstrumentation, moduleName: \"@aws-sdk/client-bedrock-runtime\" },\n cohere: { ctor: CohereInstrumentation, moduleName: \"cohere-ai\" },\n langchain: { ctor: LangChainInstrumentation, moduleName: \"langchain\" },\n llamaindex: { ctor: LlamaIndexInstrumentation, moduleName: \"llamaindex\" },\n togetherai: { ctor: TogetherInstrumentation, moduleName: \"together-ai\", defaultEnrichTokens: false },\n vertexai: { ctor: VertexAIInstrumentation, moduleName: \"@google-cloud/vertexai\" },\n aiplatform: { ctor: AIPlatformInstrumentation, moduleName: \"@google-cloud/aiplatform\" },\n}\n\n/**\n * Internal function to create LLM instrumentation instances.\n * Not exported publicly - use registerLatitudeInstrumentations instead.\n */\nasync function createLatitudeInstrumentations(options: CreateInstrumentationsOptions): Promise<LlmInstrumentation[]> {\n const result: LlmInstrumentation[] = []\n\n for (const type of options.instrumentations) {\n const config = INSTRUMENTATION_MAP[type]\n if (!config) {\n console.warn(`[Latitude] Unknown instrumentation type: ${type}`)\n continue\n }\n\n const enrichTokens = options.enrichTokens?.[type] ?? config.defaultEnrichTokens\n const inst = new config.ctor(enrichTokens !== undefined ? { enrichTokens } : undefined)\n\n // Get module from explicit options or try to auto-require\n const moduleRef = options.modules?.[type] ?? (await tryRequire(config.moduleName))\n if (!moduleRef) {\n console.warn(\n `[Latitude] Module not found for ${type}: ${config.moduleName}. Install it or pass it explicitly in 'modules'.`,\n )\n continue\n }\n inst.manuallyInstrument?.(moduleRef)\n\n result.push(inst)\n }\n\n return result\n}\n\nasync function tryRequire(moduleName: string): Promise<unknown | undefined> {\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n return require(moduleName)\n } catch {\n // Fallback to dynamic import for ESM environments\n try {\n const mod = await import(moduleName)\n return mod.default ?? mod\n } catch {\n return undefined\n }\n }\n}\n\n/**\n * Registers LLM instrumentations with the global OpenTelemetry instrumentation registry.\n *\n * This is a convenience wrapper around `createLatitudeInstrumentations` and\n * `@opentelemetry/instrumentation`'s `registerInstrumentations`.\n *\n * @example\n * ```typescript\n * import { NodeTracerProvider } from \"@opentelemetry/sdk-trace-node\"\n * import { registerLatitudeInstrumentations, LatitudeSpanProcessor } from \"@latitude-data/telemetry\"\n *\n * const provider = new NodeTracerProvider({\n * spanProcessors: [new LatitudeSpanProcessor(apiKey, projectSlug)],\n * })\n *\n * await registerLatitudeInstrumentations({\n * instrumentations: [\"openai\", \"anthropic\"],\n * tracerProvider: provider,\n * })\n *\n * provider.register()\n * ```\n */\nexport async function registerLatitudeInstrumentations(\n options: CreateInstrumentationsOptions & { tracerProvider: TracerProvider },\n): Promise<void> {\n const instrumentations = await createLatitudeInstrumentations(options)\n registerInstrumentations({\n instrumentations,\n tracerProvider: options.tracerProvider,\n })\n}\n","import type { Context } from \"@opentelemetry/api\"\nimport { OTLPTraceExporter } from \"@opentelemetry/exporter-trace-otlp-http\"\nimport {\n BatchSpanProcessor,\n type ReadableSpan,\n SimpleSpanProcessor,\n type Span,\n type SpanProcessor,\n} from \"@opentelemetry/sdk-trace-node\"\nimport { ATTRIBUTES } from \"../constants/index.ts\"\nimport { env } from \"../env/index.ts\"\nimport { getLatitudeContext } from \"./context.ts\"\nimport { DEFAULT_REDACT_SPAN_PROCESSOR, RedactSpanProcessor } from \"./redact.ts\"\nimport {\n buildShouldExportSpanFromFields,\n ExportFilterSpanProcessor,\n RedactThenExportSpanProcessor,\n} from \"./span-filter.ts\"\nimport type { LatitudeSpanProcessorOptions } from \"./types.ts\"\n\nexport class LatitudeSpanProcessor implements SpanProcessor {\n private readonly tail: SpanProcessor\n\n constructor(apiKey: string, projectSlug: string, options?: LatitudeSpanProcessorOptions) {\n if (!apiKey || apiKey.trim() === \"\") {\n throw new Error(\"[Latitude] apiKey is required and cannot be empty\")\n }\n if (!projectSlug || projectSlug.trim() === \"\") {\n throw new Error(\"[Latitude] projectSlug is required and cannot be empty\")\n }\n\n const exporter =\n options?.exporter ??\n new OTLPTraceExporter({\n url: `${env.EXPORTER_URL}/v1/traces`,\n headers: {\n Authorization: `Bearer ${apiKey}`,\n \"Content-Type\": \"application/json\",\n \"X-Latitude-Project\": projectSlug,\n },\n timeoutMillis: 30_000,\n })\n\n const redact = options?.disableRedact\n ? null\n : options?.redact\n ? new RedactSpanProcessor(options.redact)\n : DEFAULT_REDACT_SPAN_PROCESSOR()\n\n const batchOrSimple = options?.disableBatch ? new SimpleSpanProcessor(exporter) : new BatchSpanProcessor(exporter)\n\n const shouldExport = buildShouldExportSpanFromFields({\n disableSmartFilter: options?.disableSmartFilter,\n shouldExportSpan: options?.shouldExportSpan,\n blockedInstrumentationScopes: options?.blockedInstrumentationScopes,\n })\n\n const redactThenExport = new RedactThenExportSpanProcessor(redact, batchOrSimple)\n this.tail = new ExportFilterSpanProcessor(shouldExport, redactThenExport)\n }\n\n onStart(span: Span, parentContext: Context): void {\n const latitudeData = getLatitudeContext(parentContext)\n\n if (latitudeData) {\n if (latitudeData.name) {\n span.setAttribute(ATTRIBUTES.name, latitudeData.name)\n // Only update span name for the capture root span (has latitude.capture.root attr)\n // Child spans keep their original names (database.query, business.validate, etc.)\n if (span.attributes[\"latitude.capture.root\"]) {\n span.updateName(latitudeData.name)\n }\n }\n if (latitudeData.tags && latitudeData.tags.length > 0) {\n span.setAttribute(ATTRIBUTES.tags, JSON.stringify(latitudeData.tags))\n }\n if (latitudeData.metadata && Object.keys(latitudeData.metadata).length > 0) {\n span.setAttribute(ATTRIBUTES.metadata, JSON.stringify(latitudeData.metadata))\n }\n if (latitudeData.sessionId) {\n span.setAttribute(ATTRIBUTES.sessionId, latitudeData.sessionId)\n }\n if (latitudeData.userId) {\n span.setAttribute(ATTRIBUTES.userId, latitudeData.userId)\n }\n }\n\n this.tail.onStart(span, parentContext)\n }\n\n onEnd(span: ReadableSpan): void {\n this.tail.onEnd(span)\n }\n\n async forceFlush(): Promise<void> {\n await this.tail.forceFlush()\n }\n\n async shutdown(): Promise<void> {\n await this.tail.shutdown()\n }\n}\n","export const ATTRIBUTES = {\n name: \"latitude.capture.name\",\n tags: \"latitude.tags\",\n metadata: \"latitude.metadata\",\n sessionId: \"session.id\",\n userId: \"user.id\",\n} as const\n","export const SCOPE_LATITUDE = \"so.latitude.instrumentation\"\n\nexport enum InstrumentationScope {\n Manual = \"manual\",\n OpenAI = \"openai\",\n Anthropic = \"anthropic\",\n AzureOpenAI = \"azure\",\n VercelAI = \"vercelai\",\n VertexAI = \"vertexai\",\n AIPlatform = \"aiplatform\",\n MistralAI = \"mistralai\",\n Bedrock = \"bedrock\",\n Sagemaker = \"sagemaker\",\n TogetherAI = \"togetherai\",\n Replicate = \"replicate\",\n Groq = \"groq\",\n Cohere = \"cohere\",\n LiteLLM = \"litellm\",\n Langchain = \"langchain\",\n LlamaIndex = \"llamaindex\",\n DSPy = \"dspy\",\n Haystack = \"haystack\",\n Ollama = \"ollama\",\n Transformers = \"transformers\",\n AlephAlpha = \"alephalpha\",\n}\n","const DEFAULT_EXPORTER_URL =\n {\n production: \"https://ingest.latitude.so\",\n development: \"http://localhost:3002\",\n test: \"http://localhost:3002\",\n }[process.env.NODE_ENV ?? \"development\"] ?? \"http://localhost:3002\"\n\nfunction getExporterUrl() {\n if (process.env.LATITUDE_TELEMETRY_URL) {\n return process.env.LATITUDE_TELEMETRY_URL\n }\n\n return DEFAULT_EXPORTER_URL\n}\n\nexport const env = { EXPORTER_URL: getExporterUrl() } as const\n","import type * as otel from \"@opentelemetry/api\"\nimport type { ReadableSpan, Span, SpanProcessor } from \"@opentelemetry/sdk-trace-node\"\n\nexport interface RedactSpanProcessorOptions {\n attributes: (string | RegExp)[]\n mask?: (attribute: string, value: unknown) => string\n}\n\nexport class RedactSpanProcessor implements SpanProcessor {\n private options: RedactSpanProcessorOptions\n\n constructor(options: RedactSpanProcessorOptions) {\n this.options = options\n\n if (!options.mask) {\n this.options.mask = (_attribute: string, _value: unknown) => \"******\"\n }\n }\n\n onStart(_span: Span, _context: otel.Context): void {\n // Noop\n }\n\n onEnd(span: ReadableSpan): void {\n Object.assign(span.attributes, this.redactAttributes(span.attributes))\n for (const event of span.events) {\n if (!event.attributes) continue\n Object.assign(event.attributes, this.redactAttributes(event.attributes))\n }\n for (const link of span.links) {\n if (!link.attributes) continue\n Object.assign(link.attributes, this.redactAttributes(link.attributes))\n }\n }\n\n forceFlush(): Promise<void> {\n return Promise.resolve()\n }\n\n shutdown(): Promise<void> {\n return Promise.resolve()\n }\n\n private shouldRedact(attribute: string) {\n return this.options.attributes.some((pattern) => {\n if (typeof pattern === \"string\") {\n return attribute === pattern\n } else if (pattern instanceof RegExp) {\n return pattern.test(attribute)\n }\n return false\n })\n }\n\n private redactAttributes(attributes: otel.Attributes) {\n const redacted: otel.Attributes = {}\n\n for (const [key, value] of Object.entries(attributes)) {\n if (this.shouldRedact(key)) {\n redacted[key] = this.options.mask?.(key, value)\n }\n }\n\n return redacted\n }\n}\n\nexport const DEFAULT_REDACT_SPAN_PROCESSOR = () =>\n new RedactSpanProcessor({\n attributes: [\n // HTTP security headers\n /^http\\.request\\.header\\.authorization$/i,\n /^http\\.request\\.header\\.cookie$/i,\n /^http\\.request\\.header\\.x[-_]api[-_]key$/i,\n // Database statements may contain sensitive data\n /^db\\.statement$/i,\n ],\n })\n","import type { Context } from \"@opentelemetry/api\"\nimport type { ReadableSpan, Span, SpanProcessor } from \"@opentelemetry/sdk-trace-node\"\nimport { SCOPE_LATITUDE } from \"../constants/scope.ts\"\n\n/** OpenTelemetry GenAI semantic convention attribute prefix. */\nconst GEN_AI_PREFIX = \"gen_ai.\"\n\n/** Legacy / OpenInference-style LLM attribute prefix. */\nconst LLM_PREFIX = \"llm.\"\n\nconst OPENINFERENCE_KIND = \"openinference.span.kind\"\n\n/** OTel Python instrumentation scope prefixes for LLM-related instrumentors we support. */\nconst OTEL_LLM_INSTRUMENTATION_SCOPE_PREFIXES = [\n \"opentelemetry.instrumentation.alephalpha\",\n \"opentelemetry.instrumentation.anthropic\",\n \"opentelemetry.instrumentation.bedrock\",\n \"opentelemetry.instrumentation.cohere\",\n \"opentelemetry.instrumentation.crewai\",\n \"opentelemetry.instrumentation.google_generativeai\",\n \"opentelemetry.instrumentation.groq\",\n \"opentelemetry.instrumentation.haystack\",\n \"opentelemetry.instrumentation.langchain\",\n \"opentelemetry.instrumentation.llamaindex\",\n \"opentelemetry.instrumentation.mistralai\",\n \"opentelemetry.instrumentation.ollama\",\n \"opentelemetry.instrumentation.openai\",\n \"opentelemetry.instrumentation.replicate\",\n \"opentelemetry.instrumentation.sagemaker\",\n \"opentelemetry.instrumentation.together\",\n \"opentelemetry.instrumentation.transformers\",\n \"opentelemetry.instrumentation.vertexai\",\n \"opentelemetry.instrumentation.watsonx\",\n \"openinference.instrumentation\",\n] as const\n\n/** Substrings in scope names that indicate LLM / GenAI instrumentation (e.g. Traceloop JS). */\nconst LLM_SCOPE_SUBSTRINGS = [\"openinference\", \"traceloop\", \"langsmith\", \"litellm\"] as const\n\nexport type SmartFilterOptions = {\n /**\n * When true, all spans are exported (legacy behavior).\n * Default false — only LLM-relevant spans are exported.\n */\n disableSmartFilter?: boolean\n /**\n * When smart filter is on, also export spans for which this returns true\n * (in addition to {@link isDefaultExportSpan}).\n */\n shouldExportSpan?: (span: ReadableSpan) => boolean\n /** Instrumentation scope names to drop (exact match) even if they pass the default predicate. */\n blockedInstrumentationScopes?: string[]\n}\n\n/** Input for {@link buildShouldExportSpanFromFields}; allows `undefined` field values for ergonomics. */\nexport type SmartFilterFieldsInput = {\n disableSmartFilter?: boolean | undefined\n shouldExportSpan?: ((span: ReadableSpan) => boolean) | undefined\n blockedInstrumentationScopes?: string[] | undefined\n}\n\n/**\n * Builds the export predicate from loose option fields (`exactOptionalPropertyTypes`-safe call sites).\n */\nexport function buildShouldExportSpanFromFields(fields: SmartFilterFieldsInput): (span: ReadableSpan) => boolean {\n return buildShouldExportSpan({\n ...(fields.disableSmartFilter !== undefined ? { disableSmartFilter: fields.disableSmartFilter } : {}),\n ...(fields.shouldExportSpan !== undefined ? { shouldExportSpan: fields.shouldExportSpan } : {}),\n ...(fields.blockedInstrumentationScopes !== undefined\n ? { blockedInstrumentationScopes: fields.blockedInstrumentationScopes }\n : {}),\n })\n}\n\nfunction attributeKeys(span: ReadableSpan): string[] {\n const attrs = span.attributes\n if (!attrs || typeof attrs !== \"object\") return []\n return Object.keys(attrs as Record<string, unknown>)\n}\n\nfunction instrumentationScopeName(span: ReadableSpan): string {\n return span.instrumentationLibrary?.name ?? \"\"\n}\n\n/** True if the span uses OpenTelemetry GenAI semantic conventions or common LLM attribute namespaces. */\nexport function isGenAiOrLlmAttributeSpan(span: ReadableSpan): boolean {\n for (const key of attributeKeys(span)) {\n if (key.startsWith(GEN_AI_PREFIX) || key.startsWith(LLM_PREFIX)) return true\n if (key === OPENINFERENCE_KIND || key.startsWith(\"openinference.\")) return true\n // Vercel AI SDK uses ai.* prefix\n if (key.startsWith(\"ai.\")) return true\n // Latitude context attributes\n if (key.startsWith(\"latitude.\")) return true\n }\n return false\n}\n\n/** True if the span was created with Latitude's tracer scopes. */\nexport function isLatitudeInstrumentationSpan(span: ReadableSpan): boolean {\n const name = instrumentationScopeName(span)\n return name === SCOPE_LATITUDE || name.startsWith(`${SCOPE_LATITUDE}.`)\n}\n\nfunction isKnownLlmInstrumentationScope(span: ReadableSpan): boolean {\n const name = instrumentationScopeName(span)\n if (!name) return false\n for (const prefix of OTEL_LLM_INSTRUMENTATION_SCOPE_PREFIXES) {\n if (name === prefix || name.startsWith(`${prefix}.`)) return true\n }\n const lower = name.toLowerCase()\n for (const part of LLM_SCOPE_SUBSTRINGS) {\n if (lower.includes(part)) return true\n }\n return false\n}\n\n/**\n * Default export predicate (smart filter): Latitude scopes, GenAI / LLM attributes,\n * or known LLM instrumentation scopes.\n */\nexport function isDefaultExportSpan(span: ReadableSpan): boolean {\n if (isLatitudeInstrumentationSpan(span)) return true\n if (isGenAiOrLlmAttributeSpan(span)) return true\n if (isKnownLlmInstrumentationScope(span)) return true\n return false\n}\n\nexport function buildShouldExportSpan(options: SmartFilterOptions): (span: ReadableSpan) => boolean {\n if (options.disableSmartFilter) return () => true\n const blocked = new Set(options.blockedInstrumentationScopes ?? [])\n const extra = options.shouldExportSpan\n return (span: ReadableSpan) => {\n const scope = instrumentationScopeName(span)\n if (blocked.has(scope)) return false\n if (isDefaultExportSpan(span)) return true\n if (extra?.(span)) return true\n return false\n }\n}\n\n/**\n * Drops spans that fail the export predicate before passing them to the inner processor.\n * Inner processor should perform redaction and export.\n */\nexport class ExportFilterSpanProcessor implements SpanProcessor {\n private readonly shouldExport: (span: ReadableSpan) => boolean\n private readonly inner: SpanProcessor\n\n constructor(shouldExport: (span: ReadableSpan) => boolean, inner: SpanProcessor) {\n this.shouldExport = shouldExport\n this.inner = inner\n }\n\n onStart(span: Span, parentContext: Context): void {\n this.inner.onStart(span, parentContext)\n }\n\n onEnd(span: ReadableSpan): void {\n if (!this.shouldExport(span)) return\n this.inner.onEnd(span)\n }\n\n forceFlush(): Promise<void> {\n return this.inner.forceFlush()\n }\n\n shutdown(): Promise<void> {\n return this.inner.shutdown()\n }\n}\n\n/** Runs optional redaction then the export processor (batch/simple). */\nexport class RedactThenExportSpanProcessor implements SpanProcessor {\n private readonly redact: SpanProcessor | null\n private readonly exportProcessor: SpanProcessor\n\n constructor(redact: SpanProcessor | null, exportProcessor: SpanProcessor) {\n this.redact = redact\n this.exportProcessor = exportProcessor\n }\n\n onStart(span: Span, parentContext: Context): void {\n this.redact?.onStart(span, parentContext)\n this.exportProcessor.onStart(span, parentContext)\n }\n\n onEnd(span: ReadableSpan): void {\n this.redact?.onEnd(span)\n this.exportProcessor.onEnd(span)\n }\n\n forceFlush(): Promise<void> {\n return this.exportProcessor.forceFlush()\n }\n\n shutdown(): Promise<void> {\n return this.exportProcessor.shutdown()\n }\n}\n"],"mappings":"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","names":["import_api","import_sdk_trace_node"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/sdk/context.ts","../src/sdk/init.ts","../src/sdk/instrumentations.ts","../src/sdk/processor.ts","../src/constants/attributes.ts","../src/constants/scope.ts","../src/env/env.ts","../src/sdk/redact.ts","../src/sdk/span-filter.ts"],"sourcesContent":["export * from \"./sdk/index.ts\"\n","import { type Context, context, createContextKey, trace } from \"@opentelemetry/api\"\nimport type { ContextOptions } from \"./types.ts\"\n\nexport const LATITUDE_CONTEXT_KEY = createContextKey(\"latitude-internal-context\")\nconst CAPTURE_TRACER_NAME = \"so.latitude.instrumentation.capture\"\n\ntype LatitudeContextData = {\n name: string | undefined\n tags: string[] | undefined\n metadata: Record<string, unknown> | undefined\n sessionId: string | undefined\n userId: string | undefined\n}\n\nexport function getLatitudeContext(ctx: Context): LatitudeContextData | undefined {\n return ctx.getValue(LATITUDE_CONTEXT_KEY) as LatitudeContextData | undefined\n}\n\nfunction mergeArrays<T>(a: T[] | undefined, b: T[] | undefined): T[] | undefined {\n if (!a && !b) return undefined\n if (!a) return b\n if (!b) return a\n return [...new Set([...a, ...b])]\n}\n\nexport function capture<T>(name: string, fn: () => T | Promise<T>, options: ContextOptions = {}): T | Promise<T> {\n const currentContext = context.active()\n const existingData = getLatitudeContext(currentContext)\n\n const mergedData: LatitudeContextData = {\n name: options.name ?? name,\n tags: mergeArrays(existingData?.tags, options.tags),\n metadata: { ...existingData?.metadata, ...options.metadata },\n sessionId: options.sessionId ?? existingData?.sessionId,\n userId: options.userId ?? existingData?.userId,\n }\n\n const newContext = currentContext.setValue(LATITUDE_CONTEXT_KEY, mergedData)\n const existingSpan = trace.getSpan(currentContext)\n\n if (existingSpan) {\n return context.with(newContext, fn)\n }\n\n const tracer = trace.getTracer(CAPTURE_TRACER_NAME)\n\n return tracer.startActiveSpan(name, { attributes: { \"latitude.capture.root\": true } }, newContext, (span) => {\n let result: T | Promise<T>\n try {\n result = fn()\n } catch (error) {\n span.recordException(error as Error)\n span.end()\n throw error\n }\n\n if (result instanceof Promise) {\n return result\n .catch((error) => {\n span.recordException(error as Error)\n throw error\n })\n .finally(() => {\n span.end()\n }) as T | Promise<T>\n }\n\n span.end()\n return result\n })\n}\n","import { context, propagation } from \"@opentelemetry/api\"\nimport { AsyncLocalStorageContextManager } from \"@opentelemetry/context-async-hooks\"\nimport { CompositePropagator, W3CBaggagePropagator, W3CTraceContextPropagator } from \"@opentelemetry/core\"\nimport { resourceFromAttributes } from \"@opentelemetry/resources\"\nimport { NodeTracerProvider } from \"@opentelemetry/sdk-trace-node\"\nimport { ATTR_SERVICE_NAME } from \"@opentelemetry/semantic-conventions\"\nimport { registerLatitudeInstrumentations } from \"./instrumentations.ts\"\nimport { LatitudeSpanProcessor } from \"./processor.ts\"\nimport type { InitLatitudeOptions } from \"./types.ts\"\n\nconst SERVICE_NAME = process.env.npm_package_name || \"unknown\"\n\n/** Module-level flag to prevent duplicate signal handler registration on repeated initLatitude calls */\nlet shutdownHandlersRegistered = false\n\nexport function initLatitude(options: InitLatitudeOptions): {\n provider: NodeTracerProvider\n flush: () => Promise<void>\n shutdown: () => Promise<void>\n ready: Promise<void>\n} {\n const { apiKey, projectSlug, instrumentations = [], ...processorOptions } = options\n\n if (!apiKey || apiKey.trim() === \"\") {\n throw new Error(\"[Latitude] apiKey is required and cannot be empty\")\n }\n if (!projectSlug || projectSlug.trim() === \"\") {\n throw new Error(\"[Latitude] projectSlug is required and cannot be empty\")\n }\n\n const contextManager = new AsyncLocalStorageContextManager()\n contextManager.enable()\n\n const propagator = new CompositePropagator({\n propagators: [new W3CTraceContextPropagator(), new W3CBaggagePropagator()],\n })\n\n context.setGlobalContextManager(contextManager)\n propagation.setGlobalPropagator(propagator)\n\n const resourceServiceName =\n typeof processorOptions.serviceName === \"string\" && processorOptions.serviceName.trim() !== \"\"\n ? processorOptions.serviceName.trim()\n : SERVICE_NAME\n\n const provider = new NodeTracerProvider({\n resource: resourceFromAttributes({\n [ATTR_SERVICE_NAME]: resourceServiceName,\n }),\n spanProcessors: [new LatitudeSpanProcessor(apiKey, projectSlug, processorOptions)],\n })\n\n provider.register()\n\n const ready = registerLatitudeInstrumentations({\n instrumentations,\n tracerProvider: provider,\n }).catch((err) => {\n console.warn(\"[Latitude] Failed to register instrumentations:\", err)\n })\n\n const shutdown = async (): Promise<void> => {\n await provider.shutdown()\n }\n\n const flush = async (): Promise<void> => {\n await provider.forceFlush()\n }\n\n const handleShutdown = async () => {\n try {\n await shutdown()\n } catch (err) {\n console.error(\"Error during Latitude Telemetry shutdown:\", err)\n }\n }\n\n if (!shutdownHandlersRegistered) {\n process.once(\"SIGTERM\", handleShutdown)\n process.once(\"SIGINT\", handleShutdown)\n shutdownHandlersRegistered = true\n }\n\n return {\n provider,\n flush,\n shutdown,\n ready,\n }\n}\n","import type { TracerProvider } from \"@opentelemetry/api\"\nimport { type Instrumentation, registerInstrumentations } from \"@opentelemetry/instrumentation\"\nimport { AnthropicInstrumentation } from \"@traceloop/instrumentation-anthropic\"\nimport { BedrockInstrumentation } from \"@traceloop/instrumentation-bedrock\"\nimport { CohereInstrumentation } from \"@traceloop/instrumentation-cohere\"\nimport { LangChainInstrumentation } from \"@traceloop/instrumentation-langchain\"\nimport { LlamaIndexInstrumentation } from \"@traceloop/instrumentation-llamaindex\"\nimport { OpenAIInstrumentation } from \"@traceloop/instrumentation-openai\"\nimport { TogetherInstrumentation } from \"@traceloop/instrumentation-together\"\nimport { AIPlatformInstrumentation, VertexAIInstrumentation } from \"@traceloop/instrumentation-vertexai\"\n\n/**\n * Supported LLM instrumentation types.\n * Use these string identifiers to enable auto-instrumentation.\n */\nexport type InstrumentationType =\n | \"openai\"\n | \"anthropic\"\n | \"bedrock\"\n | \"cohere\"\n | \"langchain\"\n | \"llamaindex\"\n | \"togetherai\"\n | \"vertexai\"\n | \"aiplatform\"\n\n/**\n * Minimal interface for LLM instrumentation instances.\n * Extends OpenTelemetry's Instrumentation interface.\n */\ninterface LlmInstrumentation extends Instrumentation {\n manuallyInstrument?(module: unknown): void\n}\n\n/**\n * Options for creating LLM instrumentations.\n */\ninterface CreateInstrumentationsOptions {\n /** List of instrumentation types to enable. */\n instrumentations: InstrumentationType[]\n /**\n * Optional module references for auto-instrumentation.\n * If not provided, the instrumentation will attempt to require the module.\n * Used for Traceloop-based instrumentations.\n */\n modules?: Partial<Record<InstrumentationType, unknown>>\n /**\n * Per-instrumentation token enrichment settings.\n * @default { openai: true }\n */\n enrichTokens?: Partial<Record<InstrumentationType, boolean>>\n}\n\ninterface InstrumentationConfig {\n ctor: new (config?: Record<string, unknown>) => LlmInstrumentation\n moduleName: string\n defaultEnrichTokens?: boolean\n}\n\nconst INSTRUMENTATION_MAP: Record<InstrumentationType, InstrumentationConfig> = {\n openai: { ctor: OpenAIInstrumentation, moduleName: \"openai\", defaultEnrichTokens: true },\n anthropic: { ctor: AnthropicInstrumentation, moduleName: \"@anthropic-ai/sdk\" },\n bedrock: { ctor: BedrockInstrumentation, moduleName: \"@aws-sdk/client-bedrock-runtime\" },\n cohere: { ctor: CohereInstrumentation, moduleName: \"cohere-ai\" },\n langchain: { ctor: LangChainInstrumentation, moduleName: \"langchain\" },\n llamaindex: { ctor: LlamaIndexInstrumentation, moduleName: \"llamaindex\" },\n togetherai: { ctor: TogetherInstrumentation, moduleName: \"together-ai\", defaultEnrichTokens: false },\n vertexai: { ctor: VertexAIInstrumentation, moduleName: \"@google-cloud/vertexai\" },\n aiplatform: { ctor: AIPlatformInstrumentation, moduleName: \"@google-cloud/aiplatform\" },\n}\n\n/**\n * Internal function to create LLM instrumentation instances.\n * Not exported publicly - use registerLatitudeInstrumentations instead.\n */\nasync function createLatitudeInstrumentations(options: CreateInstrumentationsOptions): Promise<LlmInstrumentation[]> {\n const result: LlmInstrumentation[] = []\n\n for (const type of options.instrumentations) {\n const config = INSTRUMENTATION_MAP[type]\n if (!config) {\n console.warn(`[Latitude] Unknown instrumentation type: ${type}`)\n continue\n }\n\n const enrichTokens = options.enrichTokens?.[type] ?? config.defaultEnrichTokens\n const inst = new config.ctor(enrichTokens !== undefined ? { enrichTokens } : undefined)\n\n // Get module from explicit options or try to auto-require\n const moduleRef = options.modules?.[type] ?? (await tryRequire(config.moduleName))\n if (!moduleRef) {\n console.warn(\n `[Latitude] Module not found for ${type}: ${config.moduleName}. Install it or pass it explicitly in 'modules'.`,\n )\n continue\n }\n inst.manuallyInstrument?.(moduleRef)\n\n result.push(inst)\n }\n\n return result\n}\n\nasync function tryRequire(moduleName: string): Promise<unknown | undefined> {\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n return require(moduleName)\n } catch {\n // Fallback to dynamic import for ESM environments\n try {\n const mod = await import(moduleName)\n return mod.default ?? mod\n } catch {\n return undefined\n }\n }\n}\n\n/**\n * Registers LLM instrumentations with the global OpenTelemetry instrumentation registry.\n *\n * This is a convenience wrapper around `createLatitudeInstrumentations` and\n * `@opentelemetry/instrumentation`'s `registerInstrumentations`.\n *\n * @example\n * ```typescript\n * import { NodeTracerProvider } from \"@opentelemetry/sdk-trace-node\"\n * import { registerLatitudeInstrumentations, LatitudeSpanProcessor } from \"@latitude-data/telemetry\"\n *\n * const provider = new NodeTracerProvider({\n * spanProcessors: [new LatitudeSpanProcessor(apiKey, projectSlug)],\n * })\n *\n * await registerLatitudeInstrumentations({\n * instrumentations: [\"openai\", \"anthropic\"],\n * tracerProvider: provider,\n * })\n *\n * provider.register()\n * ```\n */\nexport async function registerLatitudeInstrumentations(\n options: CreateInstrumentationsOptions & { tracerProvider: TracerProvider },\n): Promise<void> {\n const instrumentations = await createLatitudeInstrumentations(options)\n registerInstrumentations({\n instrumentations,\n tracerProvider: options.tracerProvider,\n })\n}\n","import type { Context } from \"@opentelemetry/api\"\nimport { OTLPTraceExporter } from \"@opentelemetry/exporter-trace-otlp-http\"\nimport {\n BatchSpanProcessor,\n type ReadableSpan,\n SimpleSpanProcessor,\n type Span,\n type SpanProcessor,\n} from \"@opentelemetry/sdk-trace-node\"\nimport { ATTR_SERVICE_NAME } from \"@opentelemetry/semantic-conventions\"\nimport { ATTRIBUTES } from \"../constants/index.ts\"\nimport { env } from \"../env/index.ts\"\nimport { getLatitudeContext } from \"./context.ts\"\nimport { DEFAULT_REDACT_SPAN_PROCESSOR, RedactSpanProcessor } from \"./redact.ts\"\nimport {\n buildShouldExportSpanFromFields,\n ExportFilterSpanProcessor,\n RedactThenExportSpanProcessor,\n} from \"./span-filter.ts\"\nimport type { LatitudeSpanProcessorOptions } from \"./types.ts\"\n\nexport class LatitudeSpanProcessor implements SpanProcessor {\n private readonly tail: SpanProcessor\n private readonly serviceName: string | undefined\n\n constructor(apiKey: string, projectSlug: string, options?: LatitudeSpanProcessorOptions) {\n if (!apiKey || apiKey.trim() === \"\") {\n throw new Error(\"[Latitude] apiKey is required and cannot be empty\")\n }\n if (!projectSlug || projectSlug.trim() === \"\") {\n throw new Error(\"[Latitude] projectSlug is required and cannot be empty\")\n }\n\n const exporter =\n options?.exporter ??\n new OTLPTraceExporter({\n url: `${env.EXPORTER_URL}/v1/traces`,\n headers: {\n Authorization: `Bearer ${apiKey}`,\n \"Content-Type\": \"application/json\",\n \"X-Latitude-Project\": projectSlug,\n },\n timeoutMillis: 30_000,\n })\n\n const redact = options?.disableRedact\n ? null\n : options?.redact\n ? new RedactSpanProcessor(options.redact)\n : DEFAULT_REDACT_SPAN_PROCESSOR()\n\n const batchOrSimple = options?.disableBatch ? new SimpleSpanProcessor(exporter) : new BatchSpanProcessor(exporter)\n\n const shouldExport = buildShouldExportSpanFromFields({\n disableSmartFilter: options?.disableSmartFilter,\n shouldExportSpan: options?.shouldExportSpan,\n blockedInstrumentationScopes: options?.blockedInstrumentationScopes,\n })\n\n const redactThenExport = new RedactThenExportSpanProcessor(redact, batchOrSimple)\n this.tail = new ExportFilterSpanProcessor(shouldExport, redactThenExport)\n\n const rawServiceName = options?.serviceName?.trim()\n this.serviceName = rawServiceName === \"\" ? undefined : rawServiceName\n }\n\n onStart(span: Span, parentContext: Context): void {\n if (this.serviceName !== undefined) {\n span.setAttribute(ATTR_SERVICE_NAME, this.serviceName)\n }\n\n const latitudeData = getLatitudeContext(parentContext)\n\n if (latitudeData) {\n if (latitudeData.name) {\n span.setAttribute(ATTRIBUTES.name, latitudeData.name)\n // Only update span name for the capture root span (has latitude.capture.root attr)\n // Child spans keep their original names (database.query, business.validate, etc.)\n if (span.attributes[\"latitude.capture.root\"]) {\n span.updateName(latitudeData.name)\n }\n }\n if (latitudeData.tags && latitudeData.tags.length > 0) {\n span.setAttribute(ATTRIBUTES.tags, JSON.stringify(latitudeData.tags))\n }\n if (latitudeData.metadata && Object.keys(latitudeData.metadata).length > 0) {\n span.setAttribute(ATTRIBUTES.metadata, JSON.stringify(latitudeData.metadata))\n }\n if (latitudeData.sessionId) {\n span.setAttribute(ATTRIBUTES.sessionId, latitudeData.sessionId)\n }\n if (latitudeData.userId) {\n span.setAttribute(ATTRIBUTES.userId, latitudeData.userId)\n }\n }\n\n this.tail.onStart(span, parentContext)\n }\n\n onEnd(span: ReadableSpan): void {\n this.tail.onEnd(span)\n }\n\n async forceFlush(): Promise<void> {\n await this.tail.forceFlush()\n }\n\n async shutdown(): Promise<void> {\n await this.tail.shutdown()\n }\n}\n","export const ATTRIBUTES = {\n name: \"latitude.capture.name\",\n tags: \"latitude.tags\",\n metadata: \"latitude.metadata\",\n sessionId: \"session.id\",\n userId: \"user.id\",\n} as const\n","export const SCOPE_LATITUDE = \"so.latitude.instrumentation\"\n\nexport enum InstrumentationScope {\n Manual = \"manual\",\n OpenAI = \"openai\",\n Anthropic = \"anthropic\",\n AzureOpenAI = \"azure\",\n VercelAI = \"vercelai\",\n VertexAI = \"vertexai\",\n AIPlatform = \"aiplatform\",\n MistralAI = \"mistralai\",\n Bedrock = \"bedrock\",\n Sagemaker = \"sagemaker\",\n TogetherAI = \"togetherai\",\n Replicate = \"replicate\",\n Groq = \"groq\",\n Cohere = \"cohere\",\n LiteLLM = \"litellm\",\n Langchain = \"langchain\",\n LlamaIndex = \"llamaindex\",\n DSPy = \"dspy\",\n Haystack = \"haystack\",\n Ollama = \"ollama\",\n Transformers = \"transformers\",\n AlephAlpha = \"alephalpha\",\n}\n","const DEFAULT_EXPORTER_URL =\n {\n production: \"https://ingest.latitude.so\",\n development: \"http://localhost:3002\",\n test: \"http://localhost:3002\",\n }[process.env.NODE_ENV ?? \"development\"] ?? \"http://localhost:3002\"\n\nfunction getExporterUrl() {\n if (process.env.LATITUDE_TELEMETRY_URL) {\n return process.env.LATITUDE_TELEMETRY_URL\n }\n\n return DEFAULT_EXPORTER_URL\n}\n\nexport const env = { EXPORTER_URL: getExporterUrl() } as const\n","import type * as otel from \"@opentelemetry/api\"\nimport type { ReadableSpan, Span, SpanProcessor } from \"@opentelemetry/sdk-trace-node\"\n\nexport interface RedactSpanProcessorOptions {\n attributes: (string | RegExp)[]\n mask?: (attribute: string, value: unknown) => string\n}\n\nexport class RedactSpanProcessor implements SpanProcessor {\n private options: RedactSpanProcessorOptions\n\n constructor(options: RedactSpanProcessorOptions) {\n this.options = options\n\n if (!options.mask) {\n this.options.mask = (_attribute: string, _value: unknown) => \"******\"\n }\n }\n\n onStart(_span: Span, _context: otel.Context): void {\n // Noop\n }\n\n onEnd(span: ReadableSpan): void {\n Object.assign(span.attributes, this.redactAttributes(span.attributes))\n for (const event of span.events) {\n if (!event.attributes) continue\n Object.assign(event.attributes, this.redactAttributes(event.attributes))\n }\n for (const link of span.links) {\n if (!link.attributes) continue\n Object.assign(link.attributes, this.redactAttributes(link.attributes))\n }\n }\n\n forceFlush(): Promise<void> {\n return Promise.resolve()\n }\n\n shutdown(): Promise<void> {\n return Promise.resolve()\n }\n\n private shouldRedact(attribute: string) {\n return this.options.attributes.some((pattern) => {\n if (typeof pattern === \"string\") {\n return attribute === pattern\n } else if (pattern instanceof RegExp) {\n return pattern.test(attribute)\n }\n return false\n })\n }\n\n private redactAttributes(attributes: otel.Attributes) {\n const redacted: otel.Attributes = {}\n\n for (const [key, value] of Object.entries(attributes)) {\n if (this.shouldRedact(key)) {\n redacted[key] = this.options.mask?.(key, value)\n }\n }\n\n return redacted\n }\n}\n\nexport const DEFAULT_REDACT_SPAN_PROCESSOR = () =>\n new RedactSpanProcessor({\n attributes: [\n // HTTP security headers\n /^http\\.request\\.header\\.authorization$/i,\n /^http\\.request\\.header\\.cookie$/i,\n /^http\\.request\\.header\\.x[-_]api[-_]key$/i,\n // Database statements may contain sensitive data\n /^db\\.statement$/i,\n ],\n })\n","import type { Context } from \"@opentelemetry/api\"\nimport type { ReadableSpan, Span, SpanProcessor } from \"@opentelemetry/sdk-trace-node\"\nimport { SCOPE_LATITUDE } from \"../constants/scope.ts\"\n\n/** OpenTelemetry GenAI semantic convention attribute prefix. */\nconst GEN_AI_PREFIX = \"gen_ai.\"\n\n/** Legacy / OpenInference-style LLM attribute prefix. */\nconst LLM_PREFIX = \"llm.\"\n\nconst OPENINFERENCE_KIND = \"openinference.span.kind\"\n\n/** OTel Python instrumentation scope prefixes for LLM-related instrumentors we support. */\nconst OTEL_LLM_INSTRUMENTATION_SCOPE_PREFIXES = [\n \"opentelemetry.instrumentation.alephalpha\",\n \"opentelemetry.instrumentation.anthropic\",\n \"opentelemetry.instrumentation.bedrock\",\n \"opentelemetry.instrumentation.cohere\",\n \"opentelemetry.instrumentation.crewai\",\n \"opentelemetry.instrumentation.google_generativeai\",\n \"opentelemetry.instrumentation.groq\",\n \"opentelemetry.instrumentation.haystack\",\n \"opentelemetry.instrumentation.langchain\",\n \"opentelemetry.instrumentation.llamaindex\",\n \"opentelemetry.instrumentation.mistralai\",\n \"opentelemetry.instrumentation.ollama\",\n \"opentelemetry.instrumentation.openai\",\n \"opentelemetry.instrumentation.replicate\",\n \"opentelemetry.instrumentation.sagemaker\",\n \"opentelemetry.instrumentation.together\",\n \"opentelemetry.instrumentation.transformers\",\n \"opentelemetry.instrumentation.vertexai\",\n \"opentelemetry.instrumentation.watsonx\",\n \"openinference.instrumentation\",\n] as const\n\n/** Substrings in scope names that indicate LLM / GenAI instrumentation (e.g. Traceloop JS). */\nconst LLM_SCOPE_SUBSTRINGS = [\"openinference\", \"traceloop\", \"langsmith\", \"litellm\"] as const\n\nexport type SmartFilterOptions = {\n /**\n * When true, all spans are exported (legacy behavior).\n * Default false — only LLM-relevant spans are exported.\n */\n disableSmartFilter?: boolean\n /**\n * When smart filter is on, also export spans for which this returns true\n * (in addition to {@link isDefaultExportSpan}).\n */\n shouldExportSpan?: (span: ReadableSpan) => boolean\n /** Instrumentation scope names to drop (exact match) even if they pass the default predicate. */\n blockedInstrumentationScopes?: string[]\n}\n\n/** Input for {@link buildShouldExportSpanFromFields}; allows `undefined` field values for ergonomics. */\nexport type SmartFilterFieldsInput = {\n disableSmartFilter?: boolean | undefined\n shouldExportSpan?: ((span: ReadableSpan) => boolean) | undefined\n blockedInstrumentationScopes?: string[] | undefined\n}\n\n/**\n * Builds the export predicate from loose option fields (`exactOptionalPropertyTypes`-safe call sites).\n */\nexport function buildShouldExportSpanFromFields(fields: SmartFilterFieldsInput): (span: ReadableSpan) => boolean {\n return buildShouldExportSpan({\n ...(fields.disableSmartFilter !== undefined ? { disableSmartFilter: fields.disableSmartFilter } : {}),\n ...(fields.shouldExportSpan !== undefined ? { shouldExportSpan: fields.shouldExportSpan } : {}),\n ...(fields.blockedInstrumentationScopes !== undefined\n ? { blockedInstrumentationScopes: fields.blockedInstrumentationScopes }\n : {}),\n })\n}\n\nfunction attributeKeys(span: ReadableSpan): string[] {\n const attrs = span.attributes\n if (!attrs || typeof attrs !== \"object\") return []\n return Object.keys(attrs as Record<string, unknown>)\n}\n\nfunction instrumentationScopeName(span: ReadableSpan): string {\n return span.instrumentationScope?.name ?? \"\"\n}\n\n/** True if the span uses OpenTelemetry GenAI semantic conventions or common LLM attribute namespaces. */\nexport function isGenAiOrLlmAttributeSpan(span: ReadableSpan): boolean {\n for (const key of attributeKeys(span)) {\n if (key.startsWith(GEN_AI_PREFIX) || key.startsWith(LLM_PREFIX)) return true\n if (key === OPENINFERENCE_KIND || key.startsWith(\"openinference.\")) return true\n // Vercel AI SDK uses ai.* prefix\n if (key.startsWith(\"ai.\")) return true\n // Latitude context attributes\n if (key.startsWith(\"latitude.\")) return true\n }\n return false\n}\n\n/** True if the span was created with Latitude's tracer scopes. */\nexport function isLatitudeInstrumentationSpan(span: ReadableSpan): boolean {\n const name = instrumentationScopeName(span)\n return name === SCOPE_LATITUDE || name.startsWith(`${SCOPE_LATITUDE}.`)\n}\n\nfunction isKnownLlmInstrumentationScope(span: ReadableSpan): boolean {\n const name = instrumentationScopeName(span)\n if (!name) return false\n for (const prefix of OTEL_LLM_INSTRUMENTATION_SCOPE_PREFIXES) {\n if (name === prefix || name.startsWith(`${prefix}.`)) return true\n }\n const lower = name.toLowerCase()\n for (const part of LLM_SCOPE_SUBSTRINGS) {\n if (lower.includes(part)) return true\n }\n return false\n}\n\n/**\n * Default export predicate (smart filter): Latitude scopes, GenAI / LLM attributes,\n * or known LLM instrumentation scopes.\n */\nexport function isDefaultExportSpan(span: ReadableSpan): boolean {\n if (isLatitudeInstrumentationSpan(span)) return true\n if (isGenAiOrLlmAttributeSpan(span)) return true\n if (isKnownLlmInstrumentationScope(span)) return true\n return false\n}\n\nexport function buildShouldExportSpan(options: SmartFilterOptions): (span: ReadableSpan) => boolean {\n if (options.disableSmartFilter) return () => true\n const blocked = new Set(options.blockedInstrumentationScopes ?? [])\n const extra = options.shouldExportSpan\n return (span: ReadableSpan) => {\n const scope = instrumentationScopeName(span)\n if (blocked.has(scope)) return false\n if (isDefaultExportSpan(span)) return true\n if (extra?.(span)) return true\n return false\n }\n}\n\n/**\n * Drops spans that fail the export predicate before passing them to the inner processor.\n * Inner processor should perform redaction and export.\n */\nexport class ExportFilterSpanProcessor implements SpanProcessor {\n private readonly shouldExport: (span: ReadableSpan) => boolean\n private readonly inner: SpanProcessor\n\n constructor(shouldExport: (span: ReadableSpan) => boolean, inner: SpanProcessor) {\n this.shouldExport = shouldExport\n this.inner = inner\n }\n\n onStart(span: Span, parentContext: Context): void {\n this.inner.onStart(span, parentContext)\n }\n\n onEnd(span: ReadableSpan): void {\n if (!this.shouldExport(span)) return\n this.inner.onEnd(span)\n }\n\n forceFlush(): Promise<void> {\n return this.inner.forceFlush()\n }\n\n shutdown(): Promise<void> {\n return this.inner.shutdown()\n }\n}\n\n/** Runs optional redaction then the export processor (batch/simple). */\nexport class RedactThenExportSpanProcessor implements SpanProcessor {\n private readonly redact: SpanProcessor | null\n private readonly exportProcessor: SpanProcessor\n\n constructor(redact: SpanProcessor | null, exportProcessor: SpanProcessor) {\n this.redact = redact\n this.exportProcessor = exportProcessor\n }\n\n onStart(span: Span, parentContext: Context): void {\n this.redact?.onStart(span, parentContext)\n this.exportProcessor.onStart(span, parentContext)\n }\n\n onEnd(span: ReadableSpan): void {\n this.redact?.onEnd(span)\n this.exportProcessor.onEnd(span)\n }\n\n forceFlush(): Promise<void> {\n return this.exportProcessor.forceFlush()\n }\n\n shutdown(): Promise<void> {\n return this.exportProcessor.shutdown()\n }\n}\n"],"mappings":"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","names":["import_api","import_sdk_trace_node","import_semantic_conventions"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -140,12 +140,16 @@ type InitLatitudeOptions = SmartFilterOptions & {
|
|
|
140
140
|
redact?: RedactSpanProcessorOptions;
|
|
141
141
|
disableBatch?: boolean;
|
|
142
142
|
exporter?: SpanExporter;
|
|
143
|
+
/** Sets `service.name` on exported spans (and on the provider resource when using `initLatitude`). */
|
|
144
|
+
serviceName?: string;
|
|
143
145
|
};
|
|
144
146
|
type LatitudeSpanProcessorOptions = SmartFilterOptions & {
|
|
145
147
|
disableRedact?: boolean;
|
|
146
148
|
redact?: RedactSpanProcessorOptions;
|
|
147
149
|
disableBatch?: boolean;
|
|
148
150
|
exporter?: SpanExporter;
|
|
151
|
+
/** Sets `service.name` on each span so Latitude ingest can attribute telemetry to your service. */
|
|
152
|
+
serviceName?: string;
|
|
149
153
|
};
|
|
150
154
|
|
|
151
155
|
declare function capture<T>(name: string, fn: () => T | Promise<T>, options?: ContextOptions): T | Promise<T>;
|
|
@@ -159,6 +163,7 @@ declare function initLatitude(options: InitLatitudeOptions): {
|
|
|
159
163
|
|
|
160
164
|
declare class LatitudeSpanProcessor implements SpanProcessor {
|
|
161
165
|
private readonly tail;
|
|
166
|
+
private readonly serviceName;
|
|
162
167
|
constructor(apiKey: string, projectSlug: string, options?: LatitudeSpanProcessorOptions);
|
|
163
168
|
onStart(span: Span, parentContext: Context): void;
|
|
164
169
|
onEnd(span: ReadableSpan): void;
|
package/dist/index.d.ts
CHANGED
|
@@ -140,12 +140,16 @@ type InitLatitudeOptions = SmartFilterOptions & {
|
|
|
140
140
|
redact?: RedactSpanProcessorOptions;
|
|
141
141
|
disableBatch?: boolean;
|
|
142
142
|
exporter?: SpanExporter;
|
|
143
|
+
/** Sets `service.name` on exported spans (and on the provider resource when using `initLatitude`). */
|
|
144
|
+
serviceName?: string;
|
|
143
145
|
};
|
|
144
146
|
type LatitudeSpanProcessorOptions = SmartFilterOptions & {
|
|
145
147
|
disableRedact?: boolean;
|
|
146
148
|
redact?: RedactSpanProcessorOptions;
|
|
147
149
|
disableBatch?: boolean;
|
|
148
150
|
exporter?: SpanExporter;
|
|
151
|
+
/** Sets `service.name` on each span so Latitude ingest can attribute telemetry to your service. */
|
|
152
|
+
serviceName?: string;
|
|
149
153
|
};
|
|
150
154
|
|
|
151
155
|
declare function capture<T>(name: string, fn: () => T | Promise<T>, options?: ContextOptions): T | Promise<T>;
|
|
@@ -159,6 +163,7 @@ declare function initLatitude(options: InitLatitudeOptions): {
|
|
|
159
163
|
|
|
160
164
|
declare class LatitudeSpanProcessor implements SpanProcessor {
|
|
161
165
|
private readonly tail;
|
|
166
|
+
private readonly serviceName;
|
|
162
167
|
constructor(apiKey: string, projectSlug: string, options?: LatitudeSpanProcessorOptions);
|
|
163
168
|
onStart(span: Span, parentContext: Context): void;
|
|
164
169
|
onEnd(span: ReadableSpan): void;
|
package/dist/index.js
CHANGED
|
@@ -60,9 +60,9 @@ function capture(name, fn, options = {}) {
|
|
|
60
60
|
import { context as context2, propagation } from "@opentelemetry/api";
|
|
61
61
|
import { AsyncLocalStorageContextManager } from "@opentelemetry/context-async-hooks";
|
|
62
62
|
import { CompositePropagator, W3CBaggagePropagator, W3CTraceContextPropagator } from "@opentelemetry/core";
|
|
63
|
-
import {
|
|
63
|
+
import { resourceFromAttributes } from "@opentelemetry/resources";
|
|
64
64
|
import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
|
|
65
|
-
import { ATTR_SERVICE_NAME } from "@opentelemetry/semantic-conventions";
|
|
65
|
+
import { ATTR_SERVICE_NAME as ATTR_SERVICE_NAME2 } from "@opentelemetry/semantic-conventions";
|
|
66
66
|
|
|
67
67
|
// src/sdk/instrumentations.ts
|
|
68
68
|
import { registerInstrumentations } from "@opentelemetry/instrumentation";
|
|
@@ -133,6 +133,7 @@ import {
|
|
|
133
133
|
BatchSpanProcessor,
|
|
134
134
|
SimpleSpanProcessor
|
|
135
135
|
} from "@opentelemetry/sdk-trace-node";
|
|
136
|
+
import { ATTR_SERVICE_NAME } from "@opentelemetry/semantic-conventions";
|
|
136
137
|
|
|
137
138
|
// src/constants/attributes.ts
|
|
138
139
|
var ATTRIBUTES = {
|
|
@@ -259,7 +260,7 @@ function attributeKeys(span) {
|
|
|
259
260
|
return Object.keys(attrs);
|
|
260
261
|
}
|
|
261
262
|
function instrumentationScopeName(span) {
|
|
262
|
-
return span.
|
|
263
|
+
return span.instrumentationScope?.name ?? "";
|
|
263
264
|
}
|
|
264
265
|
function isGenAiOrLlmAttributeSpan(span) {
|
|
265
266
|
for (const key of attributeKeys(span)) {
|
|
@@ -351,6 +352,7 @@ var RedactThenExportSpanProcessor = class {
|
|
|
351
352
|
// src/sdk/processor.ts
|
|
352
353
|
var LatitudeSpanProcessor = class {
|
|
353
354
|
tail;
|
|
355
|
+
serviceName;
|
|
354
356
|
constructor(apiKey, projectSlug, options) {
|
|
355
357
|
if (!apiKey || apiKey.trim() === "") {
|
|
356
358
|
throw new Error("[Latitude] apiKey is required and cannot be empty");
|
|
@@ -376,8 +378,13 @@ var LatitudeSpanProcessor = class {
|
|
|
376
378
|
});
|
|
377
379
|
const redactThenExport = new RedactThenExportSpanProcessor(redact, batchOrSimple);
|
|
378
380
|
this.tail = new ExportFilterSpanProcessor(shouldExport, redactThenExport);
|
|
381
|
+
const rawServiceName = options?.serviceName?.trim();
|
|
382
|
+
this.serviceName = rawServiceName === "" ? void 0 : rawServiceName;
|
|
379
383
|
}
|
|
380
384
|
onStart(span, parentContext) {
|
|
385
|
+
if (this.serviceName !== void 0) {
|
|
386
|
+
span.setAttribute(ATTR_SERVICE_NAME, this.serviceName);
|
|
387
|
+
}
|
|
381
388
|
const latitudeData = getLatitudeContext(parentContext);
|
|
382
389
|
if (latitudeData) {
|
|
383
390
|
if (latitudeData.name) {
|
|
@@ -430,9 +437,10 @@ function initLatitude(options) {
|
|
|
430
437
|
});
|
|
431
438
|
context2.setGlobalContextManager(contextManager);
|
|
432
439
|
propagation.setGlobalPropagator(propagator);
|
|
440
|
+
const resourceServiceName = typeof processorOptions.serviceName === "string" && processorOptions.serviceName.trim() !== "" ? processorOptions.serviceName.trim() : SERVICE_NAME;
|
|
433
441
|
const provider = new NodeTracerProvider({
|
|
434
|
-
resource:
|
|
435
|
-
[
|
|
442
|
+
resource: resourceFromAttributes({
|
|
443
|
+
[ATTR_SERVICE_NAME2]: resourceServiceName
|
|
436
444
|
}),
|
|
437
445
|
spanProcessors: [new LatitudeSpanProcessor(apiKey, projectSlug, processorOptions)]
|
|
438
446
|
});
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/sdk/context.ts","../src/sdk/init.ts","../src/sdk/instrumentations.ts","../src/sdk/processor.ts","../src/constants/attributes.ts","../src/constants/scope.ts","../src/env/env.ts","../src/sdk/redact.ts","../src/sdk/span-filter.ts"],"sourcesContent":["import { type Context, context, createContextKey, trace } from \"@opentelemetry/api\"\nimport type { ContextOptions } from \"./types.ts\"\n\nexport const LATITUDE_CONTEXT_KEY = createContextKey(\"latitude-internal-context\")\nconst CAPTURE_TRACER_NAME = \"so.latitude.instrumentation.capture\"\n\ntype LatitudeContextData = {\n name: string | undefined\n tags: string[] | undefined\n metadata: Record<string, unknown> | undefined\n sessionId: string | undefined\n userId: string | undefined\n}\n\nexport function getLatitudeContext(ctx: Context): LatitudeContextData | undefined {\n return ctx.getValue(LATITUDE_CONTEXT_KEY) as LatitudeContextData | undefined\n}\n\nfunction mergeArrays<T>(a: T[] | undefined, b: T[] | undefined): T[] | undefined {\n if (!a && !b) return undefined\n if (!a) return b\n if (!b) return a\n return [...new Set([...a, ...b])]\n}\n\nexport function capture<T>(name: string, fn: () => T | Promise<T>, options: ContextOptions = {}): T | Promise<T> {\n const currentContext = context.active()\n const existingData = getLatitudeContext(currentContext)\n\n const mergedData: LatitudeContextData = {\n name: options.name ?? name,\n tags: mergeArrays(existingData?.tags, options.tags),\n metadata: { ...existingData?.metadata, ...options.metadata },\n sessionId: options.sessionId ?? existingData?.sessionId,\n userId: options.userId ?? existingData?.userId,\n }\n\n const newContext = currentContext.setValue(LATITUDE_CONTEXT_KEY, mergedData)\n const existingSpan = trace.getSpan(currentContext)\n\n if (existingSpan) {\n return context.with(newContext, fn)\n }\n\n const tracer = trace.getTracer(CAPTURE_TRACER_NAME)\n\n return tracer.startActiveSpan(name, { attributes: { \"latitude.capture.root\": true } }, newContext, (span) => {\n let result: T | Promise<T>\n try {\n result = fn()\n } catch (error) {\n span.recordException(error as Error)\n span.end()\n throw error\n }\n\n if (result instanceof Promise) {\n return result\n .catch((error) => {\n span.recordException(error as Error)\n throw error\n })\n .finally(() => {\n span.end()\n }) as T | Promise<T>\n }\n\n span.end()\n return result\n })\n}\n","import { context, propagation } from \"@opentelemetry/api\"\nimport { AsyncLocalStorageContextManager } from \"@opentelemetry/context-async-hooks\"\nimport { CompositePropagator, W3CBaggagePropagator, W3CTraceContextPropagator } from \"@opentelemetry/core\"\nimport { Resource } from \"@opentelemetry/resources\"\nimport { NodeTracerProvider } from \"@opentelemetry/sdk-trace-node\"\nimport { ATTR_SERVICE_NAME } from \"@opentelemetry/semantic-conventions\"\nimport { registerLatitudeInstrumentations } from \"./instrumentations.ts\"\nimport { LatitudeSpanProcessor } from \"./processor.ts\"\nimport type { InitLatitudeOptions } from \"./types.ts\"\n\nconst SERVICE_NAME = process.env.npm_package_name || \"unknown\"\n\n/** Module-level flag to prevent duplicate signal handler registration on repeated initLatitude calls */\nlet shutdownHandlersRegistered = false\n\nexport function initLatitude(options: InitLatitudeOptions): {\n provider: NodeTracerProvider\n flush: () => Promise<void>\n shutdown: () => Promise<void>\n ready: Promise<void>\n} {\n const { apiKey, projectSlug, instrumentations = [], ...processorOptions } = options\n\n if (!apiKey || apiKey.trim() === \"\") {\n throw new Error(\"[Latitude] apiKey is required and cannot be empty\")\n }\n if (!projectSlug || projectSlug.trim() === \"\") {\n throw new Error(\"[Latitude] projectSlug is required and cannot be empty\")\n }\n\n const contextManager = new AsyncLocalStorageContextManager()\n contextManager.enable()\n\n const propagator = new CompositePropagator({\n propagators: [new W3CTraceContextPropagator(), new W3CBaggagePropagator()],\n })\n\n context.setGlobalContextManager(contextManager)\n propagation.setGlobalPropagator(propagator)\n\n const provider = new NodeTracerProvider({\n resource: new Resource({\n [ATTR_SERVICE_NAME]: SERVICE_NAME,\n }),\n spanProcessors: [new LatitudeSpanProcessor(apiKey, projectSlug, processorOptions)],\n })\n\n provider.register()\n\n const ready = registerLatitudeInstrumentations({\n instrumentations,\n tracerProvider: provider,\n }).catch((err) => {\n console.warn(\"[Latitude] Failed to register instrumentations:\", err)\n })\n\n const shutdown = async (): Promise<void> => {\n await provider.shutdown()\n }\n\n const flush = async (): Promise<void> => {\n await provider.forceFlush()\n }\n\n const handleShutdown = async () => {\n try {\n await shutdown()\n } catch (err) {\n console.error(\"Error during Latitude Telemetry shutdown:\", err)\n }\n }\n\n if (!shutdownHandlersRegistered) {\n process.once(\"SIGTERM\", handleShutdown)\n process.once(\"SIGINT\", handleShutdown)\n shutdownHandlersRegistered = true\n }\n\n return {\n provider,\n flush,\n shutdown,\n ready,\n }\n}\n","import type { TracerProvider } from \"@opentelemetry/api\"\nimport { type Instrumentation, registerInstrumentations } from \"@opentelemetry/instrumentation\"\nimport { AnthropicInstrumentation } from \"@traceloop/instrumentation-anthropic\"\nimport { BedrockInstrumentation } from \"@traceloop/instrumentation-bedrock\"\nimport { CohereInstrumentation } from \"@traceloop/instrumentation-cohere\"\nimport { LangChainInstrumentation } from \"@traceloop/instrumentation-langchain\"\nimport { LlamaIndexInstrumentation } from \"@traceloop/instrumentation-llamaindex\"\nimport { OpenAIInstrumentation } from \"@traceloop/instrumentation-openai\"\nimport { TogetherInstrumentation } from \"@traceloop/instrumentation-together\"\nimport { AIPlatformInstrumentation, VertexAIInstrumentation } from \"@traceloop/instrumentation-vertexai\"\n\n/**\n * Supported LLM instrumentation types.\n * Use these string identifiers to enable auto-instrumentation.\n */\nexport type InstrumentationType =\n | \"openai\"\n | \"anthropic\"\n | \"bedrock\"\n | \"cohere\"\n | \"langchain\"\n | \"llamaindex\"\n | \"togetherai\"\n | \"vertexai\"\n | \"aiplatform\"\n\n/**\n * Minimal interface for LLM instrumentation instances.\n * Extends OpenTelemetry's Instrumentation interface.\n */\ninterface LlmInstrumentation extends Instrumentation {\n manuallyInstrument?(module: unknown): void\n}\n\n/**\n * Options for creating LLM instrumentations.\n */\ninterface CreateInstrumentationsOptions {\n /** List of instrumentation types to enable. */\n instrumentations: InstrumentationType[]\n /**\n * Optional module references for auto-instrumentation.\n * If not provided, the instrumentation will attempt to require the module.\n * Used for Traceloop-based instrumentations.\n */\n modules?: Partial<Record<InstrumentationType, unknown>>\n /**\n * Per-instrumentation token enrichment settings.\n * @default { openai: true }\n */\n enrichTokens?: Partial<Record<InstrumentationType, boolean>>\n}\n\ninterface InstrumentationConfig {\n ctor: new (config?: Record<string, unknown>) => LlmInstrumentation\n moduleName: string\n defaultEnrichTokens?: boolean\n}\n\nconst INSTRUMENTATION_MAP: Record<InstrumentationType, InstrumentationConfig> = {\n openai: { ctor: OpenAIInstrumentation, moduleName: \"openai\", defaultEnrichTokens: true },\n anthropic: { ctor: AnthropicInstrumentation, moduleName: \"@anthropic-ai/sdk\" },\n bedrock: { ctor: BedrockInstrumentation, moduleName: \"@aws-sdk/client-bedrock-runtime\" },\n cohere: { ctor: CohereInstrumentation, moduleName: \"cohere-ai\" },\n langchain: { ctor: LangChainInstrumentation, moduleName: \"langchain\" },\n llamaindex: { ctor: LlamaIndexInstrumentation, moduleName: \"llamaindex\" },\n togetherai: { ctor: TogetherInstrumentation, moduleName: \"together-ai\", defaultEnrichTokens: false },\n vertexai: { ctor: VertexAIInstrumentation, moduleName: \"@google-cloud/vertexai\" },\n aiplatform: { ctor: AIPlatformInstrumentation, moduleName: \"@google-cloud/aiplatform\" },\n}\n\n/**\n * Internal function to create LLM instrumentation instances.\n * Not exported publicly - use registerLatitudeInstrumentations instead.\n */\nasync function createLatitudeInstrumentations(options: CreateInstrumentationsOptions): Promise<LlmInstrumentation[]> {\n const result: LlmInstrumentation[] = []\n\n for (const type of options.instrumentations) {\n const config = INSTRUMENTATION_MAP[type]\n if (!config) {\n console.warn(`[Latitude] Unknown instrumentation type: ${type}`)\n continue\n }\n\n const enrichTokens = options.enrichTokens?.[type] ?? config.defaultEnrichTokens\n const inst = new config.ctor(enrichTokens !== undefined ? { enrichTokens } : undefined)\n\n // Get module from explicit options or try to auto-require\n const moduleRef = options.modules?.[type] ?? (await tryRequire(config.moduleName))\n if (!moduleRef) {\n console.warn(\n `[Latitude] Module not found for ${type}: ${config.moduleName}. Install it or pass it explicitly in 'modules'.`,\n )\n continue\n }\n inst.manuallyInstrument?.(moduleRef)\n\n result.push(inst)\n }\n\n return result\n}\n\nasync function tryRequire(moduleName: string): Promise<unknown | undefined> {\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n return require(moduleName)\n } catch {\n // Fallback to dynamic import for ESM environments\n try {\n const mod = await import(moduleName)\n return mod.default ?? mod\n } catch {\n return undefined\n }\n }\n}\n\n/**\n * Registers LLM instrumentations with the global OpenTelemetry instrumentation registry.\n *\n * This is a convenience wrapper around `createLatitudeInstrumentations` and\n * `@opentelemetry/instrumentation`'s `registerInstrumentations`.\n *\n * @example\n * ```typescript\n * import { NodeTracerProvider } from \"@opentelemetry/sdk-trace-node\"\n * import { registerLatitudeInstrumentations, LatitudeSpanProcessor } from \"@latitude-data/telemetry\"\n *\n * const provider = new NodeTracerProvider({\n * spanProcessors: [new LatitudeSpanProcessor(apiKey, projectSlug)],\n * })\n *\n * await registerLatitudeInstrumentations({\n * instrumentations: [\"openai\", \"anthropic\"],\n * tracerProvider: provider,\n * })\n *\n * provider.register()\n * ```\n */\nexport async function registerLatitudeInstrumentations(\n options: CreateInstrumentationsOptions & { tracerProvider: TracerProvider },\n): Promise<void> {\n const instrumentations = await createLatitudeInstrumentations(options)\n registerInstrumentations({\n instrumentations,\n tracerProvider: options.tracerProvider,\n })\n}\n","import type { Context } from \"@opentelemetry/api\"\nimport { OTLPTraceExporter } from \"@opentelemetry/exporter-trace-otlp-http\"\nimport {\n BatchSpanProcessor,\n type ReadableSpan,\n SimpleSpanProcessor,\n type Span,\n type SpanProcessor,\n} from \"@opentelemetry/sdk-trace-node\"\nimport { ATTRIBUTES } from \"../constants/index.ts\"\nimport { env } from \"../env/index.ts\"\nimport { getLatitudeContext } from \"./context.ts\"\nimport { DEFAULT_REDACT_SPAN_PROCESSOR, RedactSpanProcessor } from \"./redact.ts\"\nimport {\n buildShouldExportSpanFromFields,\n ExportFilterSpanProcessor,\n RedactThenExportSpanProcessor,\n} from \"./span-filter.ts\"\nimport type { LatitudeSpanProcessorOptions } from \"./types.ts\"\n\nexport class LatitudeSpanProcessor implements SpanProcessor {\n private readonly tail: SpanProcessor\n\n constructor(apiKey: string, projectSlug: string, options?: LatitudeSpanProcessorOptions) {\n if (!apiKey || apiKey.trim() === \"\") {\n throw new Error(\"[Latitude] apiKey is required and cannot be empty\")\n }\n if (!projectSlug || projectSlug.trim() === \"\") {\n throw new Error(\"[Latitude] projectSlug is required and cannot be empty\")\n }\n\n const exporter =\n options?.exporter ??\n new OTLPTraceExporter({\n url: `${env.EXPORTER_URL}/v1/traces`,\n headers: {\n Authorization: `Bearer ${apiKey}`,\n \"Content-Type\": \"application/json\",\n \"X-Latitude-Project\": projectSlug,\n },\n timeoutMillis: 30_000,\n })\n\n const redact = options?.disableRedact\n ? null\n : options?.redact\n ? new RedactSpanProcessor(options.redact)\n : DEFAULT_REDACT_SPAN_PROCESSOR()\n\n const batchOrSimple = options?.disableBatch ? new SimpleSpanProcessor(exporter) : new BatchSpanProcessor(exporter)\n\n const shouldExport = buildShouldExportSpanFromFields({\n disableSmartFilter: options?.disableSmartFilter,\n shouldExportSpan: options?.shouldExportSpan,\n blockedInstrumentationScopes: options?.blockedInstrumentationScopes,\n })\n\n const redactThenExport = new RedactThenExportSpanProcessor(redact, batchOrSimple)\n this.tail = new ExportFilterSpanProcessor(shouldExport, redactThenExport)\n }\n\n onStart(span: Span, parentContext: Context): void {\n const latitudeData = getLatitudeContext(parentContext)\n\n if (latitudeData) {\n if (latitudeData.name) {\n span.setAttribute(ATTRIBUTES.name, latitudeData.name)\n // Only update span name for the capture root span (has latitude.capture.root attr)\n // Child spans keep their original names (database.query, business.validate, etc.)\n if (span.attributes[\"latitude.capture.root\"]) {\n span.updateName(latitudeData.name)\n }\n }\n if (latitudeData.tags && latitudeData.tags.length > 0) {\n span.setAttribute(ATTRIBUTES.tags, JSON.stringify(latitudeData.tags))\n }\n if (latitudeData.metadata && Object.keys(latitudeData.metadata).length > 0) {\n span.setAttribute(ATTRIBUTES.metadata, JSON.stringify(latitudeData.metadata))\n }\n if (latitudeData.sessionId) {\n span.setAttribute(ATTRIBUTES.sessionId, latitudeData.sessionId)\n }\n if (latitudeData.userId) {\n span.setAttribute(ATTRIBUTES.userId, latitudeData.userId)\n }\n }\n\n this.tail.onStart(span, parentContext)\n }\n\n onEnd(span: ReadableSpan): void {\n this.tail.onEnd(span)\n }\n\n async forceFlush(): Promise<void> {\n await this.tail.forceFlush()\n }\n\n async shutdown(): Promise<void> {\n await this.tail.shutdown()\n }\n}\n","export const ATTRIBUTES = {\n name: \"latitude.capture.name\",\n tags: \"latitude.tags\",\n metadata: \"latitude.metadata\",\n sessionId: \"session.id\",\n userId: \"user.id\",\n} as const\n","export const SCOPE_LATITUDE = \"so.latitude.instrumentation\"\n\nexport enum InstrumentationScope {\n Manual = \"manual\",\n OpenAI = \"openai\",\n Anthropic = \"anthropic\",\n AzureOpenAI = \"azure\",\n VercelAI = \"vercelai\",\n VertexAI = \"vertexai\",\n AIPlatform = \"aiplatform\",\n MistralAI = \"mistralai\",\n Bedrock = \"bedrock\",\n Sagemaker = \"sagemaker\",\n TogetherAI = \"togetherai\",\n Replicate = \"replicate\",\n Groq = \"groq\",\n Cohere = \"cohere\",\n LiteLLM = \"litellm\",\n Langchain = \"langchain\",\n LlamaIndex = \"llamaindex\",\n DSPy = \"dspy\",\n Haystack = \"haystack\",\n Ollama = \"ollama\",\n Transformers = \"transformers\",\n AlephAlpha = \"alephalpha\",\n}\n","const DEFAULT_EXPORTER_URL =\n {\n production: \"https://ingest.latitude.so\",\n development: \"http://localhost:3002\",\n test: \"http://localhost:3002\",\n }[process.env.NODE_ENV ?? \"development\"] ?? \"http://localhost:3002\"\n\nfunction getExporterUrl() {\n if (process.env.LATITUDE_TELEMETRY_URL) {\n return process.env.LATITUDE_TELEMETRY_URL\n }\n\n return DEFAULT_EXPORTER_URL\n}\n\nexport const env = { EXPORTER_URL: getExporterUrl() } as const\n","import type * as otel from \"@opentelemetry/api\"\nimport type { ReadableSpan, Span, SpanProcessor } from \"@opentelemetry/sdk-trace-node\"\n\nexport interface RedactSpanProcessorOptions {\n attributes: (string | RegExp)[]\n mask?: (attribute: string, value: unknown) => string\n}\n\nexport class RedactSpanProcessor implements SpanProcessor {\n private options: RedactSpanProcessorOptions\n\n constructor(options: RedactSpanProcessorOptions) {\n this.options = options\n\n if (!options.mask) {\n this.options.mask = (_attribute: string, _value: unknown) => \"******\"\n }\n }\n\n onStart(_span: Span, _context: otel.Context): void {\n // Noop\n }\n\n onEnd(span: ReadableSpan): void {\n Object.assign(span.attributes, this.redactAttributes(span.attributes))\n for (const event of span.events) {\n if (!event.attributes) continue\n Object.assign(event.attributes, this.redactAttributes(event.attributes))\n }\n for (const link of span.links) {\n if (!link.attributes) continue\n Object.assign(link.attributes, this.redactAttributes(link.attributes))\n }\n }\n\n forceFlush(): Promise<void> {\n return Promise.resolve()\n }\n\n shutdown(): Promise<void> {\n return Promise.resolve()\n }\n\n private shouldRedact(attribute: string) {\n return this.options.attributes.some((pattern) => {\n if (typeof pattern === \"string\") {\n return attribute === pattern\n } else if (pattern instanceof RegExp) {\n return pattern.test(attribute)\n }\n return false\n })\n }\n\n private redactAttributes(attributes: otel.Attributes) {\n const redacted: otel.Attributes = {}\n\n for (const [key, value] of Object.entries(attributes)) {\n if (this.shouldRedact(key)) {\n redacted[key] = this.options.mask?.(key, value)\n }\n }\n\n return redacted\n }\n}\n\nexport const DEFAULT_REDACT_SPAN_PROCESSOR = () =>\n new RedactSpanProcessor({\n attributes: [\n // HTTP security headers\n /^http\\.request\\.header\\.authorization$/i,\n /^http\\.request\\.header\\.cookie$/i,\n /^http\\.request\\.header\\.x[-_]api[-_]key$/i,\n // Database statements may contain sensitive data\n /^db\\.statement$/i,\n ],\n })\n","import type { Context } from \"@opentelemetry/api\"\nimport type { ReadableSpan, Span, SpanProcessor } from \"@opentelemetry/sdk-trace-node\"\nimport { SCOPE_LATITUDE } from \"../constants/scope.ts\"\n\n/** OpenTelemetry GenAI semantic convention attribute prefix. */\nconst GEN_AI_PREFIX = \"gen_ai.\"\n\n/** Legacy / OpenInference-style LLM attribute prefix. */\nconst LLM_PREFIX = \"llm.\"\n\nconst OPENINFERENCE_KIND = \"openinference.span.kind\"\n\n/** OTel Python instrumentation scope prefixes for LLM-related instrumentors we support. */\nconst OTEL_LLM_INSTRUMENTATION_SCOPE_PREFIXES = [\n \"opentelemetry.instrumentation.alephalpha\",\n \"opentelemetry.instrumentation.anthropic\",\n \"opentelemetry.instrumentation.bedrock\",\n \"opentelemetry.instrumentation.cohere\",\n \"opentelemetry.instrumentation.crewai\",\n \"opentelemetry.instrumentation.google_generativeai\",\n \"opentelemetry.instrumentation.groq\",\n \"opentelemetry.instrumentation.haystack\",\n \"opentelemetry.instrumentation.langchain\",\n \"opentelemetry.instrumentation.llamaindex\",\n \"opentelemetry.instrumentation.mistralai\",\n \"opentelemetry.instrumentation.ollama\",\n \"opentelemetry.instrumentation.openai\",\n \"opentelemetry.instrumentation.replicate\",\n \"opentelemetry.instrumentation.sagemaker\",\n \"opentelemetry.instrumentation.together\",\n \"opentelemetry.instrumentation.transformers\",\n \"opentelemetry.instrumentation.vertexai\",\n \"opentelemetry.instrumentation.watsonx\",\n \"openinference.instrumentation\",\n] as const\n\n/** Substrings in scope names that indicate LLM / GenAI instrumentation (e.g. Traceloop JS). */\nconst LLM_SCOPE_SUBSTRINGS = [\"openinference\", \"traceloop\", \"langsmith\", \"litellm\"] as const\n\nexport type SmartFilterOptions = {\n /**\n * When true, all spans are exported (legacy behavior).\n * Default false — only LLM-relevant spans are exported.\n */\n disableSmartFilter?: boolean\n /**\n * When smart filter is on, also export spans for which this returns true\n * (in addition to {@link isDefaultExportSpan}).\n */\n shouldExportSpan?: (span: ReadableSpan) => boolean\n /** Instrumentation scope names to drop (exact match) even if they pass the default predicate. */\n blockedInstrumentationScopes?: string[]\n}\n\n/** Input for {@link buildShouldExportSpanFromFields}; allows `undefined` field values for ergonomics. */\nexport type SmartFilterFieldsInput = {\n disableSmartFilter?: boolean | undefined\n shouldExportSpan?: ((span: ReadableSpan) => boolean) | undefined\n blockedInstrumentationScopes?: string[] | undefined\n}\n\n/**\n * Builds the export predicate from loose option fields (`exactOptionalPropertyTypes`-safe call sites).\n */\nexport function buildShouldExportSpanFromFields(fields: SmartFilterFieldsInput): (span: ReadableSpan) => boolean {\n return buildShouldExportSpan({\n ...(fields.disableSmartFilter !== undefined ? { disableSmartFilter: fields.disableSmartFilter } : {}),\n ...(fields.shouldExportSpan !== undefined ? { shouldExportSpan: fields.shouldExportSpan } : {}),\n ...(fields.blockedInstrumentationScopes !== undefined\n ? { blockedInstrumentationScopes: fields.blockedInstrumentationScopes }\n : {}),\n })\n}\n\nfunction attributeKeys(span: ReadableSpan): string[] {\n const attrs = span.attributes\n if (!attrs || typeof attrs !== \"object\") return []\n return Object.keys(attrs as Record<string, unknown>)\n}\n\nfunction instrumentationScopeName(span: ReadableSpan): string {\n return span.instrumentationLibrary?.name ?? \"\"\n}\n\n/** True if the span uses OpenTelemetry GenAI semantic conventions or common LLM attribute namespaces. */\nexport function isGenAiOrLlmAttributeSpan(span: ReadableSpan): boolean {\n for (const key of attributeKeys(span)) {\n if (key.startsWith(GEN_AI_PREFIX) || key.startsWith(LLM_PREFIX)) return true\n if (key === OPENINFERENCE_KIND || key.startsWith(\"openinference.\")) return true\n // Vercel AI SDK uses ai.* prefix\n if (key.startsWith(\"ai.\")) return true\n // Latitude context attributes\n if (key.startsWith(\"latitude.\")) return true\n }\n return false\n}\n\n/** True if the span was created with Latitude's tracer scopes. */\nexport function isLatitudeInstrumentationSpan(span: ReadableSpan): boolean {\n const name = instrumentationScopeName(span)\n return name === SCOPE_LATITUDE || name.startsWith(`${SCOPE_LATITUDE}.`)\n}\n\nfunction isKnownLlmInstrumentationScope(span: ReadableSpan): boolean {\n const name = instrumentationScopeName(span)\n if (!name) return false\n for (const prefix of OTEL_LLM_INSTRUMENTATION_SCOPE_PREFIXES) {\n if (name === prefix || name.startsWith(`${prefix}.`)) return true\n }\n const lower = name.toLowerCase()\n for (const part of LLM_SCOPE_SUBSTRINGS) {\n if (lower.includes(part)) return true\n }\n return false\n}\n\n/**\n * Default export predicate (smart filter): Latitude scopes, GenAI / LLM attributes,\n * or known LLM instrumentation scopes.\n */\nexport function isDefaultExportSpan(span: ReadableSpan): boolean {\n if (isLatitudeInstrumentationSpan(span)) return true\n if (isGenAiOrLlmAttributeSpan(span)) return true\n if (isKnownLlmInstrumentationScope(span)) return true\n return false\n}\n\nexport function buildShouldExportSpan(options: SmartFilterOptions): (span: ReadableSpan) => boolean {\n if (options.disableSmartFilter) return () => true\n const blocked = new Set(options.blockedInstrumentationScopes ?? [])\n const extra = options.shouldExportSpan\n return (span: ReadableSpan) => {\n const scope = instrumentationScopeName(span)\n if (blocked.has(scope)) return false\n if (isDefaultExportSpan(span)) return true\n if (extra?.(span)) return true\n return false\n }\n}\n\n/**\n * Drops spans that fail the export predicate before passing them to the inner processor.\n * Inner processor should perform redaction and export.\n */\nexport class ExportFilterSpanProcessor implements SpanProcessor {\n private readonly shouldExport: (span: ReadableSpan) => boolean\n private readonly inner: SpanProcessor\n\n constructor(shouldExport: (span: ReadableSpan) => boolean, inner: SpanProcessor) {\n this.shouldExport = shouldExport\n this.inner = inner\n }\n\n onStart(span: Span, parentContext: Context): void {\n this.inner.onStart(span, parentContext)\n }\n\n onEnd(span: ReadableSpan): void {\n if (!this.shouldExport(span)) return\n this.inner.onEnd(span)\n }\n\n forceFlush(): Promise<void> {\n return this.inner.forceFlush()\n }\n\n shutdown(): Promise<void> {\n return this.inner.shutdown()\n }\n}\n\n/** Runs optional redaction then the export processor (batch/simple). */\nexport class RedactThenExportSpanProcessor implements SpanProcessor {\n private readonly redact: SpanProcessor | null\n private readonly exportProcessor: SpanProcessor\n\n constructor(redact: SpanProcessor | null, exportProcessor: SpanProcessor) {\n this.redact = redact\n this.exportProcessor = exportProcessor\n }\n\n onStart(span: Span, parentContext: Context): void {\n this.redact?.onStart(span, parentContext)\n this.exportProcessor.onStart(span, parentContext)\n }\n\n onEnd(span: ReadableSpan): void {\n this.redact?.onEnd(span)\n this.exportProcessor.onEnd(span)\n }\n\n forceFlush(): Promise<void> {\n return this.exportProcessor.forceFlush()\n }\n\n shutdown(): Promise<void> {\n return this.exportProcessor.shutdown()\n }\n}\n"],"mappings":"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","names":["context","context"]}
|
|
1
|
+
{"version":3,"sources":["../src/sdk/context.ts","../src/sdk/init.ts","../src/sdk/instrumentations.ts","../src/sdk/processor.ts","../src/constants/attributes.ts","../src/constants/scope.ts","../src/env/env.ts","../src/sdk/redact.ts","../src/sdk/span-filter.ts"],"sourcesContent":["import { type Context, context, createContextKey, trace } from \"@opentelemetry/api\"\nimport type { ContextOptions } from \"./types.ts\"\n\nexport const LATITUDE_CONTEXT_KEY = createContextKey(\"latitude-internal-context\")\nconst CAPTURE_TRACER_NAME = \"so.latitude.instrumentation.capture\"\n\ntype LatitudeContextData = {\n name: string | undefined\n tags: string[] | undefined\n metadata: Record<string, unknown> | undefined\n sessionId: string | undefined\n userId: string | undefined\n}\n\nexport function getLatitudeContext(ctx: Context): LatitudeContextData | undefined {\n return ctx.getValue(LATITUDE_CONTEXT_KEY) as LatitudeContextData | undefined\n}\n\nfunction mergeArrays<T>(a: T[] | undefined, b: T[] | undefined): T[] | undefined {\n if (!a && !b) return undefined\n if (!a) return b\n if (!b) return a\n return [...new Set([...a, ...b])]\n}\n\nexport function capture<T>(name: string, fn: () => T | Promise<T>, options: ContextOptions = {}): T | Promise<T> {\n const currentContext = context.active()\n const existingData = getLatitudeContext(currentContext)\n\n const mergedData: LatitudeContextData = {\n name: options.name ?? name,\n tags: mergeArrays(existingData?.tags, options.tags),\n metadata: { ...existingData?.metadata, ...options.metadata },\n sessionId: options.sessionId ?? existingData?.sessionId,\n userId: options.userId ?? existingData?.userId,\n }\n\n const newContext = currentContext.setValue(LATITUDE_CONTEXT_KEY, mergedData)\n const existingSpan = trace.getSpan(currentContext)\n\n if (existingSpan) {\n return context.with(newContext, fn)\n }\n\n const tracer = trace.getTracer(CAPTURE_TRACER_NAME)\n\n return tracer.startActiveSpan(name, { attributes: { \"latitude.capture.root\": true } }, newContext, (span) => {\n let result: T | Promise<T>\n try {\n result = fn()\n } catch (error) {\n span.recordException(error as Error)\n span.end()\n throw error\n }\n\n if (result instanceof Promise) {\n return result\n .catch((error) => {\n span.recordException(error as Error)\n throw error\n })\n .finally(() => {\n span.end()\n }) as T | Promise<T>\n }\n\n span.end()\n return result\n })\n}\n","import { context, propagation } from \"@opentelemetry/api\"\nimport { AsyncLocalStorageContextManager } from \"@opentelemetry/context-async-hooks\"\nimport { CompositePropagator, W3CBaggagePropagator, W3CTraceContextPropagator } from \"@opentelemetry/core\"\nimport { resourceFromAttributes } from \"@opentelemetry/resources\"\nimport { NodeTracerProvider } from \"@opentelemetry/sdk-trace-node\"\nimport { ATTR_SERVICE_NAME } from \"@opentelemetry/semantic-conventions\"\nimport { registerLatitudeInstrumentations } from \"./instrumentations.ts\"\nimport { LatitudeSpanProcessor } from \"./processor.ts\"\nimport type { InitLatitudeOptions } from \"./types.ts\"\n\nconst SERVICE_NAME = process.env.npm_package_name || \"unknown\"\n\n/** Module-level flag to prevent duplicate signal handler registration on repeated initLatitude calls */\nlet shutdownHandlersRegistered = false\n\nexport function initLatitude(options: InitLatitudeOptions): {\n provider: NodeTracerProvider\n flush: () => Promise<void>\n shutdown: () => Promise<void>\n ready: Promise<void>\n} {\n const { apiKey, projectSlug, instrumentations = [], ...processorOptions } = options\n\n if (!apiKey || apiKey.trim() === \"\") {\n throw new Error(\"[Latitude] apiKey is required and cannot be empty\")\n }\n if (!projectSlug || projectSlug.trim() === \"\") {\n throw new Error(\"[Latitude] projectSlug is required and cannot be empty\")\n }\n\n const contextManager = new AsyncLocalStorageContextManager()\n contextManager.enable()\n\n const propagator = new CompositePropagator({\n propagators: [new W3CTraceContextPropagator(), new W3CBaggagePropagator()],\n })\n\n context.setGlobalContextManager(contextManager)\n propagation.setGlobalPropagator(propagator)\n\n const resourceServiceName =\n typeof processorOptions.serviceName === \"string\" && processorOptions.serviceName.trim() !== \"\"\n ? processorOptions.serviceName.trim()\n : SERVICE_NAME\n\n const provider = new NodeTracerProvider({\n resource: resourceFromAttributes({\n [ATTR_SERVICE_NAME]: resourceServiceName,\n }),\n spanProcessors: [new LatitudeSpanProcessor(apiKey, projectSlug, processorOptions)],\n })\n\n provider.register()\n\n const ready = registerLatitudeInstrumentations({\n instrumentations,\n tracerProvider: provider,\n }).catch((err) => {\n console.warn(\"[Latitude] Failed to register instrumentations:\", err)\n })\n\n const shutdown = async (): Promise<void> => {\n await provider.shutdown()\n }\n\n const flush = async (): Promise<void> => {\n await provider.forceFlush()\n }\n\n const handleShutdown = async () => {\n try {\n await shutdown()\n } catch (err) {\n console.error(\"Error during Latitude Telemetry shutdown:\", err)\n }\n }\n\n if (!shutdownHandlersRegistered) {\n process.once(\"SIGTERM\", handleShutdown)\n process.once(\"SIGINT\", handleShutdown)\n shutdownHandlersRegistered = true\n }\n\n return {\n provider,\n flush,\n shutdown,\n ready,\n }\n}\n","import type { TracerProvider } from \"@opentelemetry/api\"\nimport { type Instrumentation, registerInstrumentations } from \"@opentelemetry/instrumentation\"\nimport { AnthropicInstrumentation } from \"@traceloop/instrumentation-anthropic\"\nimport { BedrockInstrumentation } from \"@traceloop/instrumentation-bedrock\"\nimport { CohereInstrumentation } from \"@traceloop/instrumentation-cohere\"\nimport { LangChainInstrumentation } from \"@traceloop/instrumentation-langchain\"\nimport { LlamaIndexInstrumentation } from \"@traceloop/instrumentation-llamaindex\"\nimport { OpenAIInstrumentation } from \"@traceloop/instrumentation-openai\"\nimport { TogetherInstrumentation } from \"@traceloop/instrumentation-together\"\nimport { AIPlatformInstrumentation, VertexAIInstrumentation } from \"@traceloop/instrumentation-vertexai\"\n\n/**\n * Supported LLM instrumentation types.\n * Use these string identifiers to enable auto-instrumentation.\n */\nexport type InstrumentationType =\n | \"openai\"\n | \"anthropic\"\n | \"bedrock\"\n | \"cohere\"\n | \"langchain\"\n | \"llamaindex\"\n | \"togetherai\"\n | \"vertexai\"\n | \"aiplatform\"\n\n/**\n * Minimal interface for LLM instrumentation instances.\n * Extends OpenTelemetry's Instrumentation interface.\n */\ninterface LlmInstrumentation extends Instrumentation {\n manuallyInstrument?(module: unknown): void\n}\n\n/**\n * Options for creating LLM instrumentations.\n */\ninterface CreateInstrumentationsOptions {\n /** List of instrumentation types to enable. */\n instrumentations: InstrumentationType[]\n /**\n * Optional module references for auto-instrumentation.\n * If not provided, the instrumentation will attempt to require the module.\n * Used for Traceloop-based instrumentations.\n */\n modules?: Partial<Record<InstrumentationType, unknown>>\n /**\n * Per-instrumentation token enrichment settings.\n * @default { openai: true }\n */\n enrichTokens?: Partial<Record<InstrumentationType, boolean>>\n}\n\ninterface InstrumentationConfig {\n ctor: new (config?: Record<string, unknown>) => LlmInstrumentation\n moduleName: string\n defaultEnrichTokens?: boolean\n}\n\nconst INSTRUMENTATION_MAP: Record<InstrumentationType, InstrumentationConfig> = {\n openai: { ctor: OpenAIInstrumentation, moduleName: \"openai\", defaultEnrichTokens: true },\n anthropic: { ctor: AnthropicInstrumentation, moduleName: \"@anthropic-ai/sdk\" },\n bedrock: { ctor: BedrockInstrumentation, moduleName: \"@aws-sdk/client-bedrock-runtime\" },\n cohere: { ctor: CohereInstrumentation, moduleName: \"cohere-ai\" },\n langchain: { ctor: LangChainInstrumentation, moduleName: \"langchain\" },\n llamaindex: { ctor: LlamaIndexInstrumentation, moduleName: \"llamaindex\" },\n togetherai: { ctor: TogetherInstrumentation, moduleName: \"together-ai\", defaultEnrichTokens: false },\n vertexai: { ctor: VertexAIInstrumentation, moduleName: \"@google-cloud/vertexai\" },\n aiplatform: { ctor: AIPlatformInstrumentation, moduleName: \"@google-cloud/aiplatform\" },\n}\n\n/**\n * Internal function to create LLM instrumentation instances.\n * Not exported publicly - use registerLatitudeInstrumentations instead.\n */\nasync function createLatitudeInstrumentations(options: CreateInstrumentationsOptions): Promise<LlmInstrumentation[]> {\n const result: LlmInstrumentation[] = []\n\n for (const type of options.instrumentations) {\n const config = INSTRUMENTATION_MAP[type]\n if (!config) {\n console.warn(`[Latitude] Unknown instrumentation type: ${type}`)\n continue\n }\n\n const enrichTokens = options.enrichTokens?.[type] ?? config.defaultEnrichTokens\n const inst = new config.ctor(enrichTokens !== undefined ? { enrichTokens } : undefined)\n\n // Get module from explicit options or try to auto-require\n const moduleRef = options.modules?.[type] ?? (await tryRequire(config.moduleName))\n if (!moduleRef) {\n console.warn(\n `[Latitude] Module not found for ${type}: ${config.moduleName}. Install it or pass it explicitly in 'modules'.`,\n )\n continue\n }\n inst.manuallyInstrument?.(moduleRef)\n\n result.push(inst)\n }\n\n return result\n}\n\nasync function tryRequire(moduleName: string): Promise<unknown | undefined> {\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n return require(moduleName)\n } catch {\n // Fallback to dynamic import for ESM environments\n try {\n const mod = await import(moduleName)\n return mod.default ?? mod\n } catch {\n return undefined\n }\n }\n}\n\n/**\n * Registers LLM instrumentations with the global OpenTelemetry instrumentation registry.\n *\n * This is a convenience wrapper around `createLatitudeInstrumentations` and\n * `@opentelemetry/instrumentation`'s `registerInstrumentations`.\n *\n * @example\n * ```typescript\n * import { NodeTracerProvider } from \"@opentelemetry/sdk-trace-node\"\n * import { registerLatitudeInstrumentations, LatitudeSpanProcessor } from \"@latitude-data/telemetry\"\n *\n * const provider = new NodeTracerProvider({\n * spanProcessors: [new LatitudeSpanProcessor(apiKey, projectSlug)],\n * })\n *\n * await registerLatitudeInstrumentations({\n * instrumentations: [\"openai\", \"anthropic\"],\n * tracerProvider: provider,\n * })\n *\n * provider.register()\n * ```\n */\nexport async function registerLatitudeInstrumentations(\n options: CreateInstrumentationsOptions & { tracerProvider: TracerProvider },\n): Promise<void> {\n const instrumentations = await createLatitudeInstrumentations(options)\n registerInstrumentations({\n instrumentations,\n tracerProvider: options.tracerProvider,\n })\n}\n","import type { Context } from \"@opentelemetry/api\"\nimport { OTLPTraceExporter } from \"@opentelemetry/exporter-trace-otlp-http\"\nimport {\n BatchSpanProcessor,\n type ReadableSpan,\n SimpleSpanProcessor,\n type Span,\n type SpanProcessor,\n} from \"@opentelemetry/sdk-trace-node\"\nimport { ATTR_SERVICE_NAME } from \"@opentelemetry/semantic-conventions\"\nimport { ATTRIBUTES } from \"../constants/index.ts\"\nimport { env } from \"../env/index.ts\"\nimport { getLatitudeContext } from \"./context.ts\"\nimport { DEFAULT_REDACT_SPAN_PROCESSOR, RedactSpanProcessor } from \"./redact.ts\"\nimport {\n buildShouldExportSpanFromFields,\n ExportFilterSpanProcessor,\n RedactThenExportSpanProcessor,\n} from \"./span-filter.ts\"\nimport type { LatitudeSpanProcessorOptions } from \"./types.ts\"\n\nexport class LatitudeSpanProcessor implements SpanProcessor {\n private readonly tail: SpanProcessor\n private readonly serviceName: string | undefined\n\n constructor(apiKey: string, projectSlug: string, options?: LatitudeSpanProcessorOptions) {\n if (!apiKey || apiKey.trim() === \"\") {\n throw new Error(\"[Latitude] apiKey is required and cannot be empty\")\n }\n if (!projectSlug || projectSlug.trim() === \"\") {\n throw new Error(\"[Latitude] projectSlug is required and cannot be empty\")\n }\n\n const exporter =\n options?.exporter ??\n new OTLPTraceExporter({\n url: `${env.EXPORTER_URL}/v1/traces`,\n headers: {\n Authorization: `Bearer ${apiKey}`,\n \"Content-Type\": \"application/json\",\n \"X-Latitude-Project\": projectSlug,\n },\n timeoutMillis: 30_000,\n })\n\n const redact = options?.disableRedact\n ? null\n : options?.redact\n ? new RedactSpanProcessor(options.redact)\n : DEFAULT_REDACT_SPAN_PROCESSOR()\n\n const batchOrSimple = options?.disableBatch ? new SimpleSpanProcessor(exporter) : new BatchSpanProcessor(exporter)\n\n const shouldExport = buildShouldExportSpanFromFields({\n disableSmartFilter: options?.disableSmartFilter,\n shouldExportSpan: options?.shouldExportSpan,\n blockedInstrumentationScopes: options?.blockedInstrumentationScopes,\n })\n\n const redactThenExport = new RedactThenExportSpanProcessor(redact, batchOrSimple)\n this.tail = new ExportFilterSpanProcessor(shouldExport, redactThenExport)\n\n const rawServiceName = options?.serviceName?.trim()\n this.serviceName = rawServiceName === \"\" ? undefined : rawServiceName\n }\n\n onStart(span: Span, parentContext: Context): void {\n if (this.serviceName !== undefined) {\n span.setAttribute(ATTR_SERVICE_NAME, this.serviceName)\n }\n\n const latitudeData = getLatitudeContext(parentContext)\n\n if (latitudeData) {\n if (latitudeData.name) {\n span.setAttribute(ATTRIBUTES.name, latitudeData.name)\n // Only update span name for the capture root span (has latitude.capture.root attr)\n // Child spans keep their original names (database.query, business.validate, etc.)\n if (span.attributes[\"latitude.capture.root\"]) {\n span.updateName(latitudeData.name)\n }\n }\n if (latitudeData.tags && latitudeData.tags.length > 0) {\n span.setAttribute(ATTRIBUTES.tags, JSON.stringify(latitudeData.tags))\n }\n if (latitudeData.metadata && Object.keys(latitudeData.metadata).length > 0) {\n span.setAttribute(ATTRIBUTES.metadata, JSON.stringify(latitudeData.metadata))\n }\n if (latitudeData.sessionId) {\n span.setAttribute(ATTRIBUTES.sessionId, latitudeData.sessionId)\n }\n if (latitudeData.userId) {\n span.setAttribute(ATTRIBUTES.userId, latitudeData.userId)\n }\n }\n\n this.tail.onStart(span, parentContext)\n }\n\n onEnd(span: ReadableSpan): void {\n this.tail.onEnd(span)\n }\n\n async forceFlush(): Promise<void> {\n await this.tail.forceFlush()\n }\n\n async shutdown(): Promise<void> {\n await this.tail.shutdown()\n }\n}\n","export const ATTRIBUTES = {\n name: \"latitude.capture.name\",\n tags: \"latitude.tags\",\n metadata: \"latitude.metadata\",\n sessionId: \"session.id\",\n userId: \"user.id\",\n} as const\n","export const SCOPE_LATITUDE = \"so.latitude.instrumentation\"\n\nexport enum InstrumentationScope {\n Manual = \"manual\",\n OpenAI = \"openai\",\n Anthropic = \"anthropic\",\n AzureOpenAI = \"azure\",\n VercelAI = \"vercelai\",\n VertexAI = \"vertexai\",\n AIPlatform = \"aiplatform\",\n MistralAI = \"mistralai\",\n Bedrock = \"bedrock\",\n Sagemaker = \"sagemaker\",\n TogetherAI = \"togetherai\",\n Replicate = \"replicate\",\n Groq = \"groq\",\n Cohere = \"cohere\",\n LiteLLM = \"litellm\",\n Langchain = \"langchain\",\n LlamaIndex = \"llamaindex\",\n DSPy = \"dspy\",\n Haystack = \"haystack\",\n Ollama = \"ollama\",\n Transformers = \"transformers\",\n AlephAlpha = \"alephalpha\",\n}\n","const DEFAULT_EXPORTER_URL =\n {\n production: \"https://ingest.latitude.so\",\n development: \"http://localhost:3002\",\n test: \"http://localhost:3002\",\n }[process.env.NODE_ENV ?? \"development\"] ?? \"http://localhost:3002\"\n\nfunction getExporterUrl() {\n if (process.env.LATITUDE_TELEMETRY_URL) {\n return process.env.LATITUDE_TELEMETRY_URL\n }\n\n return DEFAULT_EXPORTER_URL\n}\n\nexport const env = { EXPORTER_URL: getExporterUrl() } as const\n","import type * as otel from \"@opentelemetry/api\"\nimport type { ReadableSpan, Span, SpanProcessor } from \"@opentelemetry/sdk-trace-node\"\n\nexport interface RedactSpanProcessorOptions {\n attributes: (string | RegExp)[]\n mask?: (attribute: string, value: unknown) => string\n}\n\nexport class RedactSpanProcessor implements SpanProcessor {\n private options: RedactSpanProcessorOptions\n\n constructor(options: RedactSpanProcessorOptions) {\n this.options = options\n\n if (!options.mask) {\n this.options.mask = (_attribute: string, _value: unknown) => \"******\"\n }\n }\n\n onStart(_span: Span, _context: otel.Context): void {\n // Noop\n }\n\n onEnd(span: ReadableSpan): void {\n Object.assign(span.attributes, this.redactAttributes(span.attributes))\n for (const event of span.events) {\n if (!event.attributes) continue\n Object.assign(event.attributes, this.redactAttributes(event.attributes))\n }\n for (const link of span.links) {\n if (!link.attributes) continue\n Object.assign(link.attributes, this.redactAttributes(link.attributes))\n }\n }\n\n forceFlush(): Promise<void> {\n return Promise.resolve()\n }\n\n shutdown(): Promise<void> {\n return Promise.resolve()\n }\n\n private shouldRedact(attribute: string) {\n return this.options.attributes.some((pattern) => {\n if (typeof pattern === \"string\") {\n return attribute === pattern\n } else if (pattern instanceof RegExp) {\n return pattern.test(attribute)\n }\n return false\n })\n }\n\n private redactAttributes(attributes: otel.Attributes) {\n const redacted: otel.Attributes = {}\n\n for (const [key, value] of Object.entries(attributes)) {\n if (this.shouldRedact(key)) {\n redacted[key] = this.options.mask?.(key, value)\n }\n }\n\n return redacted\n }\n}\n\nexport const DEFAULT_REDACT_SPAN_PROCESSOR = () =>\n new RedactSpanProcessor({\n attributes: [\n // HTTP security headers\n /^http\\.request\\.header\\.authorization$/i,\n /^http\\.request\\.header\\.cookie$/i,\n /^http\\.request\\.header\\.x[-_]api[-_]key$/i,\n // Database statements may contain sensitive data\n /^db\\.statement$/i,\n ],\n })\n","import type { Context } from \"@opentelemetry/api\"\nimport type { ReadableSpan, Span, SpanProcessor } from \"@opentelemetry/sdk-trace-node\"\nimport { SCOPE_LATITUDE } from \"../constants/scope.ts\"\n\n/** OpenTelemetry GenAI semantic convention attribute prefix. */\nconst GEN_AI_PREFIX = \"gen_ai.\"\n\n/** Legacy / OpenInference-style LLM attribute prefix. */\nconst LLM_PREFIX = \"llm.\"\n\nconst OPENINFERENCE_KIND = \"openinference.span.kind\"\n\n/** OTel Python instrumentation scope prefixes for LLM-related instrumentors we support. */\nconst OTEL_LLM_INSTRUMENTATION_SCOPE_PREFIXES = [\n \"opentelemetry.instrumentation.alephalpha\",\n \"opentelemetry.instrumentation.anthropic\",\n \"opentelemetry.instrumentation.bedrock\",\n \"opentelemetry.instrumentation.cohere\",\n \"opentelemetry.instrumentation.crewai\",\n \"opentelemetry.instrumentation.google_generativeai\",\n \"opentelemetry.instrumentation.groq\",\n \"opentelemetry.instrumentation.haystack\",\n \"opentelemetry.instrumentation.langchain\",\n \"opentelemetry.instrumentation.llamaindex\",\n \"opentelemetry.instrumentation.mistralai\",\n \"opentelemetry.instrumentation.ollama\",\n \"opentelemetry.instrumentation.openai\",\n \"opentelemetry.instrumentation.replicate\",\n \"opentelemetry.instrumentation.sagemaker\",\n \"opentelemetry.instrumentation.together\",\n \"opentelemetry.instrumentation.transformers\",\n \"opentelemetry.instrumentation.vertexai\",\n \"opentelemetry.instrumentation.watsonx\",\n \"openinference.instrumentation\",\n] as const\n\n/** Substrings in scope names that indicate LLM / GenAI instrumentation (e.g. Traceloop JS). */\nconst LLM_SCOPE_SUBSTRINGS = [\"openinference\", \"traceloop\", \"langsmith\", \"litellm\"] as const\n\nexport type SmartFilterOptions = {\n /**\n * When true, all spans are exported (legacy behavior).\n * Default false — only LLM-relevant spans are exported.\n */\n disableSmartFilter?: boolean\n /**\n * When smart filter is on, also export spans for which this returns true\n * (in addition to {@link isDefaultExportSpan}).\n */\n shouldExportSpan?: (span: ReadableSpan) => boolean\n /** Instrumentation scope names to drop (exact match) even if they pass the default predicate. */\n blockedInstrumentationScopes?: string[]\n}\n\n/** Input for {@link buildShouldExportSpanFromFields}; allows `undefined` field values for ergonomics. */\nexport type SmartFilterFieldsInput = {\n disableSmartFilter?: boolean | undefined\n shouldExportSpan?: ((span: ReadableSpan) => boolean) | undefined\n blockedInstrumentationScopes?: string[] | undefined\n}\n\n/**\n * Builds the export predicate from loose option fields (`exactOptionalPropertyTypes`-safe call sites).\n */\nexport function buildShouldExportSpanFromFields(fields: SmartFilterFieldsInput): (span: ReadableSpan) => boolean {\n return buildShouldExportSpan({\n ...(fields.disableSmartFilter !== undefined ? { disableSmartFilter: fields.disableSmartFilter } : {}),\n ...(fields.shouldExportSpan !== undefined ? { shouldExportSpan: fields.shouldExportSpan } : {}),\n ...(fields.blockedInstrumentationScopes !== undefined\n ? { blockedInstrumentationScopes: fields.blockedInstrumentationScopes }\n : {}),\n })\n}\n\nfunction attributeKeys(span: ReadableSpan): string[] {\n const attrs = span.attributes\n if (!attrs || typeof attrs !== \"object\") return []\n return Object.keys(attrs as Record<string, unknown>)\n}\n\nfunction instrumentationScopeName(span: ReadableSpan): string {\n return span.instrumentationScope?.name ?? \"\"\n}\n\n/** True if the span uses OpenTelemetry GenAI semantic conventions or common LLM attribute namespaces. */\nexport function isGenAiOrLlmAttributeSpan(span: ReadableSpan): boolean {\n for (const key of attributeKeys(span)) {\n if (key.startsWith(GEN_AI_PREFIX) || key.startsWith(LLM_PREFIX)) return true\n if (key === OPENINFERENCE_KIND || key.startsWith(\"openinference.\")) return true\n // Vercel AI SDK uses ai.* prefix\n if (key.startsWith(\"ai.\")) return true\n // Latitude context attributes\n if (key.startsWith(\"latitude.\")) return true\n }\n return false\n}\n\n/** True if the span was created with Latitude's tracer scopes. */\nexport function isLatitudeInstrumentationSpan(span: ReadableSpan): boolean {\n const name = instrumentationScopeName(span)\n return name === SCOPE_LATITUDE || name.startsWith(`${SCOPE_LATITUDE}.`)\n}\n\nfunction isKnownLlmInstrumentationScope(span: ReadableSpan): boolean {\n const name = instrumentationScopeName(span)\n if (!name) return false\n for (const prefix of OTEL_LLM_INSTRUMENTATION_SCOPE_PREFIXES) {\n if (name === prefix || name.startsWith(`${prefix}.`)) return true\n }\n const lower = name.toLowerCase()\n for (const part of LLM_SCOPE_SUBSTRINGS) {\n if (lower.includes(part)) return true\n }\n return false\n}\n\n/**\n * Default export predicate (smart filter): Latitude scopes, GenAI / LLM attributes,\n * or known LLM instrumentation scopes.\n */\nexport function isDefaultExportSpan(span: ReadableSpan): boolean {\n if (isLatitudeInstrumentationSpan(span)) return true\n if (isGenAiOrLlmAttributeSpan(span)) return true\n if (isKnownLlmInstrumentationScope(span)) return true\n return false\n}\n\nexport function buildShouldExportSpan(options: SmartFilterOptions): (span: ReadableSpan) => boolean {\n if (options.disableSmartFilter) return () => true\n const blocked = new Set(options.blockedInstrumentationScopes ?? [])\n const extra = options.shouldExportSpan\n return (span: ReadableSpan) => {\n const scope = instrumentationScopeName(span)\n if (blocked.has(scope)) return false\n if (isDefaultExportSpan(span)) return true\n if (extra?.(span)) return true\n return false\n }\n}\n\n/**\n * Drops spans that fail the export predicate before passing them to the inner processor.\n * Inner processor should perform redaction and export.\n */\nexport class ExportFilterSpanProcessor implements SpanProcessor {\n private readonly shouldExport: (span: ReadableSpan) => boolean\n private readonly inner: SpanProcessor\n\n constructor(shouldExport: (span: ReadableSpan) => boolean, inner: SpanProcessor) {\n this.shouldExport = shouldExport\n this.inner = inner\n }\n\n onStart(span: Span, parentContext: Context): void {\n this.inner.onStart(span, parentContext)\n }\n\n onEnd(span: ReadableSpan): void {\n if (!this.shouldExport(span)) return\n this.inner.onEnd(span)\n }\n\n forceFlush(): Promise<void> {\n return this.inner.forceFlush()\n }\n\n shutdown(): Promise<void> {\n return this.inner.shutdown()\n }\n}\n\n/** Runs optional redaction then the export processor (batch/simple). */\nexport class RedactThenExportSpanProcessor implements SpanProcessor {\n private readonly redact: SpanProcessor | null\n private readonly exportProcessor: SpanProcessor\n\n constructor(redact: SpanProcessor | null, exportProcessor: SpanProcessor) {\n this.redact = redact\n this.exportProcessor = exportProcessor\n }\n\n onStart(span: Span, parentContext: Context): void {\n this.redact?.onStart(span, parentContext)\n this.exportProcessor.onStart(span, parentContext)\n }\n\n onEnd(span: ReadableSpan): void {\n this.redact?.onEnd(span)\n this.exportProcessor.onEnd(span)\n }\n\n forceFlush(): Promise<void> {\n return this.exportProcessor.forceFlush()\n }\n\n shutdown(): Promise<void> {\n return this.exportProcessor.shutdown()\n }\n}\n"],"mappings":"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","names":["context","ATTR_SERVICE_NAME","context","ATTR_SERVICE_NAME"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@latitude-data/telemetry",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.3",
|
|
4
4
|
"description": "Latitude Telemetry for TypeScript",
|
|
5
5
|
"author": "Latitude Data SL <hello@latitude.so>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -36,14 +36,14 @@
|
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@opentelemetry/api": "^1.9.0",
|
|
39
|
-
"@opentelemetry/context-async-hooks": "^
|
|
40
|
-
"@opentelemetry/core": "^
|
|
41
|
-
"@opentelemetry/exporter-trace-otlp-http": "^0.
|
|
42
|
-
"@opentelemetry/instrumentation": "^0.
|
|
39
|
+
"@opentelemetry/context-async-hooks": "^2.6.0",
|
|
40
|
+
"@opentelemetry/core": "^2.6.0",
|
|
41
|
+
"@opentelemetry/exporter-trace-otlp-http": "^0.213.0",
|
|
42
|
+
"@opentelemetry/instrumentation": "^0.213.0",
|
|
43
43
|
"@traceloop/instrumentation-openai": "^0.22.0",
|
|
44
|
-
"@opentelemetry/resources": "^
|
|
45
|
-
"@opentelemetry/sdk-trace-node": "^
|
|
46
|
-
"@opentelemetry/semantic-conventions": "^1.
|
|
44
|
+
"@opentelemetry/resources": "^2.6.0",
|
|
45
|
+
"@opentelemetry/sdk-trace-node": "^2.6.0",
|
|
46
|
+
"@opentelemetry/semantic-conventions": "^1.40.0",
|
|
47
47
|
"@traceloop/instrumentation-anthropic": "^0.22.0",
|
|
48
48
|
"@traceloop/instrumentation-bedrock": "^0.22.0",
|
|
49
49
|
"@traceloop/instrumentation-cohere": "^0.22.0",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"typescript": "^5.5.4"
|
|
64
64
|
},
|
|
65
65
|
"optionalDependencies": {
|
|
66
|
-
"@anthropic-ai/sdk": "^0.
|
|
66
|
+
"@anthropic-ai/sdk": "^0.82.0",
|
|
67
67
|
"@aws-sdk/client-bedrock-runtime": "^3.1021.0",
|
|
68
68
|
"@google-cloud/vertexai": "^1.10.4",
|
|
69
69
|
"@langchain/core": "^1.1.38",
|