@sebspark/otel 0.4.4 → 0.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/dist/index.d.mts CHANGED
@@ -1,8 +1,9 @@
1
+ import { LoggerProvider } from '@opentelemetry/api-logs';
1
2
  import * as _opentelemetry_api from '@opentelemetry/api';
2
3
  import { trace, SpanOptions } from '@opentelemetry/api';
3
4
 
4
5
  type Attrs = Record<string, any>;
5
- declare function getLogger(serviceOverride?: string, extraAttrs?: Attrs): {
6
+ declare function getLogger(serviceOverride?: string, extraAttrs?: Attrs, testProvider?: LoggerProvider): {
6
7
  debug: (msg: string, attrs?: Attrs) => void;
7
8
  info: (msg: string, attrs?: Attrs) => void;
8
9
  notice: (msg: string, attrs?: Attrs) => void;
@@ -15,8 +16,6 @@ declare function getLogger(serviceOverride?: string, extraAttrs?: Attrs): {
15
16
 
16
17
  declare function getMeter(componentNameOverride?: string): Promise<_opentelemetry_api.Meter>;
17
18
 
18
- declare function initialize(): Promise<void>;
19
-
20
19
  type OtelTracer = ReturnType<typeof trace.getTracer>;
21
20
  type Span = ReturnType<OtelTracer['startSpan']>;
22
21
  type Func<T> = (span: Span) => Promise<T> | T;
@@ -49,4 +48,4 @@ interface Tracer extends OtelTracer {
49
48
  */
50
49
  declare function getTracer(componentNameOverride?: string): Promise<Tracer>;
51
50
 
52
- export { getLogger, getMeter, getTracer, initialize };
51
+ export { getLogger, getMeter, getTracer };
package/dist/index.d.ts CHANGED
@@ -1,8 +1,9 @@
1
+ import { LoggerProvider } from '@opentelemetry/api-logs';
1
2
  import * as _opentelemetry_api from '@opentelemetry/api';
2
3
  import { trace, SpanOptions } from '@opentelemetry/api';
3
4
 
4
5
  type Attrs = Record<string, any>;
5
- declare function getLogger(serviceOverride?: string, extraAttrs?: Attrs): {
6
+ declare function getLogger(serviceOverride?: string, extraAttrs?: Attrs, testProvider?: LoggerProvider): {
6
7
  debug: (msg: string, attrs?: Attrs) => void;
7
8
  info: (msg: string, attrs?: Attrs) => void;
8
9
  notice: (msg: string, attrs?: Attrs) => void;
@@ -15,8 +16,6 @@ declare function getLogger(serviceOverride?: string, extraAttrs?: Attrs): {
15
16
 
16
17
  declare function getMeter(componentNameOverride?: string): Promise<_opentelemetry_api.Meter>;
17
18
 
18
- declare function initialize(): Promise<void>;
19
-
20
19
  type OtelTracer = ReturnType<typeof trace.getTracer>;
21
20
  type Span = ReturnType<OtelTracer['startSpan']>;
22
21
  type Func<T> = (span: Span) => Promise<T> | T;
@@ -49,4 +48,4 @@ interface Tracer extends OtelTracer {
49
48
  */
50
49
  declare function getTracer(componentNameOverride?: string): Promise<Tracer>;
51
50
 
52
- export { getLogger, getMeter, getTracer, initialize };
51
+ export { getLogger, getMeter, getTracer };
package/dist/index.js CHANGED
@@ -32,14 +32,26 @@ var index_exports = {};
32
32
  __export(index_exports, {
33
33
  getLogger: () => getLogger,
34
34
  getMeter: () => getMeter,
35
- getTracer: () => getTracer,
36
- initialize: () => initialize
35
+ getTracer: () => getTracer
37
36
  });
38
37
  module.exports = __toCommonJS(index_exports);
39
38
 
40
- // src/logger.ts
41
- var import_api = require("@opentelemetry/api");
39
+ // src/otel.ts
40
+ var import_api3 = require("@opentelemetry/api");
42
41
  var import_api_logs = require("@opentelemetry/api-logs");
42
+ var import_auto_instrumentations_node = require("@opentelemetry/auto-instrumentations-node");
43
+ var import_sdk_node = require("@opentelemetry/sdk-node");
44
+
45
+ // src/providers.ts
46
+ var import_exporter_logs_otlp_http = require("@opentelemetry/exporter-logs-otlp-http");
47
+ var import_exporter_metrics_otlp_http = require("@opentelemetry/exporter-metrics-otlp-http");
48
+ var import_exporter_trace_otlp_http = require("@opentelemetry/exporter-trace-otlp-http");
49
+ var import_sdk_logs = require("@opentelemetry/sdk-logs");
50
+ var import_sdk_metrics = require("@opentelemetry/sdk-metrics");
51
+ var import_sdk_trace_node = require("@opentelemetry/sdk-trace-node");
52
+
53
+ // src/loggers/console-log-pretty-exporter.ts
54
+ var import_core = require("@opentelemetry/core");
43
55
 
44
56
  // src/consts.ts
45
57
  var LOG_SEVERITY_MAP = {
@@ -56,119 +68,8 @@ var LOG_SEVERITY_MAP = {
56
68
  EMERGENCY: 23
57
69
  };
58
70
 
59
- // src/otel-context.ts
60
- var import_semantic_conventions = require("@opentelemetry/semantic-conventions");
61
- function detectTelemetryContext(componentNameOverride) {
62
- const {
63
- OTEL_SERVICE_NAME,
64
- // e.g. "UserSystem"
65
- OTEL_SERVICE_VERSION,
66
- // e.g. "1.2.3"
67
- K_SERVICE,
68
- K_REVISION,
69
- K_CONFIGURATION,
70
- KUBERNETES_SERVICE_HOST,
71
- POD_NAME,
72
- POD_NAMESPACE,
73
- GCP_PROJECT,
74
- CLOUD_PROVIDER
75
- } = process.env;
76
- const systemName = OTEL_SERVICE_NAME || "unknown-service";
77
- const systemVersion = OTEL_SERVICE_VERSION || "1.0.0";
78
- const componentName = componentNameOverride || void 0;
79
- const resourceAttributes = {
80
- [import_semantic_conventions.ATTR_SERVICE_NAME]: systemName,
81
- [import_semantic_conventions.ATTR_SERVICE_VERSION]: systemVersion,
82
- "serviceContext.service": systemName,
83
- "serviceContext.version": systemVersion,
84
- ...K_SERVICE && { "cloud.run.service": K_SERVICE },
85
- ...K_REVISION && { "cloud.run.revision": K_REVISION },
86
- ...K_CONFIGURATION && { "cloud.run.configuration": K_CONFIGURATION },
87
- ...POD_NAME && { "k8s.pod_name": POD_NAME },
88
- ...POD_NAMESPACE && { "k8s.namespace_name": POD_NAMESPACE },
89
- ...KUBERNETES_SERVICE_HOST && { "cloud.orchestrator": "kubernetes" },
90
- ...GCP_PROJECT && { "cloud.account.id": GCP_PROJECT },
91
- ...CLOUD_PROVIDER && { "cloud.provider": CLOUD_PROVIDER },
92
- ...componentName && { "component.name": componentName }
93
- };
94
- return {
95
- systemName,
96
- systemVersion,
97
- componentName,
98
- resourceAttributes
99
- };
100
- }
101
-
102
- // src/logger.ts
103
- function getLogger(serviceOverride, extraAttrs = {}) {
104
- const { systemName, systemVersion, resourceAttributes } = detectTelemetryContext(serviceOverride);
105
- const defaultAttrs = {
106
- ...resourceAttributes,
107
- ...extraAttrs
108
- };
109
- function emit(severityText, body, attrs = {}) {
110
- const logger = import_api_logs.logs.getLogger(systemName, systemVersion);
111
- const span = import_api.trace.getSpan(import_api.context.active());
112
- const spanContext = span?.spanContext();
113
- logger.emit({
114
- severityText,
115
- severityNumber: LOG_SEVERITY_MAP[severityText],
116
- body,
117
- attributes: {
118
- ...defaultAttrs,
119
- ...spanContext && {
120
- trace_id: spanContext.traceId,
121
- span_id: spanContext.spanId
122
- },
123
- ...attrs
124
- }
125
- });
126
- }
127
- return {
128
- debug: (msg, attrs) => emit("DEBUG", msg, attrs),
129
- info: (msg, attrs) => emit("INFO", msg, attrs),
130
- notice: (msg, attrs) => emit("NOTICE", msg, attrs),
131
- warn: (msg, attrs) => emit("WARNING", msg, attrs),
132
- error: (msg, errOrAttrs, maybeAttrs = {}) => {
133
- let body;
134
- let attrs;
135
- if (errOrAttrs instanceof Error) {
136
- body = `${msg}: ${errOrAttrs.stack || errOrAttrs.message}`;
137
- attrs = maybeAttrs;
138
- } else {
139
- body = msg instanceof Error ? msg.stack || msg.message : msg;
140
- attrs = errOrAttrs || {};
141
- }
142
- emit("ERROR", body, attrs);
143
- },
144
- critical: (msg, attrs) => emit("CRITICAL", msg, attrs),
145
- alert: (msg, attrs) => emit("ALERT", msg, attrs),
146
- emergency: (msg, attrs) => emit("EMERGENCY", msg, attrs)
147
- };
148
- }
149
-
150
- // src/metrics.ts
151
- var import_api5 = require("@opentelemetry/api");
152
-
153
- // src/otel.ts
154
- var import_api4 = require("@opentelemetry/api");
155
- var import_api_logs2 = require("@opentelemetry/api-logs");
156
- var import_auto_instrumentations_node = require("@opentelemetry/auto-instrumentations-node");
157
- var import_sdk_node = require("@opentelemetry/sdk-node");
158
-
159
- // src/providers.ts
160
- var import_exporter_logs_otlp_http = require("@opentelemetry/exporter-logs-otlp-http");
161
- var import_exporter_metrics_otlp_http = require("@opentelemetry/exporter-metrics-otlp-http");
162
- var import_exporter_trace_otlp_http = require("@opentelemetry/exporter-trace-otlp-http");
163
- var import_sdk_logs = require("@opentelemetry/sdk-logs");
164
- var import_sdk_metrics = require("@opentelemetry/sdk-metrics");
165
- var import_sdk_trace_node = require("@opentelemetry/sdk-trace-node");
166
-
167
- // src/loggers/console-log-pretty-exporter.ts
168
- var import_core = require("@opentelemetry/core");
169
-
170
71
  // src/loggers/formatters/shared.ts
171
- var import_semantic_conventions2 = require("@opentelemetry/semantic-conventions");
72
+ var import_semantic_conventions = require("@opentelemetry/semantic-conventions");
172
73
  var import_fast_safe_stringify = __toESM(require("fast-safe-stringify"));
173
74
 
174
75
  // src/loggers/formatters/style.ts
@@ -229,8 +130,8 @@ function formatTimestamp(time) {
229
130
  return colors.dim(date.toISOString().slice(11, 23));
230
131
  }
231
132
  function formatService(resource) {
232
- const name = resource.attributes[import_semantic_conventions2.ATTR_SERVICE_NAME] ?? "unknown-service";
233
- const version = resource.attributes[import_semantic_conventions2.ATTR_SERVICE_VERSION] ?? "1.0.0";
133
+ const name = resource.attributes[import_semantic_conventions.ATTR_SERVICE_NAME] ?? "unknown-service";
134
+ const version = resource.attributes[import_semantic_conventions.ATTR_SERVICE_VERSION] ?? "1.0.0";
234
135
  return colors.gray(`[${name}@${version}]`);
235
136
  }
236
137
  function formatLevel(record) {
@@ -320,7 +221,7 @@ function isHistogramLike(val) {
320
221
  }
321
222
 
322
223
  // src/loggers/formatters/span.ts
323
- var import_api2 = require("@opentelemetry/api");
224
+ var import_api = require("@opentelemetry/api");
324
225
  var LABEL_WIDTH = 20;
325
226
  var DESCRIPTION_MAX_WIDTH = 16;
326
227
  var BAR_MIN_WIDTH = 1;
@@ -350,7 +251,7 @@ function formatSpans(spans) {
350
251
  function formatSpan(span, opts) {
351
252
  const label = formatLabel(span, opts.depth);
352
253
  const bar = buildBar(span, opts?.offsetMs, opts?.totalDurationMs);
353
- const barColor = span.status.code === import_api2.SpanStatusCode.OK ? colors.green : span.status.code === import_api2.SpanStatusCode.ERROR ? colors.red : colors.gray;
254
+ const barColor = span.status.code === import_api.SpanStatusCode.OK ? colors.green : span.status.code === import_api.SpanStatusCode.ERROR ? colors.red : colors.gray;
354
255
  const desc = formatDescription(span);
355
256
  const status = formatStatus(span);
356
257
  const duration = formatDuration(span, opts?.offsetMs);
@@ -505,7 +406,7 @@ var ConsoleLogPrettyExporter = class {
505
406
  };
506
407
 
507
408
  // src/loggers/console-span-pretty-exporter.ts
508
- var import_api3 = require("@opentelemetry/api");
409
+ var import_api2 = require("@opentelemetry/api");
509
410
  var import_core2 = require("@opentelemetry/core");
510
411
  var ConsoleSpanPrettyExporter = class {
511
412
  allowedStatuses;
@@ -513,15 +414,15 @@ var ConsoleSpanPrettyExporter = class {
513
414
  const env = process.env.SPAN_LEVEL?.toUpperCase();
514
415
  if (!env) {
515
416
  this.allowedStatuses = /* @__PURE__ */ new Set([
516
- import_api3.SpanStatusCode.UNSET,
517
- import_api3.SpanStatusCode.OK,
518
- import_api3.SpanStatusCode.ERROR
417
+ import_api2.SpanStatusCode.UNSET,
418
+ import_api2.SpanStatusCode.OK,
419
+ import_api2.SpanStatusCode.ERROR
519
420
  ]);
520
421
  } else {
521
422
  const map = {
522
- UNSET: import_api3.SpanStatusCode.UNSET,
523
- OK: import_api3.SpanStatusCode.OK,
524
- ERROR: import_api3.SpanStatusCode.ERROR
423
+ UNSET: import_api2.SpanStatusCode.UNSET,
424
+ OK: import_api2.SpanStatusCode.OK,
425
+ ERROR: import_api2.SpanStatusCode.ERROR
525
426
  };
526
427
  this.allowedStatuses = new Set(
527
428
  env.split(",").map((s) => s.trim()).map((s) => map[s]).filter((v) => typeof v === "number")
@@ -679,6 +580,51 @@ var getMetricReader = (otlpEndpoint) => {
679
580
 
680
581
  // src/resource.ts
681
582
  var import_resources = require("@opentelemetry/resources");
583
+
584
+ // src/otel-context.ts
585
+ var import_semantic_conventions2 = require("@opentelemetry/semantic-conventions");
586
+ function detectTelemetryContext(componentNameOverride) {
587
+ const {
588
+ OTEL_SERVICE_NAME,
589
+ // e.g. "UserSystem"
590
+ OTEL_SERVICE_VERSION,
591
+ // e.g. "1.2.3"
592
+ K_SERVICE,
593
+ K_REVISION,
594
+ K_CONFIGURATION,
595
+ KUBERNETES_SERVICE_HOST,
596
+ POD_NAME,
597
+ POD_NAMESPACE,
598
+ GCP_PROJECT,
599
+ CLOUD_PROVIDER
600
+ } = process.env;
601
+ const systemName = OTEL_SERVICE_NAME || "unknown-service";
602
+ const systemVersion = OTEL_SERVICE_VERSION || "1.0.0";
603
+ const componentName = componentNameOverride || void 0;
604
+ const resourceAttributes = {
605
+ [import_semantic_conventions2.ATTR_SERVICE_NAME]: systemName,
606
+ [import_semantic_conventions2.ATTR_SERVICE_VERSION]: systemVersion,
607
+ "serviceContext.service": systemName,
608
+ "serviceContext.version": systemVersion,
609
+ ...K_SERVICE && { "cloud.run.service": K_SERVICE },
610
+ ...K_REVISION && { "cloud.run.revision": K_REVISION },
611
+ ...K_CONFIGURATION && { "cloud.run.configuration": K_CONFIGURATION },
612
+ ...POD_NAME && { "k8s.pod_name": POD_NAME },
613
+ ...POD_NAMESPACE && { "k8s.namespace_name": POD_NAMESPACE },
614
+ ...KUBERNETES_SERVICE_HOST && { "cloud.orchestrator": "kubernetes" },
615
+ ...GCP_PROJECT && { "cloud.account.id": GCP_PROJECT },
616
+ ...CLOUD_PROVIDER && { "cloud.provider": CLOUD_PROVIDER },
617
+ ...componentName && { "component.name": componentName }
618
+ };
619
+ return {
620
+ systemName,
621
+ systemVersion,
622
+ componentName,
623
+ resourceAttributes
624
+ };
625
+ }
626
+
627
+ // src/resource.ts
682
628
  var getResource = async () => {
683
629
  const baseRes = await (0, import_resources.detectResources)();
684
630
  const { resourceAttributes } = detectTelemetryContext();
@@ -691,21 +637,29 @@ var getResource = async () => {
691
637
  };
692
638
 
693
639
  // src/otel.ts
694
- import_api4.diag.setLogger(new import_api4.DiagConsoleLogger(), import_api4.DiagLogLevel.ERROR);
695
640
  var initialization;
696
641
  async function initialize() {
697
642
  if (!initialization) {
698
- initialization = _initialize();
643
+ import_api3.diag.setLogger(new import_api3.DiagConsoleLogger(), import_api3.DiagLogLevel.ERROR);
644
+ initialization = initializeOtel();
699
645
  }
700
646
  return initialization;
701
647
  }
702
- async function _initialize() {
648
+ function isInitialized() {
649
+ return initialization !== void 0;
650
+ }
651
+ async function initializeOtel() {
703
652
  try {
704
653
  const serviceName = process.env.OTEL_SERVICE_NAME ?? "unknown-service";
705
654
  const otlpEndpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT;
655
+ const isTestMode = process.env.NODE_ENV === "test" || process.env.VITEST === "true";
706
656
  const resource = await getResource();
707
- const logProvider = getLogProvider(resource, otlpEndpoint);
708
- import_api_logs2.logs.setGlobalLoggerProvider(logProvider);
657
+ let logProvider;
658
+ const shouldSetupLogProvider = !isTestMode || !!process.env.LOG_LEVEL;
659
+ if (shouldSetupLogProvider) {
660
+ logProvider = getLogProvider(resource, otlpEndpoint);
661
+ import_api_logs.logs.setGlobalLoggerProvider(logProvider);
662
+ }
709
663
  const spanProcessor = getSpanProcessor(otlpEndpoint);
710
664
  const metricReader = getMetricReader(otlpEndpoint);
711
665
  const sdk = new import_sdk_node.NodeSDK({
@@ -718,16 +672,80 @@ async function _initialize() {
718
672
  console.log(`[otel] Telemetry initialized for "${serviceName}"`);
719
673
  process.on("SIGTERM", async () => {
720
674
  console.log("[otel] Shutting down...");
721
- await Promise.all([sdk.shutdown(), logProvider.shutdown()]);
675
+ const shutdownPromises = [sdk.shutdown()];
676
+ if (logProvider) {
677
+ shutdownPromises.push(logProvider.shutdown());
678
+ }
679
+ await Promise.all(shutdownPromises);
722
680
  console.log("[otel] Shutdown complete.");
723
681
  process.exit(0);
724
682
  });
725
683
  } catch (err) {
726
- console.error("[otel] Startup error:", err);
684
+ if (err instanceof Error && err.message.includes("duplicate registration")) {
685
+ console.warn("[otel] Warning - API already registered, continuing...");
686
+ } else {
687
+ console.error("[otel] Startup error:", err);
688
+ }
727
689
  }
728
690
  }
729
691
 
692
+ // src/logger.ts
693
+ var import_api4 = require("@opentelemetry/api");
694
+ var import_api_logs2 = require("@opentelemetry/api-logs");
695
+ function getLogger(serviceOverride, extraAttrs = {}, testProvider) {
696
+ if (!isInitialized()) {
697
+ throw new Error(
698
+ "OpenTelemetry is not initialized. Please call initialize() before getting a logger."
699
+ );
700
+ }
701
+ const { systemName, systemVersion, resourceAttributes } = detectTelemetryContext(serviceOverride);
702
+ const defaultAttrs = {
703
+ ...resourceAttributes,
704
+ ...extraAttrs
705
+ };
706
+ function emit(severityText, body, attrs = {}) {
707
+ const logger = testProvider ? testProvider.getLogger(systemName, systemVersion) : import_api_logs2.logs.getLogger(systemName, systemVersion);
708
+ const span = import_api4.trace.getSpan(import_api4.context.active());
709
+ const spanContext = span?.spanContext();
710
+ logger.emit({
711
+ severityText,
712
+ severityNumber: LOG_SEVERITY_MAP[severityText],
713
+ body,
714
+ attributes: {
715
+ ...defaultAttrs,
716
+ ...spanContext && {
717
+ trace_id: spanContext.traceId,
718
+ span_id: spanContext.spanId
719
+ },
720
+ ...attrs
721
+ }
722
+ });
723
+ }
724
+ return {
725
+ debug: (msg, attrs) => emit("DEBUG", msg, attrs),
726
+ info: (msg, attrs) => emit("INFO", msg, attrs),
727
+ notice: (msg, attrs) => emit("NOTICE", msg, attrs),
728
+ warn: (msg, attrs) => emit("WARNING", msg, attrs),
729
+ error: (msg, errOrAttrs, maybeAttrs = {}) => {
730
+ let body;
731
+ let attrs;
732
+ if (errOrAttrs instanceof Error) {
733
+ body = `${msg}: ${errOrAttrs.stack || errOrAttrs.message}`;
734
+ attrs = maybeAttrs;
735
+ } else {
736
+ body = msg instanceof Error ? msg.stack || msg.message : msg;
737
+ attrs = errOrAttrs || {};
738
+ }
739
+ emit("ERROR", body, attrs);
740
+ },
741
+ critical: (msg, attrs) => emit("CRITICAL", msg, attrs),
742
+ alert: (msg, attrs) => emit("ALERT", msg, attrs),
743
+ emergency: (msg, attrs) => emit("EMERGENCY", msg, attrs)
744
+ };
745
+ }
746
+
730
747
  // src/metrics.ts
748
+ var import_api5 = require("@opentelemetry/api");
731
749
  async function getMeter(componentNameOverride) {
732
750
  await initialize();
733
751
  const { componentName, systemName, systemVersion } = detectTelemetryContext(
@@ -821,10 +839,12 @@ function extractArgs(spanOptionsSpanOrFunc, spanOrFunc, func) {
821
839
  var isFunction = (value) => typeof value === "function";
822
840
  var isSpan = (value) => value !== null && value !== void 0 && isFunction(value.spanContext) && isFunction(value.end);
823
841
  var isSpanOptions = (value) => value !== null && value !== void 0 && (!!value.startTime || !!value.attributes || !!value.kind) && !isSpan(value);
842
+
843
+ // src/index.ts
844
+ initialize();
824
845
  // Annotate the CommonJS export names for ESM import in node:
825
846
  0 && (module.exports = {
826
847
  getLogger,
827
848
  getMeter,
828
- getTracer,
829
- initialize
849
+ getTracer
830
850
  });
package/dist/index.mjs CHANGED
@@ -1,122 +1,6 @@
1
- // src/logger.ts
2
- import { context, trace } from "@opentelemetry/api";
3
- import { logs } from "@opentelemetry/api-logs";
4
-
5
- // src/consts.ts
6
- var LOG_SEVERITY_MAP = {
7
- TRACE: 1,
8
- DEBUG: 5,
9
- INFO: 9,
10
- NOTICE: 10,
11
- WARNING: 13,
12
- WARN: 13,
13
- ERROR: 17,
14
- FATAL: 21,
15
- CRITICAL: 21,
16
- ALERT: 22,
17
- EMERGENCY: 23
18
- };
19
-
20
- // src/otel-context.ts
21
- import {
22
- ATTR_SERVICE_NAME,
23
- ATTR_SERVICE_VERSION
24
- } from "@opentelemetry/semantic-conventions";
25
- function detectTelemetryContext(componentNameOverride) {
26
- const {
27
- OTEL_SERVICE_NAME,
28
- // e.g. "UserSystem"
29
- OTEL_SERVICE_VERSION,
30
- // e.g. "1.2.3"
31
- K_SERVICE,
32
- K_REVISION,
33
- K_CONFIGURATION,
34
- KUBERNETES_SERVICE_HOST,
35
- POD_NAME,
36
- POD_NAMESPACE,
37
- GCP_PROJECT,
38
- CLOUD_PROVIDER
39
- } = process.env;
40
- const systemName = OTEL_SERVICE_NAME || "unknown-service";
41
- const systemVersion = OTEL_SERVICE_VERSION || "1.0.0";
42
- const componentName = componentNameOverride || void 0;
43
- const resourceAttributes = {
44
- [ATTR_SERVICE_NAME]: systemName,
45
- [ATTR_SERVICE_VERSION]: systemVersion,
46
- "serviceContext.service": systemName,
47
- "serviceContext.version": systemVersion,
48
- ...K_SERVICE && { "cloud.run.service": K_SERVICE },
49
- ...K_REVISION && { "cloud.run.revision": K_REVISION },
50
- ...K_CONFIGURATION && { "cloud.run.configuration": K_CONFIGURATION },
51
- ...POD_NAME && { "k8s.pod_name": POD_NAME },
52
- ...POD_NAMESPACE && { "k8s.namespace_name": POD_NAMESPACE },
53
- ...KUBERNETES_SERVICE_HOST && { "cloud.orchestrator": "kubernetes" },
54
- ...GCP_PROJECT && { "cloud.account.id": GCP_PROJECT },
55
- ...CLOUD_PROVIDER && { "cloud.provider": CLOUD_PROVIDER },
56
- ...componentName && { "component.name": componentName }
57
- };
58
- return {
59
- systemName,
60
- systemVersion,
61
- componentName,
62
- resourceAttributes
63
- };
64
- }
65
-
66
- // src/logger.ts
67
- function getLogger(serviceOverride, extraAttrs = {}) {
68
- const { systemName, systemVersion, resourceAttributes } = detectTelemetryContext(serviceOverride);
69
- const defaultAttrs = {
70
- ...resourceAttributes,
71
- ...extraAttrs
72
- };
73
- function emit(severityText, body, attrs = {}) {
74
- const logger = logs.getLogger(systemName, systemVersion);
75
- const span = trace.getSpan(context.active());
76
- const spanContext = span?.spanContext();
77
- logger.emit({
78
- severityText,
79
- severityNumber: LOG_SEVERITY_MAP[severityText],
80
- body,
81
- attributes: {
82
- ...defaultAttrs,
83
- ...spanContext && {
84
- trace_id: spanContext.traceId,
85
- span_id: spanContext.spanId
86
- },
87
- ...attrs
88
- }
89
- });
90
- }
91
- return {
92
- debug: (msg, attrs) => emit("DEBUG", msg, attrs),
93
- info: (msg, attrs) => emit("INFO", msg, attrs),
94
- notice: (msg, attrs) => emit("NOTICE", msg, attrs),
95
- warn: (msg, attrs) => emit("WARNING", msg, attrs),
96
- error: (msg, errOrAttrs, maybeAttrs = {}) => {
97
- let body;
98
- let attrs;
99
- if (errOrAttrs instanceof Error) {
100
- body = `${msg}: ${errOrAttrs.stack || errOrAttrs.message}`;
101
- attrs = maybeAttrs;
102
- } else {
103
- body = msg instanceof Error ? msg.stack || msg.message : msg;
104
- attrs = errOrAttrs || {};
105
- }
106
- emit("ERROR", body, attrs);
107
- },
108
- critical: (msg, attrs) => emit("CRITICAL", msg, attrs),
109
- alert: (msg, attrs) => emit("ALERT", msg, attrs),
110
- emergency: (msg, attrs) => emit("EMERGENCY", msg, attrs)
111
- };
112
- }
113
-
114
- // src/metrics.ts
115
- import { metrics } from "@opentelemetry/api";
116
-
117
1
  // src/otel.ts
118
2
  import { DiagConsoleLogger, DiagLogLevel, diag } from "@opentelemetry/api";
119
- import { logs as logs2 } from "@opentelemetry/api-logs";
3
+ import { logs } from "@opentelemetry/api-logs";
120
4
  import { getNodeAutoInstrumentations } from "@opentelemetry/auto-instrumentations-node";
121
5
  import { NodeSDK } from "@opentelemetry/sdk-node";
122
6
 
@@ -137,10 +21,25 @@ import {
137
21
  // src/loggers/console-log-pretty-exporter.ts
138
22
  import { ExportResultCode } from "@opentelemetry/core";
139
23
 
24
+ // src/consts.ts
25
+ var LOG_SEVERITY_MAP = {
26
+ TRACE: 1,
27
+ DEBUG: 5,
28
+ INFO: 9,
29
+ NOTICE: 10,
30
+ WARNING: 13,
31
+ WARN: 13,
32
+ ERROR: 17,
33
+ FATAL: 21,
34
+ CRITICAL: 21,
35
+ ALERT: 22,
36
+ EMERGENCY: 23
37
+ };
38
+
140
39
  // src/loggers/formatters/shared.ts
141
40
  import {
142
- ATTR_SERVICE_NAME as ATTR_SERVICE_NAME2,
143
- ATTR_SERVICE_VERSION as ATTR_SERVICE_VERSION2
41
+ ATTR_SERVICE_NAME,
42
+ ATTR_SERVICE_VERSION
144
43
  } from "@opentelemetry/semantic-conventions";
145
44
  import stringify from "fast-safe-stringify";
146
45
 
@@ -202,8 +101,8 @@ function formatTimestamp(time) {
202
101
  return colors.dim(date.toISOString().slice(11, 23));
203
102
  }
204
103
  function formatService(resource) {
205
- const name = resource.attributes[ATTR_SERVICE_NAME2] ?? "unknown-service";
206
- const version = resource.attributes[ATTR_SERVICE_VERSION2] ?? "1.0.0";
104
+ const name = resource.attributes[ATTR_SERVICE_NAME] ?? "unknown-service";
105
+ const version = resource.attributes[ATTR_SERVICE_VERSION] ?? "1.0.0";
207
106
  return colors.gray(`[${name}@${version}]`);
208
107
  }
209
108
  function formatLevel(record) {
@@ -655,6 +554,54 @@ import {
655
554
  detectResources,
656
555
  resourceFromAttributes
657
556
  } from "@opentelemetry/resources";
557
+
558
+ // src/otel-context.ts
559
+ import {
560
+ ATTR_SERVICE_NAME as ATTR_SERVICE_NAME2,
561
+ ATTR_SERVICE_VERSION as ATTR_SERVICE_VERSION2
562
+ } from "@opentelemetry/semantic-conventions";
563
+ function detectTelemetryContext(componentNameOverride) {
564
+ const {
565
+ OTEL_SERVICE_NAME,
566
+ // e.g. "UserSystem"
567
+ OTEL_SERVICE_VERSION,
568
+ // e.g. "1.2.3"
569
+ K_SERVICE,
570
+ K_REVISION,
571
+ K_CONFIGURATION,
572
+ KUBERNETES_SERVICE_HOST,
573
+ POD_NAME,
574
+ POD_NAMESPACE,
575
+ GCP_PROJECT,
576
+ CLOUD_PROVIDER
577
+ } = process.env;
578
+ const systemName = OTEL_SERVICE_NAME || "unknown-service";
579
+ const systemVersion = OTEL_SERVICE_VERSION || "1.0.0";
580
+ const componentName = componentNameOverride || void 0;
581
+ const resourceAttributes = {
582
+ [ATTR_SERVICE_NAME2]: systemName,
583
+ [ATTR_SERVICE_VERSION2]: systemVersion,
584
+ "serviceContext.service": systemName,
585
+ "serviceContext.version": systemVersion,
586
+ ...K_SERVICE && { "cloud.run.service": K_SERVICE },
587
+ ...K_REVISION && { "cloud.run.revision": K_REVISION },
588
+ ...K_CONFIGURATION && { "cloud.run.configuration": K_CONFIGURATION },
589
+ ...POD_NAME && { "k8s.pod_name": POD_NAME },
590
+ ...POD_NAMESPACE && { "k8s.namespace_name": POD_NAMESPACE },
591
+ ...KUBERNETES_SERVICE_HOST && { "cloud.orchestrator": "kubernetes" },
592
+ ...GCP_PROJECT && { "cloud.account.id": GCP_PROJECT },
593
+ ...CLOUD_PROVIDER && { "cloud.provider": CLOUD_PROVIDER },
594
+ ...componentName && { "component.name": componentName }
595
+ };
596
+ return {
597
+ systemName,
598
+ systemVersion,
599
+ componentName,
600
+ resourceAttributes
601
+ };
602
+ }
603
+
604
+ // src/resource.ts
658
605
  var getResource = async () => {
659
606
  const baseRes = await detectResources();
660
607
  const { resourceAttributes } = detectTelemetryContext();
@@ -667,21 +614,29 @@ var getResource = async () => {
667
614
  };
668
615
 
669
616
  // src/otel.ts
670
- diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.ERROR);
671
617
  var initialization;
672
618
  async function initialize() {
673
619
  if (!initialization) {
674
- initialization = _initialize();
620
+ diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.ERROR);
621
+ initialization = initializeOtel();
675
622
  }
676
623
  return initialization;
677
624
  }
678
- async function _initialize() {
625
+ function isInitialized() {
626
+ return initialization !== void 0;
627
+ }
628
+ async function initializeOtel() {
679
629
  try {
680
630
  const serviceName = process.env.OTEL_SERVICE_NAME ?? "unknown-service";
681
631
  const otlpEndpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT;
632
+ const isTestMode = process.env.NODE_ENV === "test" || process.env.VITEST === "true";
682
633
  const resource = await getResource();
683
- const logProvider = getLogProvider(resource, otlpEndpoint);
684
- logs2.setGlobalLoggerProvider(logProvider);
634
+ let logProvider;
635
+ const shouldSetupLogProvider = !isTestMode || !!process.env.LOG_LEVEL;
636
+ if (shouldSetupLogProvider) {
637
+ logProvider = getLogProvider(resource, otlpEndpoint);
638
+ logs.setGlobalLoggerProvider(logProvider);
639
+ }
685
640
  const spanProcessor = getSpanProcessor(otlpEndpoint);
686
641
  const metricReader = getMetricReader(otlpEndpoint);
687
642
  const sdk = new NodeSDK({
@@ -694,16 +649,80 @@ async function _initialize() {
694
649
  console.log(`[otel] Telemetry initialized for "${serviceName}"`);
695
650
  process.on("SIGTERM", async () => {
696
651
  console.log("[otel] Shutting down...");
697
- await Promise.all([sdk.shutdown(), logProvider.shutdown()]);
652
+ const shutdownPromises = [sdk.shutdown()];
653
+ if (logProvider) {
654
+ shutdownPromises.push(logProvider.shutdown());
655
+ }
656
+ await Promise.all(shutdownPromises);
698
657
  console.log("[otel] Shutdown complete.");
699
658
  process.exit(0);
700
659
  });
701
660
  } catch (err) {
702
- console.error("[otel] Startup error:", err);
661
+ if (err instanceof Error && err.message.includes("duplicate registration")) {
662
+ console.warn("[otel] Warning - API already registered, continuing...");
663
+ } else {
664
+ console.error("[otel] Startup error:", err);
665
+ }
703
666
  }
704
667
  }
705
668
 
669
+ // src/logger.ts
670
+ import { context, trace } from "@opentelemetry/api";
671
+ import { logs as logs2 } from "@opentelemetry/api-logs";
672
+ function getLogger(serviceOverride, extraAttrs = {}, testProvider) {
673
+ if (!isInitialized()) {
674
+ throw new Error(
675
+ "OpenTelemetry is not initialized. Please call initialize() before getting a logger."
676
+ );
677
+ }
678
+ const { systemName, systemVersion, resourceAttributes } = detectTelemetryContext(serviceOverride);
679
+ const defaultAttrs = {
680
+ ...resourceAttributes,
681
+ ...extraAttrs
682
+ };
683
+ function emit(severityText, body, attrs = {}) {
684
+ const logger = testProvider ? testProvider.getLogger(systemName, systemVersion) : logs2.getLogger(systemName, systemVersion);
685
+ const span = trace.getSpan(context.active());
686
+ const spanContext = span?.spanContext();
687
+ logger.emit({
688
+ severityText,
689
+ severityNumber: LOG_SEVERITY_MAP[severityText],
690
+ body,
691
+ attributes: {
692
+ ...defaultAttrs,
693
+ ...spanContext && {
694
+ trace_id: spanContext.traceId,
695
+ span_id: spanContext.spanId
696
+ },
697
+ ...attrs
698
+ }
699
+ });
700
+ }
701
+ return {
702
+ debug: (msg, attrs) => emit("DEBUG", msg, attrs),
703
+ info: (msg, attrs) => emit("INFO", msg, attrs),
704
+ notice: (msg, attrs) => emit("NOTICE", msg, attrs),
705
+ warn: (msg, attrs) => emit("WARNING", msg, attrs),
706
+ error: (msg, errOrAttrs, maybeAttrs = {}) => {
707
+ let body;
708
+ let attrs;
709
+ if (errOrAttrs instanceof Error) {
710
+ body = `${msg}: ${errOrAttrs.stack || errOrAttrs.message}`;
711
+ attrs = maybeAttrs;
712
+ } else {
713
+ body = msg instanceof Error ? msg.stack || msg.message : msg;
714
+ attrs = errOrAttrs || {};
715
+ }
716
+ emit("ERROR", body, attrs);
717
+ },
718
+ critical: (msg, attrs) => emit("CRITICAL", msg, attrs),
719
+ alert: (msg, attrs) => emit("ALERT", msg, attrs),
720
+ emergency: (msg, attrs) => emit("EMERGENCY", msg, attrs)
721
+ };
722
+ }
723
+
706
724
  // src/metrics.ts
725
+ import { metrics } from "@opentelemetry/api";
707
726
  async function getMeter(componentNameOverride) {
708
727
  await initialize();
709
728
  const { componentName, systemName, systemVersion } = detectTelemetryContext(
@@ -801,9 +820,11 @@ function extractArgs(spanOptionsSpanOrFunc, spanOrFunc, func) {
801
820
  var isFunction = (value) => typeof value === "function";
802
821
  var isSpan = (value) => value !== null && value !== void 0 && isFunction(value.spanContext) && isFunction(value.end);
803
822
  var isSpanOptions = (value) => value !== null && value !== void 0 && (!!value.startTime || !!value.attributes || !!value.kind) && !isSpan(value);
823
+
824
+ // src/index.ts
825
+ initialize();
804
826
  export {
805
827
  getLogger,
806
828
  getMeter,
807
- getTracer,
808
- initialize
829
+ getTracer
809
830
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sebspark/otel",
3
- "version": "0.4.4",
3
+ "version": "0.5.1",
4
4
  "license": "Apache-2.0",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",