@veryfront/ext-observability-opentelemetry 0.1.1028 → 0.1.1029
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -13
- package/esm/index.d.ts +8 -1
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +219 -14
- package/package.json +15 -3
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> **Category:** Observability | **Contracts:** `TracingExporter`, `NodeTelemetryProvider` | **Optional**
|
|
4
4
|
|
|
5
|
-
Provides distributed tracing, OTLP metrics export, the OpenTelemetry metrics API bridge, and Node telemetry bootstrap for Veryfront via the [OpenTelemetry JS SDK](https://github.com/open-telemetry/opentelemetry-js). Exports trace spans and metrics over OTLP/HTTP to any OpenTelemetry-compatible collector.
|
|
5
|
+
Provides distributed tracing, OTLP log export, OTLP metrics export, the OpenTelemetry metrics API bridge, and Node telemetry bootstrap for Veryfront via the [OpenTelemetry JS SDK](https://github.com/open-telemetry/opentelemetry-js). Exports trace spans, log records, and metrics over OTLP/HTTP to any OpenTelemetry-compatible collector.
|
|
6
6
|
|
|
7
7
|
## Installation
|
|
8
8
|
|
|
@@ -20,18 +20,22 @@ export default defineConfig({
|
|
|
20
20
|
|
|
21
21
|
The extension reads the standard OpenTelemetry env vars at setup time:
|
|
22
22
|
|
|
23
|
-
| Variable
|
|
24
|
-
|
|
|
25
|
-
|
|
|
26
|
-
|
|
|
27
|
-
| `
|
|
28
|
-
| `
|
|
29
|
-
| `
|
|
30
|
-
| `
|
|
31
|
-
| `
|
|
32
|
-
| `
|
|
33
|
-
| `
|
|
34
|
-
| `
|
|
23
|
+
| Variable | Required | Description |
|
|
24
|
+
| --------------------------------------------------------- | ---------------- | ----------------------------------------------------------------- |
|
|
25
|
+
| `OTEL_EXPORTER_OTLP_ENDPOINT` | Yes (for export) | Base collector URL, e.g. `http://localhost:4318` |
|
|
26
|
+
| `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` | No | Trace-specific OTLP HTTP URL |
|
|
27
|
+
| `OTEL_EXPORTER_OTLP_METRICS_ENDPOINT` | No | Metric-specific OTLP HTTP URL |
|
|
28
|
+
| `OTEL_EXPORTER_OTLP_LOGS_ENDPOINT` | No | Log-specific OTLP HTTP URL |
|
|
29
|
+
| `OTEL_EXPORTER_OTLP_HEADERS` | No | Comma-separated `key=value` pairs (commonly used for auth tokens) |
|
|
30
|
+
| `OTEL_EXPORTER_OTLP_TRACES_HEADERS` | No | Trace-specific headers merged over global headers |
|
|
31
|
+
| `OTEL_EXPORTER_OTLP_METRICS_HEADERS` | No | Metric-specific headers merged over global headers |
|
|
32
|
+
| `OTEL_EXPORTER_OTLP_LOGS_HEADERS` | No | Log-specific headers merged over global headers |
|
|
33
|
+
| `OTEL_SERVICE_NAME` | No | Service name attached to telemetry |
|
|
34
|
+
| `OTEL_TRACES_ENABLED` / `OTEL_TRACES_EXPORTER=otlp` | No | Enables trace export |
|
|
35
|
+
| `OTEL_METRICS_ENABLED` / `OTEL_METRICS_EXPORTER=otlp` | No | Enables metric export |
|
|
36
|
+
| `OTEL_LOGS_ENABLED` / `OTEL_LOGS_EXPORTER=otlp` | No | Enables log export |
|
|
37
|
+
| `OTEL_METRIC_EXPORT_INTERVAL` | No | Metric export interval in milliseconds |
|
|
38
|
+
| `OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE=delta` | No | Metrics temporality. Dedicated service defaults to `delta`. |
|
|
35
39
|
|
|
36
40
|
Configuration is read from process `OTEL_*` environment variables. In shared Veryfront runtimes these are platform-owned host env vars. The extension does not accept `ctx.config.otel` exporter endpoint, header, service name, or enable-flag overrides because project config is tenant controlled in shared runtimes.
|
|
37
41
|
|
|
@@ -47,6 +51,14 @@ Exporter configuration is process-level. Dedicated runtimes can use project-spec
|
|
|
47
51
|
|
|
48
52
|
Set `OTEL_METRICS_ENABLED=true` to export framework metrics through OTLP HTTP. The extension resolves `OTEL_EXPORTER_OTLP_METRICS_ENDPOINT` first, then `OTEL_EXPORTER_OTLP_ENDPOINT`. A base OTLP endpoint receives `/v1/metrics`.
|
|
49
53
|
|
|
54
|
+
Dedicated Node agent services create a startup counter named `veryfront.agent.telemetry.startups` when metrics export is enabled. The dedicated service defaults metric temporality to `delta`, which matches Datadog's OTLP metrics intake requirement.
|
|
55
|
+
|
|
56
|
+
## Logs
|
|
57
|
+
|
|
58
|
+
Set `OTEL_LOGS_ENABLED=true` or `OTEL_LOGS_EXPORTER=otlp` to export structured Veryfront agent logs through OTLP HTTP. The extension resolves `OTEL_EXPORTER_OTLP_LOGS_ENDPOINT` first, then `OTEL_EXPORTER_OTLP_ENDPOINT`. A base OTLP endpoint receives `/v1/logs`.
|
|
59
|
+
|
|
60
|
+
Dedicated Node agent services bridge Veryfront's structured logger into OpenTelemetry logs after telemetry initialization. Log records include the active `trace_id` and `span_id` when available, so Datadog can correlate logs with traces.
|
|
61
|
+
|
|
50
62
|
In shared Veryfront runtimes, these variables are platform-owned host env vars. Project env overlays must not control the shared runtime metrics exporter. Use a dedicated runtime for project-owned collector endpoints or credentials.
|
|
51
63
|
|
|
52
64
|
## Provided contracts
|
package/esm/index.d.ts
CHANGED
|
@@ -19,17 +19,24 @@ export interface ResolvedOtlpExtensionConfig {
|
|
|
19
19
|
serviceName: string;
|
|
20
20
|
serviceVersion: string;
|
|
21
21
|
headers: Record<string, string>;
|
|
22
|
+
tracesHeaders: Record<string, string>;
|
|
23
|
+
metricsHeaders: Record<string, string>;
|
|
24
|
+
logsHeaders: Record<string, string>;
|
|
22
25
|
tracesEnabled: boolean;
|
|
23
26
|
metricsEnabled: boolean;
|
|
27
|
+
logsEnabled: boolean;
|
|
24
28
|
tracesUrl: string | undefined;
|
|
25
29
|
metricsUrl: string | undefined;
|
|
30
|
+
logsUrl: string | undefined;
|
|
26
31
|
metricsExportIntervalMillis: number;
|
|
32
|
+
metricsTemporalityPreference: "delta" | "cumulative" | "lowmemory";
|
|
27
33
|
}
|
|
28
|
-
export declare function resolveOtlpSignalUrl(endpoint: string | undefined, signal: "traces" | "metrics"): string | undefined;
|
|
34
|
+
export declare function resolveOtlpSignalUrl(endpoint: string | undefined, signal: "traces" | "metrics" | "logs"): string | undefined;
|
|
29
35
|
export declare function resolveOtlpExtensionConfig(read?: EnvReader): ResolvedOtlpExtensionConfig;
|
|
30
36
|
declare class OtlpTracingExporter implements TracingExporter {
|
|
31
37
|
private sdkProvider;
|
|
32
38
|
private meterProvider;
|
|
39
|
+
private logProvider;
|
|
33
40
|
private metricsApi;
|
|
34
41
|
private traceApi;
|
|
35
42
|
start(_ctxConfig: Record<string, unknown>): Promise<void>;
|
package/esm/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,EACV,8BAA8B,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,EACV,8BAA8B,EAE9B,qBAAqB,EACrB,QAAQ,EACR,eAAe,EAChB,MAAM,oCAAoC,CAAC;AAE5C;;;GAGG;AACH,UAAU,kBAAkB;IAC1B,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACpD;AA4BD,KAAK,UAAU,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,CAAC;AACpF,KAAK,QAAQ,GAAG;IAAE,aAAa,IAAI,OAAO,CAAC;IAAC,OAAO,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAA;CAAE,CAAC;AAgH7E,KAAK,SAAS,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;AAEtD,MAAM,WAAW,2BAA2B;IAC1C,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,aAAa,EAAE,OAAO,CAAC;IACvB,cAAc,EAAE,OAAO,CAAC;IACxB,WAAW,EAAE,OAAO,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,2BAA2B,EAAE,MAAM,CAAC;IACpC,4BAA4B,EAAE,OAAO,GAAG,YAAY,GAAG,WAAW,CAAC;CACpE;AAoGD,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,MAAM,EAAE,QAAQ,GAAG,SAAS,GAAG,MAAM,GACpC,MAAM,GAAG,SAAS,CAKpB;AAqCD,wBAAgB,0BAA0B,CACxC,IAAI,GAAE,SAAmB,GACxB,2BAA2B,CA8C7B;AAED,cAAM,mBAAoB,YAAW,eAAe;IAClD,OAAO,CAAC,WAAW,CAAkC;IACrD,OAAO,CAAC,aAAa,CAAiC;IACtD,OAAO,CAAC,WAAW,CAAkC;IACrD,OAAO,CAAC,UAAU,CAA2B;IAC7C,OAAO,CAAC,QAAQ,CAAyB;IAEnC,KAAK,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IA4GzD,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAKzC,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IA0B/B,WAAW,IAAI,kBAAkB;IAKjC,aAAa,IAAI,UAAU,GAAG,IAAI;IAIlC,WAAW,IAAI,QAAQ,GAAG,IAAI;CAG/B;AAED,cAAM,kCAAmC,YAAW,qBAAqB;IACvE,OAAO,CAAC,GAAG,CAA8C;IAEnD,UAAU,CAAC,OAAO,EAAE,8BAA8B,GAAG,OAAO,CAAC,OAAO,CAAC;IA4HrE,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAQhC;AAED;;;;;GAKG;AACH,QAAA,MAAM,gBAAgB,EAAE,gBA8CvB,CAAC;AAEF,eAAe,gBAAgB,CAAC;AAChC,OAAO,EAAE,kCAAkC,EAAE,mBAAmB,EAAE,CAAC"}
|
package/esm/index.js
CHANGED
|
@@ -58,12 +58,15 @@ const NOOP_TRACER_PROVIDER = {
|
|
|
58
58
|
};
|
|
59
59
|
async function loadOpenTelemetryRuntime() {
|
|
60
60
|
try {
|
|
61
|
-
const [api, autoInstrumentations, core, contextAsyncHooks, sdkNode, metricsExporter, sdkMetrics, sdkTraceBase, traceExporter, resources, semanticConventions,] = await Promise.all([
|
|
61
|
+
const [api, autoInstrumentations, apiLogs, core, contextAsyncHooks, logsExporter, sdkNode, sdkLogs, metricsExporter, sdkMetrics, sdkTraceBase, traceExporter, resources, semanticConventions,] = await Promise.all([
|
|
62
62
|
import("@opentelemetry/api"),
|
|
63
63
|
import("@opentelemetry/auto-instrumentations-node"),
|
|
64
|
+
import("@opentelemetry/api-logs"),
|
|
64
65
|
import("@opentelemetry/core"),
|
|
65
66
|
import("@opentelemetry/context-async-hooks"),
|
|
67
|
+
import("@opentelemetry/exporter-logs-otlp-http"),
|
|
66
68
|
import("@opentelemetry/sdk-node"),
|
|
69
|
+
import("@opentelemetry/sdk-logs"),
|
|
67
70
|
import("@opentelemetry/exporter-metrics-otlp-http"),
|
|
68
71
|
import("@opentelemetry/sdk-metrics"),
|
|
69
72
|
import("@opentelemetry/sdk-trace-base"),
|
|
@@ -74,9 +77,12 @@ async function loadOpenTelemetryRuntime() {
|
|
|
74
77
|
return {
|
|
75
78
|
api,
|
|
76
79
|
autoInstrumentations,
|
|
80
|
+
apiLogs,
|
|
77
81
|
core,
|
|
78
82
|
contextAsyncHooks,
|
|
83
|
+
logsExporter,
|
|
79
84
|
sdkNode,
|
|
85
|
+
sdkLogs,
|
|
80
86
|
metricsExporter,
|
|
81
87
|
sdkMetrics,
|
|
82
88
|
sdkTraceBase,
|
|
@@ -118,6 +124,60 @@ function parseHeaders(headerInput) {
|
|
|
118
124
|
}
|
|
119
125
|
return result;
|
|
120
126
|
}
|
|
127
|
+
function headersOrDefault(signalHeaders, defaultHeaders) {
|
|
128
|
+
return signalHeaders ?? defaultHeaders;
|
|
129
|
+
}
|
|
130
|
+
function metricTemporalityPreference(otel, preference) {
|
|
131
|
+
const enumValue = otel.metricsExporter.AggregationTemporalityPreference;
|
|
132
|
+
if (preference === "cumulative")
|
|
133
|
+
return enumValue.CUMULATIVE;
|
|
134
|
+
if (preference === "lowmemory")
|
|
135
|
+
return enumValue.LOWMEMORY;
|
|
136
|
+
return enumValue.DELTA;
|
|
137
|
+
}
|
|
138
|
+
function logSeverityNumber(otel, level) {
|
|
139
|
+
switch (level) {
|
|
140
|
+
case "debug":
|
|
141
|
+
return otel.apiLogs.SeverityNumber.DEBUG;
|
|
142
|
+
case "warn":
|
|
143
|
+
return otel.apiLogs.SeverityNumber.WARN;
|
|
144
|
+
case "error":
|
|
145
|
+
return otel.apiLogs.SeverityNumber.ERROR;
|
|
146
|
+
case "info":
|
|
147
|
+
default:
|
|
148
|
+
return otel.apiLogs.SeverityNumber.INFO;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
function logAttributes(record) {
|
|
152
|
+
const attributes = {};
|
|
153
|
+
for (const [key, value] of Object.entries(record)) {
|
|
154
|
+
if (key === "timestamp" ||
|
|
155
|
+
key === "level" ||
|
|
156
|
+
key === "message" ||
|
|
157
|
+
key === "context" ||
|
|
158
|
+
key === "error") {
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
162
|
+
attributes[key] = value;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
if (record.context) {
|
|
166
|
+
for (const [key, value] of Object.entries(record.context)) {
|
|
167
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
168
|
+
attributes[`context.${key}`] = value;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
if (record.error && typeof record.error === "object") {
|
|
173
|
+
const error = record.error;
|
|
174
|
+
if (typeof error.name === "string")
|
|
175
|
+
attributes["error.type"] = error.name;
|
|
176
|
+
if (typeof error.message === "string")
|
|
177
|
+
attributes["error.message"] = error.message;
|
|
178
|
+
}
|
|
179
|
+
return attributes;
|
|
180
|
+
}
|
|
121
181
|
export function resolveOtlpSignalUrl(endpoint, signal) {
|
|
122
182
|
if (!endpoint)
|
|
123
183
|
return undefined;
|
|
@@ -125,34 +185,73 @@ export function resolveOtlpSignalUrl(endpoint, signal) {
|
|
|
125
185
|
const suffix = `/v1/${signal}`;
|
|
126
186
|
return trimmed.endsWith(suffix) ? trimmed : `${trimmed}${suffix}`;
|
|
127
187
|
}
|
|
188
|
+
function isTruthySignalFlag(value) {
|
|
189
|
+
if (value === undefined)
|
|
190
|
+
return undefined;
|
|
191
|
+
return value === "true" || value === "1";
|
|
192
|
+
}
|
|
193
|
+
function exporterIncludesOtlp(value) {
|
|
194
|
+
if (value === undefined)
|
|
195
|
+
return undefined;
|
|
196
|
+
if (value === "none")
|
|
197
|
+
return false;
|
|
198
|
+
return value.split(",").map((part) => part.trim()).includes("otlp");
|
|
199
|
+
}
|
|
200
|
+
function resolveSignalEnabled(enabledValue, exporterValue) {
|
|
201
|
+
const enabledFlag = isTruthySignalFlag(enabledValue);
|
|
202
|
+
if (enabledFlag !== undefined)
|
|
203
|
+
return enabledFlag;
|
|
204
|
+
return exporterIncludesOtlp(exporterValue) ?? false;
|
|
205
|
+
}
|
|
206
|
+
function mergeHeaders(base, override) {
|
|
207
|
+
return { ...base, ...override };
|
|
208
|
+
}
|
|
209
|
+
function resolveMetricsTemporalityPreference(value) {
|
|
210
|
+
const normalized = value?.toLowerCase();
|
|
211
|
+
if (normalized === "cumulative" || normalized === "lowmemory")
|
|
212
|
+
return normalized;
|
|
213
|
+
return "delta";
|
|
214
|
+
}
|
|
128
215
|
export function resolveOtlpExtensionConfig(read = readEnv) {
|
|
129
216
|
const endpoint = read("OTEL_EXPORTER_OTLP_ENDPOINT");
|
|
130
217
|
const tracesEndpoint = read("OTEL_EXPORTER_OTLP_TRACES_ENDPOINT") ?? endpoint;
|
|
131
218
|
const metricsEndpoint = read("OTEL_EXPORTER_OTLP_METRICS_ENDPOINT") ?? endpoint;
|
|
219
|
+
const logsEndpoint = read("OTEL_EXPORTER_OTLP_LOGS_ENDPOINT") ?? endpoint;
|
|
132
220
|
const metricsExportIntervalMillis = Number.parseInt(read("OTEL_METRIC_EXPORT_INTERVAL") ?? "60000", 10);
|
|
221
|
+
const headers = parseHeaders(read("OTEL_EXPORTER_OTLP_HEADERS"));
|
|
222
|
+
const tracesHeaders = mergeHeaders(headers, parseHeaders(read("OTEL_EXPORTER_OTLP_TRACES_HEADERS")));
|
|
223
|
+
const metricsHeaders = mergeHeaders(headers, parseHeaders(read("OTEL_EXPORTER_OTLP_METRICS_HEADERS")));
|
|
224
|
+
const logsHeaders = mergeHeaders(headers, parseHeaders(read("OTEL_EXPORTER_OTLP_LOGS_HEADERS")));
|
|
133
225
|
return {
|
|
134
226
|
serviceName: read("OTEL_SERVICE_NAME") ?? "veryfront",
|
|
135
227
|
serviceVersion: "0.1.0",
|
|
136
|
-
headers
|
|
137
|
-
|
|
138
|
-
|
|
228
|
+
headers,
|
|
229
|
+
tracesHeaders,
|
|
230
|
+
metricsHeaders,
|
|
231
|
+
logsHeaders,
|
|
232
|
+
tracesEnabled: resolveSignalEnabled(read("OTEL_TRACES_ENABLED"), read("OTEL_TRACES_EXPORTER")),
|
|
233
|
+
metricsEnabled: resolveSignalEnabled(read("OTEL_METRICS_ENABLED"), read("OTEL_METRICS_EXPORTER")),
|
|
234
|
+
logsEnabled: resolveSignalEnabled(read("OTEL_LOGS_ENABLED"), read("OTEL_LOGS_EXPORTER")),
|
|
139
235
|
tracesUrl: resolveOtlpSignalUrl(tracesEndpoint, "traces"),
|
|
140
236
|
metricsUrl: resolveOtlpSignalUrl(metricsEndpoint, "metrics"),
|
|
237
|
+
logsUrl: resolveOtlpSignalUrl(logsEndpoint, "logs"),
|
|
141
238
|
metricsExportIntervalMillis: Number.isFinite(metricsExportIntervalMillis)
|
|
142
239
|
? metricsExportIntervalMillis
|
|
143
240
|
: 60_000,
|
|
241
|
+
metricsTemporalityPreference: resolveMetricsTemporalityPreference(read("OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE")),
|
|
144
242
|
};
|
|
145
243
|
}
|
|
146
244
|
class OtlpTracingExporter {
|
|
147
245
|
sdkProvider = null;
|
|
148
246
|
meterProvider = null;
|
|
247
|
+
logProvider = null;
|
|
149
248
|
metricsApi = null;
|
|
150
249
|
traceApi = null;
|
|
151
250
|
async start(_ctxConfig) {
|
|
152
251
|
const cfg = resolveOtlpExtensionConfig(readEnv);
|
|
153
252
|
// Honor OTEL_TRACES_ENABLED: when unset/false, skip exporter wiring so
|
|
154
253
|
// deployments opting out never create OTLP traffic or set globals.
|
|
155
|
-
if (!cfg.tracesEnabled && !cfg.metricsEnabled)
|
|
254
|
+
if (!cfg.tracesEnabled && !cfg.metricsEnabled && !cfg.logsEnabled)
|
|
156
255
|
return;
|
|
157
256
|
const otel = await loadOpenTelemetryRuntime();
|
|
158
257
|
const resource = otel.resources.resourceFromAttributes({
|
|
@@ -165,7 +264,7 @@ class OtlpTracingExporter {
|
|
|
165
264
|
}
|
|
166
265
|
const exporter = new otel.traceExporter.OTLPTraceExporter({
|
|
167
266
|
url: cfg.tracesUrl,
|
|
168
|
-
headers: cfg.
|
|
267
|
+
headers: cfg.tracesHeaders,
|
|
169
268
|
});
|
|
170
269
|
const provider = new otel.sdkTraceBase.BasicTracerProvider({
|
|
171
270
|
resource,
|
|
@@ -192,7 +291,8 @@ class OtlpTracingExporter {
|
|
|
192
291
|
const metricReader = new otel.sdkMetrics.PeriodicExportingMetricReader({
|
|
193
292
|
exporter: new otel.metricsExporter.OTLPMetricExporter({
|
|
194
293
|
url: cfg.metricsUrl,
|
|
195
|
-
headers: cfg.
|
|
294
|
+
headers: cfg.metricsHeaders,
|
|
295
|
+
temporalityPreference: metricTemporalityPreference(otel, cfg.metricsTemporalityPreference),
|
|
196
296
|
}),
|
|
197
297
|
exportIntervalMillis: cfg.metricsExportIntervalMillis,
|
|
198
298
|
});
|
|
@@ -203,6 +303,29 @@ class OtlpTracingExporter {
|
|
|
203
303
|
otel.api.metrics.setGlobalMeterProvider(this.meterProvider);
|
|
204
304
|
this.metricsApi = otel.api.metrics;
|
|
205
305
|
}
|
|
306
|
+
if (cfg.logsEnabled) {
|
|
307
|
+
if (!cfg.logsUrl) {
|
|
308
|
+
throw new Error("OTEL_LOGS_ENABLED=true requires OTEL_EXPORTER_OTLP_ENDPOINT or OTEL_EXPORTER_OTLP_LOGS_ENDPOINT");
|
|
309
|
+
}
|
|
310
|
+
this.logProvider = new otel.sdkLogs.LoggerProvider({
|
|
311
|
+
resource,
|
|
312
|
+
processors: [
|
|
313
|
+
new otel.sdkLogs.BatchLogRecordProcessor(new otel.logsExporter.OTLPLogExporter({
|
|
314
|
+
url: cfg.logsUrl,
|
|
315
|
+
headers: cfg.logsHeaders,
|
|
316
|
+
})),
|
|
317
|
+
],
|
|
318
|
+
});
|
|
319
|
+
otel.apiLogs.logs.setGlobalLoggerProvider(this.logProvider);
|
|
320
|
+
otel.apiLogs.logs.getLogger(cfg.serviceName, cfg.serviceVersion).emit({
|
|
321
|
+
severityNumber: otel.apiLogs.SeverityNumber.INFO,
|
|
322
|
+
severityText: "INFO",
|
|
323
|
+
body: "OpenTelemetry log export initialized",
|
|
324
|
+
attributes: {
|
|
325
|
+
"service.name": cfg.serviceName,
|
|
326
|
+
},
|
|
327
|
+
});
|
|
328
|
+
}
|
|
206
329
|
}
|
|
207
330
|
// eslint-disable-next-line require-await
|
|
208
331
|
async export(_spans) {
|
|
@@ -210,6 +333,14 @@ class OtlpTracingExporter {
|
|
|
210
333
|
// Callers that want to push custom SpanData batches can extend this.
|
|
211
334
|
}
|
|
212
335
|
async shutdown() {
|
|
336
|
+
if (this.logProvider) {
|
|
337
|
+
try {
|
|
338
|
+
await this.logProvider.shutdown();
|
|
339
|
+
}
|
|
340
|
+
finally {
|
|
341
|
+
this.logProvider = null;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
213
344
|
if (this.meterProvider) {
|
|
214
345
|
try {
|
|
215
346
|
await this.meterProvider.shutdown();
|
|
@@ -242,24 +373,56 @@ class OtlpTracingExporter {
|
|
|
242
373
|
class OpenTelemetryNodeTelemetryProvider {
|
|
243
374
|
sdk = null;
|
|
244
375
|
async initialize(options) {
|
|
376
|
+
const tracesEnabled = options.tracesEnabled ?? true;
|
|
377
|
+
const metricsEnabled = options.metricsEnabled ?? false;
|
|
378
|
+
const logsEnabled = options.logsEnabled ?? false;
|
|
379
|
+
if (!tracesEnabled && !metricsEnabled && !logsEnabled)
|
|
380
|
+
return false;
|
|
245
381
|
const otel = await loadOpenTelemetryRuntime();
|
|
246
382
|
const resource = otel.resources.resourceFromAttributes({
|
|
247
383
|
"service.name": options.serviceName,
|
|
248
384
|
"service.version": options.serviceVersion,
|
|
249
385
|
"deployment.environment": options.deploymentEnvironment,
|
|
250
386
|
});
|
|
251
|
-
const
|
|
252
|
-
|
|
253
|
-
|
|
387
|
+
const spanProcessors = tracesEnabled
|
|
388
|
+
? [
|
|
389
|
+
new otel.sdkTraceBase.BatchSpanProcessor(new otel.traceExporter.OTLPTraceExporter({
|
|
390
|
+
url: options.tracesEndpoint,
|
|
391
|
+
headers: headersOrDefault(options.tracesHeaders, options.exporterHeaders),
|
|
392
|
+
}), {
|
|
393
|
+
maxExportBatchSize: 100,
|
|
394
|
+
scheduledDelayMillis: 500,
|
|
395
|
+
}),
|
|
396
|
+
]
|
|
397
|
+
: [];
|
|
398
|
+
const metricReaders = metricsEnabled
|
|
399
|
+
? [
|
|
400
|
+
new otel.sdkMetrics.PeriodicExportingMetricReader({
|
|
401
|
+
exporter: new otel.metricsExporter.OTLPMetricExporter({
|
|
402
|
+
url: options.metricsEndpoint,
|
|
403
|
+
headers: headersOrDefault(options.metricsHeaders, options.exporterHeaders),
|
|
404
|
+
temporalityPreference: metricTemporalityPreference(otel, options.metricsTemporalityPreference),
|
|
405
|
+
}),
|
|
406
|
+
exportIntervalMillis: options.metricsExportIntervalMillis ?? 60_000,
|
|
407
|
+
}),
|
|
408
|
+
]
|
|
409
|
+
: [];
|
|
410
|
+
const logRecordProcessors = logsEnabled
|
|
411
|
+
? [
|
|
412
|
+
new otel.sdkLogs.BatchLogRecordProcessor(new otel.logsExporter.OTLPLogExporter({
|
|
413
|
+
url: options.logsEndpoint,
|
|
414
|
+
headers: headersOrDefault(options.logsHeaders, options.exporterHeaders),
|
|
415
|
+
})),
|
|
416
|
+
]
|
|
417
|
+
: [];
|
|
254
418
|
const sdk = new otel.sdkNode.NodeSDK({
|
|
255
419
|
resource,
|
|
256
420
|
sampler: new otel.sdkTraceBase.ParentBasedSampler({
|
|
257
421
|
root: new otel.sdkTraceBase.TraceIdRatioBasedSampler(options.samplingRatio),
|
|
258
422
|
}),
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
}),
|
|
423
|
+
spanProcessors,
|
|
424
|
+
metricReaders,
|
|
425
|
+
logRecordProcessors,
|
|
263
426
|
instrumentations: [
|
|
264
427
|
otel.autoInstrumentations.getNodeAutoInstrumentations({
|
|
265
428
|
"@opentelemetry/instrumentation-fs": { enabled: options.instrumentation.fs },
|
|
@@ -270,9 +433,42 @@ class OpenTelemetryNodeTelemetryProvider {
|
|
|
270
433
|
});
|
|
271
434
|
sdk.start();
|
|
272
435
|
this.sdk = sdk;
|
|
436
|
+
if (metricsEnabled) {
|
|
437
|
+
otel.api.metrics
|
|
438
|
+
.getMeter(options.serviceName, options.serviceVersion)
|
|
439
|
+
.createCounter("veryfront.agent.telemetry.startups")
|
|
440
|
+
.add(1, {
|
|
441
|
+
"deployment.environment": options.deploymentEnvironment,
|
|
442
|
+
"service.name": options.serviceName,
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
if (logsEnabled) {
|
|
446
|
+
const otelLogger = otel.apiLogs.logs.getLogger(options.serviceName, options.serviceVersion);
|
|
447
|
+
options.registerLogRecordEmitter?.((record) => {
|
|
448
|
+
otelLogger.emit({
|
|
449
|
+
timestamp: record.timestamp ? new Date(record.timestamp) : new Date(),
|
|
450
|
+
severityNumber: logSeverityNumber(otel, record.level),
|
|
451
|
+
severityText: record.level?.toUpperCase() ?? "INFO",
|
|
452
|
+
body: record.message,
|
|
453
|
+
attributes: logAttributes(record),
|
|
454
|
+
});
|
|
455
|
+
});
|
|
456
|
+
otelLogger.emit({
|
|
457
|
+
severityNumber: otel.apiLogs.SeverityNumber.INFO,
|
|
458
|
+
severityText: "INFO",
|
|
459
|
+
body: "OpenTelemetry log export initialized",
|
|
460
|
+
attributes: {
|
|
461
|
+
"deployment.environment": options.deploymentEnvironment,
|
|
462
|
+
"service.name": options.serviceName,
|
|
463
|
+
},
|
|
464
|
+
});
|
|
465
|
+
}
|
|
273
466
|
options.logger?.info("OpenTelemetry initialized", {
|
|
274
467
|
serviceName: options.serviceName,
|
|
275
468
|
samplingRatio: options.samplingRatio,
|
|
469
|
+
tracesEnabled,
|
|
470
|
+
metricsEnabled,
|
|
471
|
+
logsEnabled,
|
|
276
472
|
});
|
|
277
473
|
options.processTarget?.on("SIGTERM", async () => {
|
|
278
474
|
await this.shutdown();
|
|
@@ -314,11 +510,20 @@ const extOpenTelemetry = () => {
|
|
|
314
510
|
"OTEL_EXPORTER_OTLP_ENDPOINT",
|
|
315
511
|
"OTEL_EXPORTER_OTLP_TRACES_ENDPOINT",
|
|
316
512
|
"OTEL_EXPORTER_OTLP_METRICS_ENDPOINT",
|
|
513
|
+
"OTEL_EXPORTER_OTLP_LOGS_ENDPOINT",
|
|
317
514
|
"OTEL_EXPORTER_OTLP_HEADERS",
|
|
515
|
+
"OTEL_EXPORTER_OTLP_TRACES_HEADERS",
|
|
516
|
+
"OTEL_EXPORTER_OTLP_METRICS_HEADERS",
|
|
517
|
+
"OTEL_EXPORTER_OTLP_LOGS_HEADERS",
|
|
318
518
|
"OTEL_SERVICE_NAME",
|
|
319
519
|
"OTEL_TRACES_ENABLED",
|
|
320
520
|
"OTEL_METRICS_ENABLED",
|
|
521
|
+
"OTEL_LOGS_ENABLED",
|
|
522
|
+
"OTEL_TRACES_EXPORTER",
|
|
523
|
+
"OTEL_METRICS_EXPORTER",
|
|
524
|
+
"OTEL_LOGS_EXPORTER",
|
|
321
525
|
"OTEL_METRIC_EXPORT_INTERVAL",
|
|
526
|
+
"OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE",
|
|
322
527
|
],
|
|
323
528
|
},
|
|
324
529
|
],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@veryfront/ext-observability-opentelemetry",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1029",
|
|
4
4
|
"description": "Veryfront first-party extension package for ext-observability-opentelemetry",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"veryfront",
|
|
@@ -53,11 +53,20 @@
|
|
|
53
53
|
"OTEL_EXPORTER_OTLP_ENDPOINT",
|
|
54
54
|
"OTEL_EXPORTER_OTLP_TRACES_ENDPOINT",
|
|
55
55
|
"OTEL_EXPORTER_OTLP_METRICS_ENDPOINT",
|
|
56
|
+
"OTEL_EXPORTER_OTLP_LOGS_ENDPOINT",
|
|
56
57
|
"OTEL_EXPORTER_OTLP_HEADERS",
|
|
58
|
+
"OTEL_EXPORTER_OTLP_TRACES_HEADERS",
|
|
59
|
+
"OTEL_EXPORTER_OTLP_METRICS_HEADERS",
|
|
60
|
+
"OTEL_EXPORTER_OTLP_LOGS_HEADERS",
|
|
57
61
|
"OTEL_SERVICE_NAME",
|
|
58
62
|
"OTEL_TRACES_ENABLED",
|
|
59
63
|
"OTEL_METRICS_ENABLED",
|
|
60
|
-
"
|
|
64
|
+
"OTEL_LOGS_ENABLED",
|
|
65
|
+
"OTEL_TRACES_EXPORTER",
|
|
66
|
+
"OTEL_METRICS_EXPORTER",
|
|
67
|
+
"OTEL_LOGS_EXPORTER",
|
|
68
|
+
"OTEL_METRIC_EXPORT_INTERVAL",
|
|
69
|
+
"OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE"
|
|
61
70
|
]
|
|
62
71
|
}
|
|
63
72
|
]
|
|
@@ -67,19 +76,22 @@
|
|
|
67
76
|
"@deno/shim-crypto": "~0.3.1",
|
|
68
77
|
"@deno/shim-timers": "~0.1.0",
|
|
69
78
|
"@opentelemetry/api": "1.9.1",
|
|
79
|
+
"@opentelemetry/api-logs": "0.219.0",
|
|
70
80
|
"@opentelemetry/auto-instrumentations-node": "0.77.0",
|
|
71
81
|
"@opentelemetry/context-async-hooks": "2.8.0",
|
|
72
82
|
"@opentelemetry/core": "2.8.0",
|
|
83
|
+
"@opentelemetry/exporter-logs-otlp-http": "0.219.0",
|
|
73
84
|
"@opentelemetry/exporter-metrics-otlp-http": "0.219.0",
|
|
74
85
|
"@opentelemetry/exporter-trace-otlp-http": "0.219.0",
|
|
75
86
|
"@opentelemetry/resources": "2.8.0",
|
|
87
|
+
"@opentelemetry/sdk-logs": "0.219.0",
|
|
76
88
|
"@opentelemetry/sdk-metrics": "2.8.0",
|
|
77
89
|
"@opentelemetry/sdk-node": "0.219.0",
|
|
78
90
|
"@opentelemetry/sdk-trace-base": "2.8.0",
|
|
79
91
|
"@opentelemetry/semantic-conventions": "1.41.1"
|
|
80
92
|
},
|
|
81
93
|
"peerDependencies": {
|
|
82
|
-
"veryfront": "^0.1.
|
|
94
|
+
"veryfront": "^0.1.1029"
|
|
83
95
|
},
|
|
84
96
|
"type": "module",
|
|
85
97
|
"types": "./esm/index.d.ts",
|