@juspay/neurolink 13.5.0 → 13.5.1
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/CHANGELOG.md +3 -3
- package/dist/adapters/video/videoAnalyzer.d.ts +1 -0
- package/dist/adapters/video/videoAnalyzer.js +4 -0
- package/dist/autoresearch/index.d.ts +1 -0
- package/dist/autoresearch/index.js +4 -0
- package/dist/autoresearch/worker.js +4 -0
- package/dist/browser/neurolink.min.js +467 -467
- package/dist/cli/commands/observability.js +11 -4
- package/dist/cli/commands/telemetry.js +36 -6
- package/dist/cli/utils/formatters.d.ts +17 -0
- package/dist/cli/utils/formatters.js +39 -0
- package/dist/constants/langfuse.d.ts +17 -1
- package/dist/constants/langfuse.js +23 -1
- package/dist/constants/telemetry.d.ts +6 -0
- package/dist/constants/telemetry.js +6 -0
- package/dist/core/baseProvider.js +2 -0
- package/dist/core/geminiLoopAdapter.js +19 -0
- package/dist/core/loopEngine.js +10 -7
- package/dist/core/modules/StreamHandler.js +5 -4
- package/dist/core/modules/TelemetryHandler.d.ts +5 -1
- package/dist/core/modules/TelemetryHandler.js +16 -0
- package/dist/core/modules/ToolsManager.js +3 -0
- package/dist/core/nativeGenerateLoop.js +1 -1
- package/dist/evaluation/index.d.ts +1 -0
- package/dist/evaluation/index.js +4 -0
- package/dist/evaluation/ragasEvaluator.js +1 -0
- package/dist/mcp/externalServerManager.js +6 -2
- package/dist/mcp/toolRegistry.js +3 -0
- package/dist/neurolink.d.ts +16 -8
- package/dist/neurolink.js +115 -61
- package/dist/observability/FEATURE-STATUS.md +0 -4
- package/dist/observability/exporterRegistry.d.ts +6 -1
- package/dist/observability/exporterRegistry.js +18 -0
- package/dist/observability/exporterSpanProcessor.d.ts +20 -6
- package/dist/observability/exporterSpanProcessor.js +166 -34
- package/dist/observability/exporters/baseExporter.d.ts +22 -3
- package/dist/observability/exporters/baseExporter.js +87 -5
- package/dist/observability/exporters/langfuseExporter.d.ts +29 -3
- package/dist/observability/exporters/langfuseExporter.js +251 -41
- package/dist/observability/langfuseMasking.d.ts +1 -1
- package/dist/observability/langfuseMasking.js +1 -1
- package/dist/observability/otlpEncoding.d.ts +18 -5
- package/dist/observability/otlpEncoding.js +69 -12
- package/dist/observability/utils/spanSerializer.d.ts +3 -2
- package/dist/observability/utils/spanSerializer.js +5 -3
- package/dist/processors/base/BaseFileProcessor.d.ts +1 -0
- package/dist/processors/base/BaseFileProcessor.js +4 -0
- package/dist/processors/index.d.ts +1 -0
- package/dist/processors/index.js +4 -0
- package/dist/processors/registry/ProcessorRegistry.d.ts +1 -0
- package/dist/processors/registry/ProcessorRegistry.js +5 -0
- package/dist/providers/amazonBedrock/client.js +7 -5
- package/dist/providers/amazonSagemaker.js +32 -12
- package/dist/providers/anthropic/client.js +1 -0
- package/dist/providers/anthropic/loopAdapter.js +7 -3
- package/dist/providers/googleAiStudio/client.js +2 -0
- package/dist/providers/googleVertex/client.d.ts +6 -5
- package/dist/providers/googleVertex/client.js +46 -19
- package/dist/providers/openaiChatCompletionsBase.js +4 -4
- package/dist/proxy/codexUsage.js +59 -2
- package/dist/proxy/proxyTracer.d.ts +25 -1
- package/dist/proxy/proxyTracer.js +146 -22
- package/dist/proxy/proxyTranslationEngine.js +4 -2
- package/dist/proxy/sseInterceptor.js +6 -4
- package/dist/rag/chunkers/BaseChunker.js +1 -0
- package/dist/rag/index.d.ts +1 -0
- package/dist/rag/index.js +4 -0
- package/dist/rag/ragIntegration.js +1 -0
- package/dist/rag/reranker/reranker.js +2 -0
- package/dist/rag/retrieval/vectorQueryTool.js +1 -0
- package/dist/server/routes/codexProxyRoutes.js +3 -1
- package/dist/server/utils/validation.d.ts +3 -3
- package/dist/services/server/ai/observability/instrumentation.d.ts +8 -7
- package/dist/services/server/ai/observability/instrumentation.js +217 -47
- package/dist/services/server/ai/observability/langfuseSetup.d.ts +19 -1
- package/dist/services/server/ai/observability/langfuseSetup.js +62 -4
- package/dist/services/server/ai/observability/otlpSetup.d.ts +12 -2
- package/dist/services/server/ai/observability/otlpSetup.js +55 -4
- package/dist/telemetry/aiMetrics.d.ts +56 -0
- package/dist/telemetry/aiMetrics.js +229 -0
- package/dist/telemetry/attributes.d.ts +24 -1
- package/dist/telemetry/attributes.js +94 -9
- package/dist/telemetry/chatMessages.d.ts +6 -0
- package/dist/telemetry/chatMessages.js +37 -0
- package/dist/telemetry/index.d.ts +1 -1
- package/dist/telemetry/index.js +1 -1
- package/dist/telemetry/observation.d.ts +5 -5
- package/dist/telemetry/observation.js +128 -39
- package/dist/telemetry/spanSanitizer.d.ts +2 -2
- package/dist/telemetry/spanSanitizer.js +76 -8
- package/dist/telemetry/telemetryStarter.d.ts +16 -0
- package/dist/telemetry/telemetryStarter.js +28 -0
- package/dist/telemetry/traceContext.d.ts +3 -3
- package/dist/telemetry/traceContext.js +3 -3
- package/dist/telemetry/tracers.d.ts +13 -1
- package/dist/telemetry/tracers.js +49 -10
- package/dist/telemetry/withSpan.d.ts +19 -3
- package/dist/telemetry/withSpan.js +149 -20
- package/dist/types/exporter.d.ts +98 -3
- package/dist/types/livekit.d.ts +16 -1
- package/dist/types/loopEngine.d.ts +16 -1
- package/dist/types/observability.d.ts +38 -5
- package/dist/types/proxy.d.ts +2 -0
- package/dist/types/span.d.ts +26 -0
- package/dist/utils/timeout.js +4 -2
- package/dist/voice/livekit/realtimeMcpTools.js +11 -2
- package/dist/voice/livekit/realtimeMemory.d.ts +20 -2
- package/dist/voice/livekit/realtimeMemory.js +139 -46
- package/dist/voice/livekit/realtimeVoiceAgent.js +20 -8
- package/dist/voice/livekit/turnRecorder.js +22 -9
- package/dist/workflow/core/ensembleExecutor.js +2 -0
- package/dist/workflow/core/judgeScorer.js +1 -0
- package/dist/workflow/core/responseConditioner.js +1 -0
- package/dist/workflow/core/workflowRunner.js +6 -1
- package/dist/workflow/index.d.ts +1 -0
- package/dist/workflow/index.js +4 -0
- package/docs-site/static/search-index.json +32 -27
- package/package.json +21 -2
|
@@ -1,38 +1,168 @@
|
|
|
1
1
|
import { propagateAttributes, setLangfuseTracerProvider, } from "@langfuse/tracing";
|
|
2
|
-
import { context, createContextKey, metrics,
|
|
2
|
+
import { context, createContextKey, metrics, } from "@opentelemetry/api";
|
|
3
3
|
import { W3CTraceContextPropagator } from "@opentelemetry/core";
|
|
4
|
-
import { resourceFromAttributes } from "@opentelemetry/resources";
|
|
4
|
+
import { resourceFromAttributes, } from "@opentelemetry/resources";
|
|
5
5
|
import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
|
|
6
|
-
import { ATTR_SERVICE_NAME } from "@opentelemetry/semantic-conventions";
|
|
6
|
+
import { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION, } from "@opentelemetry/semantic-conventions";
|
|
7
|
+
import { DEFAULT_FLUSH_BUDGET_MS } from "../../../../constants/langfuse.js";
|
|
7
8
|
import { OTEL_LOG_PREFIX, TRACE_METADATA_CONTEXT_KEY, } from "../../../../constants/telemetry.js";
|
|
8
9
|
import { getExporterRegistry } from "../../../../observability/exporterRegistry.js";
|
|
9
10
|
import { ExporterSpanProcessor } from "../../../../observability/exporterSpanProcessor.js";
|
|
10
11
|
import { LangfuseExporter } from "../../../../observability/exporters/langfuseExporter.js";
|
|
11
12
|
import { spanJsonAttribute } from "../../../../telemetry/attributes.js";
|
|
13
|
+
import { hasHostTracerProvider, registerTelemetryStarter, } from "../../../../telemetry/telemetryStarter.js";
|
|
12
14
|
import { logger } from "../../../../utils/logger.js";
|
|
13
|
-
import { createLangfuseExporter, isLangfuseEnabled } from "./langfuseSetup.js";
|
|
14
|
-
import { createOtlpMeterProvider, createOtlpSpanProcessor, } from "./otlpSetup.js";
|
|
15
|
+
import { createLangfuseExporter, isLangfuseEnabled, isOff, resolveEnvironment, resolveRelease, } from "./langfuseSetup.js";
|
|
16
|
+
import { createOtlpConnections, createOtlpMeterProvider, createOtlpSpanProcessor, } from "./otlpSetup.js";
|
|
15
17
|
const MAX_PROPAGATED_CHARS = 200;
|
|
16
18
|
const LANGFUSE_EXPORTER_NAME = "langfuse";
|
|
17
19
|
const TRACE_METADATA_KEY = createContextKey(TRACE_METADATA_CONTEXT_KEY);
|
|
20
|
+
const CONTEXT_PROBE_KEY = createContextKey("neurolink.context-manager-probe");
|
|
21
|
+
// `false`, `0`, `off` or `no` skips the flush at process exit; the released build had none.
|
|
22
|
+
const EXIT_FLUSH_SWITCH = "NEUROLINK_TELEMETRY_EXIT_FLUSH";
|
|
18
23
|
let tracerProvider = null;
|
|
24
|
+
let registryProcessor = null;
|
|
25
|
+
let otlpProcessor = null;
|
|
19
26
|
let meterProvider = null;
|
|
27
|
+
let otlpConnections = null;
|
|
28
|
+
let flushBudgetMs = DEFAULT_FLUSH_BUDGET_MS;
|
|
20
29
|
let langfuseExporter = null;
|
|
21
30
|
let usingExternalProvider = false;
|
|
22
31
|
let started = false;
|
|
32
|
+
let startedConfig;
|
|
23
33
|
let initialized = false;
|
|
24
|
-
let
|
|
34
|
+
let ignoredConfigDebugLogged = false;
|
|
35
|
+
const ignoredConfigWarnings = new Set();
|
|
36
|
+
let exitFlushRegistered = false;
|
|
25
37
|
let initializationError = null;
|
|
26
38
|
let terminated = false;
|
|
27
39
|
let terminationLogged = false;
|
|
28
40
|
let unconfiguredLogged = false;
|
|
41
|
+
let missingKeysLogged = false;
|
|
29
42
|
let holders = 0;
|
|
30
|
-
function
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
43
|
+
function differingConfigFields(first, later) {
|
|
44
|
+
const firstLangfuse = first?.langfuse;
|
|
45
|
+
const laterLangfuse = later.langfuse;
|
|
46
|
+
if ((firstLangfuse === false) !== (laterLangfuse === false)) {
|
|
47
|
+
return ["langfuse"];
|
|
48
|
+
}
|
|
49
|
+
const left = typeof firstLangfuse === "object" ? firstLangfuse : {};
|
|
50
|
+
const right = typeof laterLangfuse === "object" ? laterLangfuse : {};
|
|
51
|
+
return [...new Set([...Object.keys(left), ...Object.keys(right)])]
|
|
52
|
+
.filter((key) => left[key] !== right[key])
|
|
53
|
+
.sort();
|
|
54
|
+
}
|
|
55
|
+
function reportIgnoredConfig(config) {
|
|
56
|
+
const differing = differingConfigFields(startedConfig, config);
|
|
57
|
+
if (differing.length === 0) {
|
|
58
|
+
if (!ignoredConfigDebugLogged) {
|
|
59
|
+
ignoredConfigDebugLogged = true;
|
|
60
|
+
logger.debug(`${OTEL_LOG_PREFIX} Telemetry already started; ignoring observability config`);
|
|
61
|
+
}
|
|
62
|
+
return;
|
|
34
63
|
}
|
|
35
|
-
|
|
64
|
+
const fields = differing.join(", ");
|
|
65
|
+
if (ignoredConfigWarnings.has(fields)) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
ignoredConfigWarnings.add(fields);
|
|
69
|
+
logger.warn(`${OTEL_LOG_PREFIX} Telemetry already started; ignoring the observability config of a later NeuroLink instance. The first config stays in effect; the ignored one differs in: ${fields}`);
|
|
70
|
+
}
|
|
71
|
+
function flushBudgetOf(config) {
|
|
72
|
+
const budget = typeof config?.langfuse === "object"
|
|
73
|
+
? config.langfuse.flushBudgetMs
|
|
74
|
+
: undefined;
|
|
75
|
+
return budget !== undefined && budget > 0 ? budget : DEFAULT_FLUSH_BUDGET_MS;
|
|
76
|
+
}
|
|
77
|
+
function hasLangfuseKeys(config) {
|
|
78
|
+
const options = typeof config?.langfuse === "object" ? config.langfuse : {};
|
|
79
|
+
return Boolean((options.publicKey ?? process.env.LANGFUSE_PUBLIC_KEY) &&
|
|
80
|
+
(options.secretKey ?? process.env.LANGFUSE_SECRET_KEY));
|
|
81
|
+
}
|
|
82
|
+
// An unreachable collector must not hold the caller past the budget. When the
|
|
83
|
+
// budget runs out `onExpiry` closes what the work still has open, so the export
|
|
84
|
+
// does not carry on to its own timeout and hold the process open.
|
|
85
|
+
async function withinBudget(work, budgetMs, onExpiry) {
|
|
86
|
+
if (!work) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
let timer;
|
|
90
|
+
const expired = new Promise((_, reject) => {
|
|
91
|
+
timer = setTimeout(() => {
|
|
92
|
+
onExpiry?.();
|
|
93
|
+
reject(new Error(`did not finish within ${budgetMs}ms`));
|
|
94
|
+
}, budgetMs);
|
|
95
|
+
});
|
|
96
|
+
try {
|
|
97
|
+
await Promise.race([work, expired]);
|
|
98
|
+
}
|
|
99
|
+
finally {
|
|
100
|
+
clearTimeout(timer);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function cutOtlpConnections() {
|
|
104
|
+
otlpConnections?.cut();
|
|
105
|
+
}
|
|
106
|
+
function reportUnsettled(action, results) {
|
|
107
|
+
const errors = results.flatMap((result) => result.status === "rejected"
|
|
108
|
+
? [
|
|
109
|
+
result.reason instanceof Error
|
|
110
|
+
? result.reason.message
|
|
111
|
+
: String(result.reason),
|
|
112
|
+
]
|
|
113
|
+
: []);
|
|
114
|
+
if (errors.length > 0) {
|
|
115
|
+
logger.warn(`${OTEL_LOG_PREFIX} ${action} did not complete; spans or metrics still pending may be lost`, { errors });
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
function flushBeforeExit() {
|
|
119
|
+
if (isOff(process.env[EXIT_FLUSH_SWITCH])) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
flushOpenTelemetry().catch((error) => {
|
|
123
|
+
logger.debug(`${OTEL_LOG_PREFIX} Flush at process exit failed`, {
|
|
124
|
+
error: error instanceof Error ? error.message : String(error),
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
function registerExitFlush() {
|
|
129
|
+
if (exitFlushRegistered) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
exitFlushRegistered = true;
|
|
133
|
+
process.once("beforeExit", flushBeforeExit);
|
|
134
|
+
}
|
|
135
|
+
// Without a registered context manager `context.with` runs the callback but
|
|
136
|
+
// `context.active()` stays the root context, so nothing set on a context
|
|
137
|
+
// (user, session, the parent span) reaches the spans created inside.
|
|
138
|
+
function hasContextManager() {
|
|
139
|
+
return context.with(context.active().setValue(CONTEXT_PROBE_KEY, true), () => context.active().getValue(CONTEXT_PROBE_KEY) === true);
|
|
140
|
+
}
|
|
141
|
+
// The OTLP traces and metrics keep the service name existing dashboards and
|
|
142
|
+
// alerts match on. The provider's own resource, which the registry exporters
|
|
143
|
+
// (Langfuse) read, is built in `initialize` with its own default.
|
|
144
|
+
function otlpResourceOf(config) {
|
|
145
|
+
const environment = resolveEnvironment(config);
|
|
146
|
+
return resourceFromAttributes({
|
|
147
|
+
[ATTR_SERVICE_NAME]: process.env.OTEL_SERVICE_NAME || "ai-service",
|
|
148
|
+
[ATTR_SERVICE_VERSION]: resolveRelease(config) || process.env.npm_package_version || "v1.0.0",
|
|
149
|
+
...(environment && { "deployment.environment": environment }),
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
// A view over each ended span rather than a copy, so the methods and fields the
|
|
153
|
+
// exporter reads stay intact, with the sink's own resource on top.
|
|
154
|
+
function withResource(processor, resource) {
|
|
155
|
+
return {
|
|
156
|
+
onStart: (span, parentContext) => processor.onStart(span, parentContext),
|
|
157
|
+
onEnd: (span) => {
|
|
158
|
+
const view = Object.create(span, {
|
|
159
|
+
resource: { value: resource, enumerable: true },
|
|
160
|
+
});
|
|
161
|
+
processor.onEnd(view);
|
|
162
|
+
},
|
|
163
|
+
forceFlush: () => processor.forceFlush(),
|
|
164
|
+
shutdown: () => processor.shutdown(),
|
|
165
|
+
};
|
|
36
166
|
}
|
|
37
167
|
function registerLangfuseExporter(config) {
|
|
38
168
|
const registry = getExporterRegistry();
|
|
@@ -47,68 +177,107 @@ function registerLangfuseExporter(config) {
|
|
|
47
177
|
return exporter;
|
|
48
178
|
}
|
|
49
179
|
function initialize(config) {
|
|
50
|
-
const
|
|
180
|
+
const langfuseRequested = isLangfuseEnabled(config);
|
|
181
|
+
// Without both keys there is nothing to export to, so Langfuse counts as not
|
|
182
|
+
// configured and a later config that has them can still start tracing.
|
|
183
|
+
const langfuse = langfuseRequested && hasLangfuseKeys(config);
|
|
184
|
+
if (langfuseRequested && !langfuse && !missingKeysLogged) {
|
|
185
|
+
missingKeysLogged = true;
|
|
186
|
+
logger.warn(`${OTEL_LOG_PREFIX} Langfuse is enabled but publicKey and secretKey are not both set in config or LANGFUSE_PUBLIC_KEY / LANGFUSE_SECRET_KEY; not exporting to Langfuse`);
|
|
187
|
+
}
|
|
51
188
|
const otlpEndpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT;
|
|
52
|
-
|
|
189
|
+
// An options object starts the pipeline even without keys, as it always did:
|
|
190
|
+
// exporters registered on the shared registry still receive the spans.
|
|
191
|
+
const optionsObject = langfuseRequested && typeof config?.langfuse === "object";
|
|
192
|
+
if (!langfuse && !optionsObject && !otlpEndpoint) {
|
|
53
193
|
if (!unconfiguredLogged) {
|
|
54
194
|
unconfiguredLogged = true;
|
|
55
195
|
logger.debug(`${OTEL_LOG_PREFIX} Langfuse and OTLP not configured; skipping`);
|
|
56
196
|
}
|
|
57
197
|
return config?.langfuse === false;
|
|
58
198
|
}
|
|
199
|
+
flushBudgetMs = flushBudgetOf(config);
|
|
59
200
|
if (hasHostTracerProvider()) {
|
|
60
201
|
usingExternalProvider = true;
|
|
61
202
|
initialized = true;
|
|
62
203
|
langfuseExporter = langfuse ? registerLangfuseExporter(config) : null;
|
|
63
204
|
if (langfuseExporter) {
|
|
64
|
-
logger.info(`${OTEL_LOG_PREFIX} Host TracerProvider detected; Langfuse exporter registered. Add \`createExporterSpanProcessor()\` to the host provider to export NeuroLink spans to it.`);
|
|
205
|
+
logger.info(`${OTEL_LOG_PREFIX} Host TracerProvider detected; Langfuse exporter registered. Add \`createExporterSpanProcessor()\` to the host provider to export NeuroLink spans to it, and register a context manager (\`NodeTracerProvider.register()\` and \`NodeSDK\` do) so user, session and parent spans reach the spans NeuroLink creates.`);
|
|
206
|
+
if (!hasContextManager()) {
|
|
207
|
+
logger.warn(`${OTEL_LOG_PREFIX} The host TracerProvider has no context manager registered: setLangfuseContext() user, session and metadata and parent/child span nesting are lost. Register one, for example with \`NodeTracerProvider.register()\`, or start the host with \`NodeSDK\`.`);
|
|
208
|
+
}
|
|
65
209
|
}
|
|
66
210
|
else {
|
|
67
211
|
logger.info(`${OTEL_LOG_PREFIX} Host TracerProvider detected; NeuroLink registers no provider and no exporter.`);
|
|
68
212
|
}
|
|
213
|
+
if (otlpEndpoint) {
|
|
214
|
+
logger.warn(`${OTEL_LOG_PREFIX} OTEL_EXPORTER_OTLP_ENDPOINT is ignored because a host TracerProvider is registered; NeuroLink exports no traces or metrics to it. Add an OTLP exporter to the host's own providers. NeuroLink's ai_* metrics are recorded on the host's MeterProvider.`);
|
|
215
|
+
}
|
|
216
|
+
if (langfuseExporter) {
|
|
217
|
+
registerExitFlush();
|
|
218
|
+
}
|
|
69
219
|
return true;
|
|
70
220
|
}
|
|
221
|
+
const environment = resolveEnvironment(config);
|
|
71
222
|
const resource = resourceFromAttributes({
|
|
72
|
-
[ATTR_SERVICE_NAME]: process.env.OTEL_SERVICE_NAME || "
|
|
223
|
+
[ATTR_SERVICE_NAME]: process.env.OTEL_SERVICE_NAME || "neurolink",
|
|
224
|
+
[ATTR_SERVICE_VERSION]: resolveRelease(config) || process.env.npm_package_version || "v1.0.0",
|
|
225
|
+
...(environment && { "deployment.environment": environment }),
|
|
73
226
|
});
|
|
74
227
|
const exporter = langfuse ? registerLangfuseExporter(config) : null;
|
|
75
|
-
const
|
|
76
|
-
|
|
228
|
+
const otlpResource = otlpResourceOf(config);
|
|
229
|
+
const connections = otlpEndpoint ? createOtlpConnections() : null;
|
|
230
|
+
const otlpExporter = otlpEndpoint
|
|
231
|
+
? createOtlpSpanProcessor(otlpEndpoint, flushBudgetMs, connections ?? undefined)
|
|
77
232
|
: null;
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
];
|
|
81
|
-
if (
|
|
82
|
-
spanProcessors.push(
|
|
233
|
+
const otlpSpanProcessor = otlpExporter && withResource(otlpExporter, otlpResource);
|
|
234
|
+
const exporterSpanProcessor = new ExporterSpanProcessor(getExporterRegistry(), true);
|
|
235
|
+
const spanProcessors = [exporterSpanProcessor];
|
|
236
|
+
if (otlpSpanProcessor) {
|
|
237
|
+
spanProcessors.push(otlpSpanProcessor);
|
|
83
238
|
}
|
|
84
239
|
const provider = new NodeTracerProvider({ resource, spanProcessors });
|
|
85
240
|
provider.register({ propagator: new W3CTraceContextPropagator() });
|
|
86
241
|
setLangfuseTracerProvider(provider);
|
|
87
242
|
tracerProvider = provider;
|
|
243
|
+
registryProcessor = exporterSpanProcessor;
|
|
244
|
+
otlpProcessor = otlpSpanProcessor;
|
|
88
245
|
langfuseExporter = exporter;
|
|
89
246
|
meterProvider = otlpEndpoint
|
|
90
|
-
? createOtlpMeterProvider(otlpEndpoint,
|
|
247
|
+
? createOtlpMeterProvider(otlpEndpoint, otlpResource, flushBudgetMs, connections ?? undefined)
|
|
91
248
|
: null;
|
|
249
|
+
otlpConnections = connections;
|
|
92
250
|
usingExternalProvider = false;
|
|
93
251
|
initialized = true;
|
|
252
|
+
registerExitFlush();
|
|
94
253
|
logger.info(`${OTEL_LOG_PREFIX} Observability initialized`, {
|
|
95
254
|
langfuseEnabled: exporter !== null,
|
|
96
|
-
otlpEnabled:
|
|
255
|
+
otlpEnabled: otlpSpanProcessor !== null,
|
|
97
256
|
});
|
|
98
257
|
return true;
|
|
99
258
|
}
|
|
100
259
|
async function stop() {
|
|
101
260
|
const provider = tracerProvider;
|
|
261
|
+
const registry = registryProcessor;
|
|
262
|
+
const otlp = otlpProcessor;
|
|
102
263
|
const meters = meterProvider;
|
|
264
|
+
const connections = otlpConnections;
|
|
103
265
|
const hostExporter = usingExternalProvider ? langfuseExporter : null;
|
|
266
|
+
const budgetMs = flushBudgetMs;
|
|
104
267
|
terminated = true;
|
|
105
268
|
tracerProvider = null;
|
|
269
|
+
registryProcessor = null;
|
|
270
|
+
otlpProcessor = null;
|
|
106
271
|
meterProvider = null;
|
|
272
|
+
otlpConnections = null;
|
|
107
273
|
langfuseExporter = null;
|
|
108
274
|
usingExternalProvider = false;
|
|
109
275
|
started = false;
|
|
276
|
+
startedConfig = undefined;
|
|
110
277
|
initialized = false;
|
|
111
278
|
initializationError = null;
|
|
279
|
+
process.off("beforeExit", flushBeforeExit);
|
|
280
|
+
exitFlushRegistered = false;
|
|
112
281
|
if (provider) {
|
|
113
282
|
setLangfuseTracerProvider(null);
|
|
114
283
|
}
|
|
@@ -118,23 +287,18 @@ async function stop() {
|
|
|
118
287
|
if (hostExporter) {
|
|
119
288
|
getExporterRegistry().unregister(hostExporter.getName());
|
|
120
289
|
}
|
|
290
|
+
// The provider's own shutdown only shuts down these processors; each is shut
|
|
291
|
+
// down here so the OTLP one is bounded and Langfuse keeps its own budget.
|
|
121
292
|
const results = await Promise.allSettled([
|
|
122
|
-
|
|
293
|
+
registry?.shutdown(),
|
|
294
|
+
withinBudget(otlp?.shutdown(), budgetMs, () => connections?.cut()),
|
|
123
295
|
hostExporter?.shutdown(),
|
|
124
|
-
meters?.shutdown(),
|
|
296
|
+
withinBudget(meters?.shutdown(), budgetMs, () => connections?.cut()),
|
|
125
297
|
]);
|
|
126
|
-
|
|
127
|
-
if (result.status === "rejected") {
|
|
128
|
-
logger.error(`${OTEL_LOG_PREFIX} Shutdown failed`, {
|
|
129
|
-
error: result.reason instanceof Error
|
|
130
|
-
? result.reason.message
|
|
131
|
-
: String(result.reason),
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
}
|
|
298
|
+
reportUnsettled("Shutdown", results);
|
|
135
299
|
}
|
|
136
300
|
/**
|
|
137
|
-
* @description Starts NeuroLink's tracing once per process, synchronously. Every span created through the shared tracers calls it first, so direct provider calls without a NeuroLink instance are traced too. Langfuse is enabled unless `config.langfuse` is `false`, when an options object
|
|
301
|
+
* @description Starts NeuroLink's tracing once per process, synchronously. Every span created through the shared tracers calls it first once this module is loaded, as the main, server and livekit entries do, so direct provider calls without a NeuroLink instance are traced too. Langfuse is enabled unless `config.langfuse` is `false` or has `enabled: false`, when `config.langfuse` is `true` or an options object, or when `LANGFUSE_PUBLIC_KEY` and `LANGFUSE_SECRET_KEY` are set and `LANGFUSE_ENABLED` is not `false`, `0`, `off` or `no`; an OTLP exporter is added when `OTEL_EXPORTER_OTLP_ENDPOINT` is set. When the host already registered a TracerProvider no provider is created and `OTEL_EXPORTER_OTLP_ENDPOINT` is ignored with a warning; the Langfuse exporter, if configured, is registered on the shared exporter registry and the host adds `createExporterSpanProcessor()` to its provider. The first call that finds tracing configured decides the setup and a later `config` is ignored, with a warning naming the options that differ from the first when it does differ; calls made before anything is configured start nothing, so a later config or environment can still start tracing, unless `langfuse: false` was passed. Langfuse enabled without both keys (in config or the environment) exports nothing to Langfuse, and a warning says so once. With `langfuse: true` or the environment alone that counts as not configured, so only an OTLP endpoint starts tracing; an options object starts tracing anyway, as it always did, so exporters registered on the shared registry receive the spans. Pending spans and metrics are flushed when the process runs out of work (`beforeExit`), within the same budget as `flushOpenTelemetry`, which an explicit `process.exit()` skips; `NEUROLINK_TELEMETRY_EXIT_FLUSH` set to `false`, `0`, `off` or `no` skips that flush too, and the process ends as soon as it has no work. After `shutdownOpenTelemetry` it does nothing.
|
|
138
302
|
* @param config {ObservabilityConfig | undefined} - Observability options, honoured only when this is the first call.
|
|
139
303
|
* @returns {void} Nothing; a failed setup is logged and recorded in `getLangfuseHealthStatus`.
|
|
140
304
|
*/
|
|
@@ -147,18 +311,19 @@ export function ensureTelemetry(config) {
|
|
|
147
311
|
return;
|
|
148
312
|
}
|
|
149
313
|
if (started) {
|
|
150
|
-
if (config
|
|
151
|
-
|
|
152
|
-
logger.debug(`${OTEL_LOG_PREFIX} Telemetry already started; ignoring observability config`);
|
|
314
|
+
if (config) {
|
|
315
|
+
reportIgnoredConfig(config);
|
|
153
316
|
}
|
|
154
317
|
return;
|
|
155
318
|
}
|
|
156
319
|
initializationError = null;
|
|
157
320
|
try {
|
|
158
321
|
started = initialize(config);
|
|
322
|
+
startedConfig = started ? config : undefined;
|
|
159
323
|
}
|
|
160
324
|
catch (error) {
|
|
161
325
|
started = true;
|
|
326
|
+
startedConfig = config;
|
|
162
327
|
initializationError =
|
|
163
328
|
error instanceof Error ? error.message : String(error);
|
|
164
329
|
logger.error(`${OTEL_LOG_PREFIX} Initialization failed`, {
|
|
@@ -166,6 +331,7 @@ export function ensureTelemetry(config) {
|
|
|
166
331
|
});
|
|
167
332
|
}
|
|
168
333
|
}
|
|
334
|
+
registerTelemetryStarter(ensureTelemetry);
|
|
169
335
|
/**
|
|
170
336
|
* @description Registers a holder of the process-wide telemetry and starts it if needed. Pair every call with `releaseTelemetry`.
|
|
171
337
|
* @param config {ObservabilityConfig | undefined} - Observability options forwarded to `ensureTelemetry`.
|
|
@@ -176,25 +342,28 @@ export function acquireTelemetry(config) {
|
|
|
176
342
|
ensureTelemetry(config);
|
|
177
343
|
}
|
|
178
344
|
/**
|
|
179
|
-
* @description Releases one holder registered by `acquireTelemetry` and flushes pending spans. The provider stays registered for the process so cached tracers keep working and later instances reuse it.
|
|
345
|
+
* @description Releases one holder registered by `acquireTelemetry` and flushes pending spans as `flushOpenTelemetry` does. The provider stays registered for the process so cached tracers keep working and later instances reuse it.
|
|
180
346
|
* @returns {Promise<void>} Resolves when pending spans are flushed.
|
|
181
|
-
* @throws {Error} When any provider fails to flush.
|
|
347
|
+
* @throws {Error} When any provider fails to flush or does not finish within the flush budget.
|
|
182
348
|
*/
|
|
183
349
|
export async function releaseTelemetry() {
|
|
184
350
|
holders = Math.max(0, holders - 1);
|
|
185
351
|
await flushOpenTelemetry();
|
|
186
352
|
}
|
|
187
353
|
/**
|
|
188
|
-
* @description Exports pending spans and metrics from the providers NeuroLink owns and flushes its Langfuse exporter. A host provider is never flushed.
|
|
354
|
+
* @description Exports pending spans and metrics from the providers NeuroLink owns and flushes its Langfuse exporter. A host provider is never flushed. The OTLP span and metric exports are waited for at most the flush budget (`observability.langfuse.flushBudgetMs`, default 3000 ms) and the Langfuse exporter within its own budget. A provider that fails to flush, or does not finish within the budget (a collector that cannot be reached, for one), is logged as a warning and makes the call reject once every provider has settled.
|
|
189
355
|
* @returns {Promise<void>} Resolves when every owned provider has flushed.
|
|
190
|
-
* @throws {Error} When any provider fails to flush.
|
|
356
|
+
* @throws {Error} When any provider fails to flush or does not finish within the flush budget.
|
|
191
357
|
*/
|
|
192
358
|
export async function flushOpenTelemetry() {
|
|
359
|
+
const budgetMs = flushBudgetMs;
|
|
193
360
|
const results = await Promise.allSettled([
|
|
194
|
-
|
|
361
|
+
registryProcessor?.forceFlush(),
|
|
195
362
|
usingExternalProvider ? langfuseExporter?.flush() : undefined,
|
|
196
|
-
|
|
363
|
+
withinBudget(otlpProcessor?.forceFlush(), budgetMs, cutOtlpConnections),
|
|
364
|
+
withinBudget(meterProvider?.forceFlush(), budgetMs, cutOtlpConnections),
|
|
197
365
|
]);
|
|
366
|
+
reportUnsettled("Flush", results);
|
|
198
367
|
const failed = results.filter((result) => result.status === "rejected");
|
|
199
368
|
if (failed.length > 0) {
|
|
200
369
|
throw new Error(`${OTEL_LOG_PREFIX} Flush failed`, {
|
|
@@ -203,8 +372,9 @@ export async function flushOpenTelemetry() {
|
|
|
203
372
|
}
|
|
204
373
|
}
|
|
205
374
|
/**
|
|
206
|
-
* @description Terminally shuts down the providers NeuroLink owns once no `acquireTelemetry` holder remains; while holders remain it only flushes. Telemetry cannot be restarted in this process afterwards. A host provider is never shut down; with one, only NeuroLink's Langfuse exporter is shut down and unregistered.
|
|
207
|
-
* @returns {Promise<void>} Resolves when telemetry is flushed or shut down.
|
|
375
|
+
* @description Terminally shuts down the providers NeuroLink owns once no `acquireTelemetry` holder remains; while holders remain it only flushes, as `flushOpenTelemetry` does. Telemetry cannot be restarted in this process afterwards. A host provider is never shut down; with one, only NeuroLink's Langfuse exporter is shut down and unregistered. The OTLP exporters get the same budget as `flushOpenTelemetry`, and a failure of the shutdown itself is logged as a warning.
|
|
376
|
+
* @returns {Promise<void>} Resolves when telemetry is flushed or shut down, or the flush budget has run out.
|
|
377
|
+
* @throws {Error} When holders remain and the flush they get fails.
|
|
208
378
|
*/
|
|
209
379
|
export async function shutdownOpenTelemetry() {
|
|
210
380
|
if (holders > 0) {
|
|
@@ -1,7 +1,25 @@
|
|
|
1
1
|
import { LangfuseExporter } from "../../../../observability/exporters/langfuseExporter.js";
|
|
2
2
|
import type { ObservabilityConfig } from "../../../../types/index.js";
|
|
3
3
|
/**
|
|
4
|
-
* @description
|
|
4
|
+
* @description Tells whether a setting says "off": `false`, or the text `false`, `0`, `off` or `no` in any case.
|
|
5
|
+
* @param value {unknown} - A config value or an environment variable.
|
|
6
|
+
* @returns {boolean} `true` for an explicit off setting; `false` for anything else, an unset value included.
|
|
7
|
+
*/
|
|
8
|
+
export declare function isOff(value: unknown): boolean;
|
|
9
|
+
/**
|
|
10
|
+
* @description Resolves the environment name the OTLP resource reports as `deployment.environment`: the config value, then `LANGFUSE_TRACING_ENVIRONMENT`, `LANGFUSE_ENVIRONMENT` and `PUBLIC_APP_ENVIRONMENT`. Langfuse traces are labelled from the config value and `LANGFUSE_TRACING_ENVIRONMENT` alone, as before.
|
|
11
|
+
* @param config {ObservabilityConfig | undefined} - Observability options.
|
|
12
|
+
* @returns {string | undefined} The environment name, or `undefined` when none is set.
|
|
13
|
+
*/
|
|
14
|
+
export declare function resolveEnvironment(config?: ObservabilityConfig): string | undefined;
|
|
15
|
+
/**
|
|
16
|
+
* @description Resolves the release the OTLP resource reports as `service.version`: the config value, then `LANGFUSE_RELEASE` and `PUBLIC_APP_VERSION`. Langfuse traces are labelled from the config value and `LANGFUSE_RELEASE` alone, as before.
|
|
17
|
+
* @param config {ObservabilityConfig | undefined} - Observability options.
|
|
18
|
+
* @returns {string | undefined} The release identifier, or `undefined` when none is set.
|
|
19
|
+
*/
|
|
20
|
+
export declare function resolveRelease(config?: ObservabilityConfig): string | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* @description Decides whether Langfuse export is on. Off when `config.langfuse` is `false` or an options object with `enabled: false`. On for `true` and for an options object with `enabled: true` or with both keys. Any other options object, and no options at all with both keys in the environment, is on unless `LANGFUSE_ENABLED` is `false`, `0`, `off` or `no`: the switch governs the keys wherever they come from the environment, so an options object that leaves them there (only a mask or an environment name) obeys it too, while keys or `enabled: true` given in code are an explicit choice and win over it.
|
|
5
23
|
* @param config {ObservabilityConfig | undefined} - Observability options.
|
|
6
24
|
* @returns {boolean} `true` when a Langfuse exporter should be created.
|
|
7
25
|
*/
|
|
@@ -11,8 +11,48 @@ async function initializeQuietly(exporter) {
|
|
|
11
11
|
});
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
|
+
const OFF_VALUES = new Set(["false", "0", "off", "no"]);
|
|
14
15
|
/**
|
|
15
|
-
* @description
|
|
16
|
+
* @description Tells whether a setting says "off": `false`, or the text `false`, `0`, `off` or `no` in any case.
|
|
17
|
+
* @param value {unknown} - A config value or an environment variable.
|
|
18
|
+
* @returns {boolean} `true` for an explicit off setting; `false` for anything else, an unset value included.
|
|
19
|
+
*/
|
|
20
|
+
export function isOff(value) {
|
|
21
|
+
return (value === false ||
|
|
22
|
+
(typeof value === "string" && OFF_VALUES.has(value.trim().toLowerCase())));
|
|
23
|
+
}
|
|
24
|
+
function firstEnv(...names) {
|
|
25
|
+
for (const name of names) {
|
|
26
|
+
const value = process.env[name]?.trim();
|
|
27
|
+
if (value) {
|
|
28
|
+
return value;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
function langfuseOptions(config) {
|
|
34
|
+
return typeof config?.langfuse === "object" ? config.langfuse : {};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* @description Resolves the environment name the OTLP resource reports as `deployment.environment`: the config value, then `LANGFUSE_TRACING_ENVIRONMENT`, `LANGFUSE_ENVIRONMENT` and `PUBLIC_APP_ENVIRONMENT`. Langfuse traces are labelled from the config value and `LANGFUSE_TRACING_ENVIRONMENT` alone, as before.
|
|
38
|
+
* @param config {ObservabilityConfig | undefined} - Observability options.
|
|
39
|
+
* @returns {string | undefined} The environment name, or `undefined` when none is set.
|
|
40
|
+
*/
|
|
41
|
+
export function resolveEnvironment(config) {
|
|
42
|
+
return (langfuseOptions(config).environment ||
|
|
43
|
+
firstEnv("LANGFUSE_TRACING_ENVIRONMENT", "LANGFUSE_ENVIRONMENT", "PUBLIC_APP_ENVIRONMENT"));
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* @description Resolves the release the OTLP resource reports as `service.version`: the config value, then `LANGFUSE_RELEASE` and `PUBLIC_APP_VERSION`. Langfuse traces are labelled from the config value and `LANGFUSE_RELEASE` alone, as before.
|
|
47
|
+
* @param config {ObservabilityConfig | undefined} - Observability options.
|
|
48
|
+
* @returns {string | undefined} The release identifier, or `undefined` when none is set.
|
|
49
|
+
*/
|
|
50
|
+
export function resolveRelease(config) {
|
|
51
|
+
return (langfuseOptions(config).release ||
|
|
52
|
+
firstEnv("LANGFUSE_RELEASE", "PUBLIC_APP_VERSION"));
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* @description Decides whether Langfuse export is on. Off when `config.langfuse` is `false` or an options object with `enabled: false`. On for `true` and for an options object with `enabled: true` or with both keys. Any other options object, and no options at all with both keys in the environment, is on unless `LANGFUSE_ENABLED` is `false`, `0`, `off` or `no`: the switch governs the keys wherever they come from the environment, so an options object that leaves them there (only a mask or an environment name) obeys it too, while keys or `enabled: true` given in code are an explicit choice and win over it.
|
|
16
56
|
* @param config {ObservabilityConfig | undefined} - Observability options.
|
|
17
57
|
* @returns {boolean} `true` when a Langfuse exporter should be created.
|
|
18
58
|
*/
|
|
@@ -21,8 +61,21 @@ export function isLangfuseEnabled(config) {
|
|
|
21
61
|
if (langfuse === false) {
|
|
22
62
|
return false;
|
|
23
63
|
}
|
|
24
|
-
|
|
25
|
-
|
|
64
|
+
if (typeof langfuse === "object") {
|
|
65
|
+
if (isOff(langfuse.enabled)) {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
// Keys or `enabled: true` given in code are an explicit choice and win over the
|
|
69
|
+
// environment switch. An object that leaves the keys to the environment (only a
|
|
70
|
+
// mask or an environment name) is governed by it like the keys themselves.
|
|
71
|
+
return (langfuse.enabled === true ||
|
|
72
|
+
Boolean(langfuse.publicKey && langfuse.secretKey) ||
|
|
73
|
+
!isOff(process.env.LANGFUSE_ENABLED));
|
|
74
|
+
}
|
|
75
|
+
if (langfuse === true) {
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
return (Boolean(process.env.LANGFUSE_PUBLIC_KEY && process.env.LANGFUSE_SECRET_KEY) && !isOff(process.env.LANGFUSE_ENABLED));
|
|
26
79
|
}
|
|
27
80
|
/**
|
|
28
81
|
* @description Builds and starts a Langfuse exporter from config, falling back to the `LANGFUSE_*` environment variables.
|
|
@@ -30,7 +83,7 @@ export function isLangfuseEnabled(config) {
|
|
|
30
83
|
* @returns {LangfuseExporter | null} The exporter, or `null` (after a warning) when the public or secret key is missing.
|
|
31
84
|
*/
|
|
32
85
|
export function createLangfuseExporter(config) {
|
|
33
|
-
const options =
|
|
86
|
+
const options = langfuseOptions(config);
|
|
34
87
|
const publicKey = options.publicKey ?? process.env.LANGFUSE_PUBLIC_KEY;
|
|
35
88
|
const secretKey = options.secretKey ?? process.env.LANGFUSE_SECRET_KEY;
|
|
36
89
|
if (!publicKey || !secretKey) {
|
|
@@ -42,9 +95,14 @@ export function createLangfuseExporter(config) {
|
|
|
42
95
|
publicKey,
|
|
43
96
|
secretKey,
|
|
44
97
|
baseUrl: options.baseUrl ?? process.env.LANGFUSE_BASE_URL,
|
|
98
|
+
// The released build labelled Langfuse traces from the option and
|
|
99
|
+
// LANGFUSE_TRACING_ENVIRONMENT / LANGFUSE_RELEASE only (the exporter reads
|
|
100
|
+
// those two itself); the longer chain feeds the OTLP resource alone.
|
|
45
101
|
environment: options.environment,
|
|
46
102
|
release: options.release,
|
|
103
|
+
flushBudgetMs: options.flushBudgetMs,
|
|
47
104
|
mask: options.mask,
|
|
105
|
+
redactIO: options.redactIO,
|
|
48
106
|
maxBufferSize: options.exportMode === "immediate" ? 1 : options.flushAt,
|
|
49
107
|
flushIntervalMs: options.flushInterval === undefined
|
|
50
108
|
? undefined
|
|
@@ -1,16 +1,26 @@
|
|
|
1
1
|
import type { Resource } from "@opentelemetry/resources";
|
|
2
2
|
import { MeterProvider } from "@opentelemetry/sdk-metrics";
|
|
3
3
|
import { type SpanProcessor } from "@opentelemetry/sdk-trace-base";
|
|
4
|
+
import type { OtlpConnections } from "../../../../types/index.js";
|
|
5
|
+
/**
|
|
6
|
+
* @description Tracks the connections the OTLP exporters open, so a flush or shutdown that has run out of its budget can close them instead of leaving a request in flight that holds the process open.
|
|
7
|
+
* @returns {OtlpConnections} The agent factory to give the exporters and the function that closes what they opened.
|
|
8
|
+
*/
|
|
9
|
+
export declare function createOtlpConnections(): OtlpConnections;
|
|
4
10
|
/**
|
|
5
11
|
* @description Builds a batching span processor that ships spans to an OTLP/HTTP endpoint.
|
|
6
12
|
* @param endpoint {string} - OTLP base URL; `/v1/traces` is appended.
|
|
13
|
+
* @param budgetMs {number | undefined} - Request timeout in milliseconds, used unless `OTEL_EXPORTER_OTLP_TIMEOUT` or `OTEL_EXPORTER_OTLP_TRACES_TIMEOUT` is set; the exporter's default when omitted.
|
|
14
|
+
* @param connections {OtlpConnections | undefined} - Tracks the connections the exporter opens so they can be closed when a flush runs out of its budget.
|
|
7
15
|
* @returns {SpanProcessor | null} The processor, or `null` (after a warning) when the exporter cannot be created.
|
|
8
16
|
*/
|
|
9
|
-
export declare function createOtlpSpanProcessor(endpoint: string): SpanProcessor | null;
|
|
17
|
+
export declare function createOtlpSpanProcessor(endpoint: string, budgetMs?: number, connections?: OtlpConnections): SpanProcessor | null;
|
|
10
18
|
/**
|
|
11
19
|
* @description Builds a meter provider that exports metrics to an OTLP/HTTP endpoint and registers it as the global meter provider.
|
|
12
20
|
* @param endpoint {string} - OTLP base URL; `/v1/metrics` is appended.
|
|
13
21
|
* @param resource {Resource} - Resource describing the service.
|
|
22
|
+
* @param budgetMs {number | undefined} - Request timeout in milliseconds, used unless `OTEL_EXPORTER_OTLP_TIMEOUT` or `OTEL_EXPORTER_OTLP_METRICS_TIMEOUT` is set; the exporter's default when omitted.
|
|
23
|
+
* @param connections {OtlpConnections | undefined} - Tracks the connections the exporter opens so they can be closed when a flush runs out of its budget.
|
|
14
24
|
* @returns {MeterProvider | null} The provider, or `null` (after a warning) when it cannot be created.
|
|
15
25
|
*/
|
|
16
|
-
export declare function createOtlpMeterProvider(endpoint: string, resource: Resource): MeterProvider | null;
|
|
26
|
+
export declare function createOtlpMeterProvider(endpoint: string, resource: Resource, budgetMs?: number, connections?: OtlpConnections): MeterProvider | null;
|