@sebspark/otel 0.4.4 → 0.5.0

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;
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;
package/dist/index.js CHANGED
@@ -38,8 +38,8 @@ __export(index_exports, {
38
38
  module.exports = __toCommonJS(index_exports);
39
39
 
40
40
  // src/logger.ts
41
- var import_api = require("@opentelemetry/api");
42
- var import_api_logs = require("@opentelemetry/api-logs");
41
+ var import_api4 = require("@opentelemetry/api");
42
+ var import_api_logs2 = require("@opentelemetry/api-logs");
43
43
 
44
44
  // src/consts.ts
45
45
  var LOG_SEVERITY_MAP = {
@@ -56,103 +56,9 @@ var LOG_SEVERITY_MAP = {
56
56
  EMERGENCY: 23
57
57
  };
58
58
 
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
59
  // src/otel.ts
154
- var import_api4 = require("@opentelemetry/api");
155
- var import_api_logs2 = require("@opentelemetry/api-logs");
60
+ var import_api3 = require("@opentelemetry/api");
61
+ var import_api_logs = require("@opentelemetry/api-logs");
156
62
  var import_auto_instrumentations_node = require("@opentelemetry/auto-instrumentations-node");
157
63
  var import_sdk_node = require("@opentelemetry/sdk-node");
158
64
 
@@ -168,7 +74,7 @@ var import_sdk_trace_node = require("@opentelemetry/sdk-trace-node");
168
74
  var import_core = require("@opentelemetry/core");
169
75
 
170
76
  // src/loggers/formatters/shared.ts
171
- var import_semantic_conventions2 = require("@opentelemetry/semantic-conventions");
77
+ var import_semantic_conventions = require("@opentelemetry/semantic-conventions");
172
78
  var import_fast_safe_stringify = __toESM(require("fast-safe-stringify"));
173
79
 
174
80
  // src/loggers/formatters/style.ts
@@ -229,8 +135,8 @@ function formatTimestamp(time) {
229
135
  return colors.dim(date.toISOString().slice(11, 23));
230
136
  }
231
137
  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";
138
+ const name = resource.attributes[import_semantic_conventions.ATTR_SERVICE_NAME] ?? "unknown-service";
139
+ const version = resource.attributes[import_semantic_conventions.ATTR_SERVICE_VERSION] ?? "1.0.0";
234
140
  return colors.gray(`[${name}@${version}]`);
235
141
  }
236
142
  function formatLevel(record) {
@@ -320,7 +226,7 @@ function isHistogramLike(val) {
320
226
  }
321
227
 
322
228
  // src/loggers/formatters/span.ts
323
- var import_api2 = require("@opentelemetry/api");
229
+ var import_api = require("@opentelemetry/api");
324
230
  var LABEL_WIDTH = 20;
325
231
  var DESCRIPTION_MAX_WIDTH = 16;
326
232
  var BAR_MIN_WIDTH = 1;
@@ -350,7 +256,7 @@ function formatSpans(spans) {
350
256
  function formatSpan(span, opts) {
351
257
  const label = formatLabel(span, opts.depth);
352
258
  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;
259
+ const barColor = span.status.code === import_api.SpanStatusCode.OK ? colors.green : span.status.code === import_api.SpanStatusCode.ERROR ? colors.red : colors.gray;
354
260
  const desc = formatDescription(span);
355
261
  const status = formatStatus(span);
356
262
  const duration = formatDuration(span, opts?.offsetMs);
@@ -505,7 +411,7 @@ var ConsoleLogPrettyExporter = class {
505
411
  };
506
412
 
507
413
  // src/loggers/console-span-pretty-exporter.ts
508
- var import_api3 = require("@opentelemetry/api");
414
+ var import_api2 = require("@opentelemetry/api");
509
415
  var import_core2 = require("@opentelemetry/core");
510
416
  var ConsoleSpanPrettyExporter = class {
511
417
  allowedStatuses;
@@ -513,15 +419,15 @@ var ConsoleSpanPrettyExporter = class {
513
419
  const env = process.env.SPAN_LEVEL?.toUpperCase();
514
420
  if (!env) {
515
421
  this.allowedStatuses = /* @__PURE__ */ new Set([
516
- import_api3.SpanStatusCode.UNSET,
517
- import_api3.SpanStatusCode.OK,
518
- import_api3.SpanStatusCode.ERROR
422
+ import_api2.SpanStatusCode.UNSET,
423
+ import_api2.SpanStatusCode.OK,
424
+ import_api2.SpanStatusCode.ERROR
519
425
  ]);
520
426
  } else {
521
427
  const map = {
522
- UNSET: import_api3.SpanStatusCode.UNSET,
523
- OK: import_api3.SpanStatusCode.OK,
524
- ERROR: import_api3.SpanStatusCode.ERROR
428
+ UNSET: import_api2.SpanStatusCode.UNSET,
429
+ OK: import_api2.SpanStatusCode.OK,
430
+ ERROR: import_api2.SpanStatusCode.ERROR
525
431
  };
526
432
  this.allowedStatuses = new Set(
527
433
  env.split(",").map((s) => s.trim()).map((s) => map[s]).filter((v) => typeof v === "number")
@@ -679,6 +585,51 @@ var getMetricReader = (otlpEndpoint) => {
679
585
 
680
586
  // src/resource.ts
681
587
  var import_resources = require("@opentelemetry/resources");
588
+
589
+ // src/otel-context.ts
590
+ var import_semantic_conventions2 = require("@opentelemetry/semantic-conventions");
591
+ function detectTelemetryContext(componentNameOverride) {
592
+ const {
593
+ OTEL_SERVICE_NAME,
594
+ // e.g. "UserSystem"
595
+ OTEL_SERVICE_VERSION,
596
+ // e.g. "1.2.3"
597
+ K_SERVICE,
598
+ K_REVISION,
599
+ K_CONFIGURATION,
600
+ KUBERNETES_SERVICE_HOST,
601
+ POD_NAME,
602
+ POD_NAMESPACE,
603
+ GCP_PROJECT,
604
+ CLOUD_PROVIDER
605
+ } = process.env;
606
+ const systemName = OTEL_SERVICE_NAME || "unknown-service";
607
+ const systemVersion = OTEL_SERVICE_VERSION || "1.0.0";
608
+ const componentName = componentNameOverride || void 0;
609
+ const resourceAttributes = {
610
+ [import_semantic_conventions2.ATTR_SERVICE_NAME]: systemName,
611
+ [import_semantic_conventions2.ATTR_SERVICE_VERSION]: systemVersion,
612
+ "serviceContext.service": systemName,
613
+ "serviceContext.version": systemVersion,
614
+ ...K_SERVICE && { "cloud.run.service": K_SERVICE },
615
+ ...K_REVISION && { "cloud.run.revision": K_REVISION },
616
+ ...K_CONFIGURATION && { "cloud.run.configuration": K_CONFIGURATION },
617
+ ...POD_NAME && { "k8s.pod_name": POD_NAME },
618
+ ...POD_NAMESPACE && { "k8s.namespace_name": POD_NAMESPACE },
619
+ ...KUBERNETES_SERVICE_HOST && { "cloud.orchestrator": "kubernetes" },
620
+ ...GCP_PROJECT && { "cloud.account.id": GCP_PROJECT },
621
+ ...CLOUD_PROVIDER && { "cloud.provider": CLOUD_PROVIDER },
622
+ ...componentName && { "component.name": componentName }
623
+ };
624
+ return {
625
+ systemName,
626
+ systemVersion,
627
+ componentName,
628
+ resourceAttributes
629
+ };
630
+ }
631
+
632
+ // src/resource.ts
682
633
  var getResource = async () => {
683
634
  const baseRes = await (0, import_resources.detectResources)();
684
635
  const { resourceAttributes } = detectTelemetryContext();
@@ -691,21 +642,29 @@ var getResource = async () => {
691
642
  };
692
643
 
693
644
  // src/otel.ts
694
- import_api4.diag.setLogger(new import_api4.DiagConsoleLogger(), import_api4.DiagLogLevel.ERROR);
695
645
  var initialization;
696
646
  async function initialize() {
697
647
  if (!initialization) {
698
- initialization = _initialize();
648
+ import_api3.diag.setLogger(new import_api3.DiagConsoleLogger(), import_api3.DiagLogLevel.ERROR);
649
+ initialization = initializeOtel();
699
650
  }
700
651
  return initialization;
701
652
  }
702
- async function _initialize() {
653
+ function isInitialized() {
654
+ return initialization !== void 0;
655
+ }
656
+ async function initializeOtel() {
703
657
  try {
704
658
  const serviceName = process.env.OTEL_SERVICE_NAME ?? "unknown-service";
705
659
  const otlpEndpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT;
660
+ const isTestMode = process.env.NODE_ENV === "test" || process.env.VITEST === "true";
706
661
  const resource = await getResource();
707
- const logProvider = getLogProvider(resource, otlpEndpoint);
708
- import_api_logs2.logs.setGlobalLoggerProvider(logProvider);
662
+ let logProvider;
663
+ const shouldSetupLogProvider = !isTestMode || !!process.env.LOG_LEVEL;
664
+ if (shouldSetupLogProvider) {
665
+ logProvider = getLogProvider(resource, otlpEndpoint);
666
+ import_api_logs.logs.setGlobalLoggerProvider(logProvider);
667
+ }
709
668
  const spanProcessor = getSpanProcessor(otlpEndpoint);
710
669
  const metricReader = getMetricReader(otlpEndpoint);
711
670
  const sdk = new import_sdk_node.NodeSDK({
@@ -718,16 +677,78 @@ async function _initialize() {
718
677
  console.log(`[otel] Telemetry initialized for "${serviceName}"`);
719
678
  process.on("SIGTERM", async () => {
720
679
  console.log("[otel] Shutting down...");
721
- await Promise.all([sdk.shutdown(), logProvider.shutdown()]);
680
+ const shutdownPromises = [sdk.shutdown()];
681
+ if (logProvider) {
682
+ shutdownPromises.push(logProvider.shutdown());
683
+ }
684
+ await Promise.all(shutdownPromises);
722
685
  console.log("[otel] Shutdown complete.");
723
686
  process.exit(0);
724
687
  });
725
688
  } catch (err) {
726
- console.error("[otel] Startup error:", err);
689
+ if (err instanceof Error && err.message.includes("duplicate registration")) {
690
+ console.warn("[otel] Warning - API already registered, continuing...");
691
+ } else {
692
+ console.error("[otel] Startup error:", err);
693
+ }
727
694
  }
728
695
  }
729
696
 
697
+ // src/logger.ts
698
+ function getLogger(serviceOverride, extraAttrs = {}, testProvider) {
699
+ if (!isInitialized()) {
700
+ throw new Error(
701
+ "OpenTelemetry is not initialized. Please call initialize() before getting a logger."
702
+ );
703
+ }
704
+ const { systemName, systemVersion, resourceAttributes } = detectTelemetryContext(serviceOverride);
705
+ const defaultAttrs = {
706
+ ...resourceAttributes,
707
+ ...extraAttrs
708
+ };
709
+ function emit(severityText, body, attrs = {}) {
710
+ const logger = testProvider ? testProvider.getLogger(systemName, systemVersion) : import_api_logs2.logs.getLogger(systemName, systemVersion);
711
+ const span = import_api4.trace.getSpan(import_api4.context.active());
712
+ const spanContext = span?.spanContext();
713
+ logger.emit({
714
+ severityText,
715
+ severityNumber: LOG_SEVERITY_MAP[severityText],
716
+ body,
717
+ attributes: {
718
+ ...defaultAttrs,
719
+ ...spanContext && {
720
+ trace_id: spanContext.traceId,
721
+ span_id: spanContext.spanId
722
+ },
723
+ ...attrs
724
+ }
725
+ });
726
+ }
727
+ return {
728
+ debug: (msg, attrs) => emit("DEBUG", msg, attrs),
729
+ info: (msg, attrs) => emit("INFO", msg, attrs),
730
+ notice: (msg, attrs) => emit("NOTICE", msg, attrs),
731
+ warn: (msg, attrs) => emit("WARNING", msg, attrs),
732
+ error: (msg, errOrAttrs, maybeAttrs = {}) => {
733
+ let body;
734
+ let attrs;
735
+ if (errOrAttrs instanceof Error) {
736
+ body = `${msg}: ${errOrAttrs.stack || errOrAttrs.message}`;
737
+ attrs = maybeAttrs;
738
+ } else {
739
+ body = msg instanceof Error ? msg.stack || msg.message : msg;
740
+ attrs = errOrAttrs || {};
741
+ }
742
+ emit("ERROR", body, attrs);
743
+ },
744
+ critical: (msg, attrs) => emit("CRITICAL", msg, attrs),
745
+ alert: (msg, attrs) => emit("ALERT", msg, attrs),
746
+ emergency: (msg, attrs) => emit("EMERGENCY", msg, attrs)
747
+ };
748
+ }
749
+
730
750
  // src/metrics.ts
751
+ var import_api5 = require("@opentelemetry/api");
731
752
  async function getMeter(componentNameOverride) {
732
753
  await initialize();
733
754
  const { componentName, systemName, systemVersion } = detectTelemetryContext(
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  // src/logger.ts
2
2
  import { context, trace } from "@opentelemetry/api";
3
- import { logs } from "@opentelemetry/api-logs";
3
+ import { logs as logs2 } from "@opentelemetry/api-logs";
4
4
 
5
5
  // src/consts.ts
6
6
  var LOG_SEVERITY_MAP = {
@@ -17,106 +17,9 @@ var LOG_SEVERITY_MAP = {
17
17
  EMERGENCY: 23
18
18
  };
19
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
20
  // src/otel.ts
118
21
  import { DiagConsoleLogger, DiagLogLevel, diag } from "@opentelemetry/api";
119
- import { logs as logs2 } from "@opentelemetry/api-logs";
22
+ import { logs } from "@opentelemetry/api-logs";
120
23
  import { getNodeAutoInstrumentations } from "@opentelemetry/auto-instrumentations-node";
121
24
  import { NodeSDK } from "@opentelemetry/sdk-node";
122
25
 
@@ -139,8 +42,8 @@ import { ExportResultCode } from "@opentelemetry/core";
139
42
 
140
43
  // src/loggers/formatters/shared.ts
141
44
  import {
142
- ATTR_SERVICE_NAME as ATTR_SERVICE_NAME2,
143
- ATTR_SERVICE_VERSION as ATTR_SERVICE_VERSION2
45
+ ATTR_SERVICE_NAME,
46
+ ATTR_SERVICE_VERSION
144
47
  } from "@opentelemetry/semantic-conventions";
145
48
  import stringify from "fast-safe-stringify";
146
49
 
@@ -202,8 +105,8 @@ function formatTimestamp(time) {
202
105
  return colors.dim(date.toISOString().slice(11, 23));
203
106
  }
204
107
  function formatService(resource) {
205
- const name = resource.attributes[ATTR_SERVICE_NAME2] ?? "unknown-service";
206
- const version = resource.attributes[ATTR_SERVICE_VERSION2] ?? "1.0.0";
108
+ const name = resource.attributes[ATTR_SERVICE_NAME] ?? "unknown-service";
109
+ const version = resource.attributes[ATTR_SERVICE_VERSION] ?? "1.0.0";
207
110
  return colors.gray(`[${name}@${version}]`);
208
111
  }
209
112
  function formatLevel(record) {
@@ -655,6 +558,54 @@ import {
655
558
  detectResources,
656
559
  resourceFromAttributes
657
560
  } from "@opentelemetry/resources";
561
+
562
+ // src/otel-context.ts
563
+ import {
564
+ ATTR_SERVICE_NAME as ATTR_SERVICE_NAME2,
565
+ ATTR_SERVICE_VERSION as ATTR_SERVICE_VERSION2
566
+ } from "@opentelemetry/semantic-conventions";
567
+ function detectTelemetryContext(componentNameOverride) {
568
+ const {
569
+ OTEL_SERVICE_NAME,
570
+ // e.g. "UserSystem"
571
+ OTEL_SERVICE_VERSION,
572
+ // e.g. "1.2.3"
573
+ K_SERVICE,
574
+ K_REVISION,
575
+ K_CONFIGURATION,
576
+ KUBERNETES_SERVICE_HOST,
577
+ POD_NAME,
578
+ POD_NAMESPACE,
579
+ GCP_PROJECT,
580
+ CLOUD_PROVIDER
581
+ } = process.env;
582
+ const systemName = OTEL_SERVICE_NAME || "unknown-service";
583
+ const systemVersion = OTEL_SERVICE_VERSION || "1.0.0";
584
+ const componentName = componentNameOverride || void 0;
585
+ const resourceAttributes = {
586
+ [ATTR_SERVICE_NAME2]: systemName,
587
+ [ATTR_SERVICE_VERSION2]: systemVersion,
588
+ "serviceContext.service": systemName,
589
+ "serviceContext.version": systemVersion,
590
+ ...K_SERVICE && { "cloud.run.service": K_SERVICE },
591
+ ...K_REVISION && { "cloud.run.revision": K_REVISION },
592
+ ...K_CONFIGURATION && { "cloud.run.configuration": K_CONFIGURATION },
593
+ ...POD_NAME && { "k8s.pod_name": POD_NAME },
594
+ ...POD_NAMESPACE && { "k8s.namespace_name": POD_NAMESPACE },
595
+ ...KUBERNETES_SERVICE_HOST && { "cloud.orchestrator": "kubernetes" },
596
+ ...GCP_PROJECT && { "cloud.account.id": GCP_PROJECT },
597
+ ...CLOUD_PROVIDER && { "cloud.provider": CLOUD_PROVIDER },
598
+ ...componentName && { "component.name": componentName }
599
+ };
600
+ return {
601
+ systemName,
602
+ systemVersion,
603
+ componentName,
604
+ resourceAttributes
605
+ };
606
+ }
607
+
608
+ // src/resource.ts
658
609
  var getResource = async () => {
659
610
  const baseRes = await detectResources();
660
611
  const { resourceAttributes } = detectTelemetryContext();
@@ -667,21 +618,29 @@ var getResource = async () => {
667
618
  };
668
619
 
669
620
  // src/otel.ts
670
- diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.ERROR);
671
621
  var initialization;
672
622
  async function initialize() {
673
623
  if (!initialization) {
674
- initialization = _initialize();
624
+ diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.ERROR);
625
+ initialization = initializeOtel();
675
626
  }
676
627
  return initialization;
677
628
  }
678
- async function _initialize() {
629
+ function isInitialized() {
630
+ return initialization !== void 0;
631
+ }
632
+ async function initializeOtel() {
679
633
  try {
680
634
  const serviceName = process.env.OTEL_SERVICE_NAME ?? "unknown-service";
681
635
  const otlpEndpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT;
636
+ const isTestMode = process.env.NODE_ENV === "test" || process.env.VITEST === "true";
682
637
  const resource = await getResource();
683
- const logProvider = getLogProvider(resource, otlpEndpoint);
684
- logs2.setGlobalLoggerProvider(logProvider);
638
+ let logProvider;
639
+ const shouldSetupLogProvider = !isTestMode || !!process.env.LOG_LEVEL;
640
+ if (shouldSetupLogProvider) {
641
+ logProvider = getLogProvider(resource, otlpEndpoint);
642
+ logs.setGlobalLoggerProvider(logProvider);
643
+ }
685
644
  const spanProcessor = getSpanProcessor(otlpEndpoint);
686
645
  const metricReader = getMetricReader(otlpEndpoint);
687
646
  const sdk = new NodeSDK({
@@ -694,16 +653,78 @@ async function _initialize() {
694
653
  console.log(`[otel] Telemetry initialized for "${serviceName}"`);
695
654
  process.on("SIGTERM", async () => {
696
655
  console.log("[otel] Shutting down...");
697
- await Promise.all([sdk.shutdown(), logProvider.shutdown()]);
656
+ const shutdownPromises = [sdk.shutdown()];
657
+ if (logProvider) {
658
+ shutdownPromises.push(logProvider.shutdown());
659
+ }
660
+ await Promise.all(shutdownPromises);
698
661
  console.log("[otel] Shutdown complete.");
699
662
  process.exit(0);
700
663
  });
701
664
  } catch (err) {
702
- console.error("[otel] Startup error:", err);
665
+ if (err instanceof Error && err.message.includes("duplicate registration")) {
666
+ console.warn("[otel] Warning - API already registered, continuing...");
667
+ } else {
668
+ console.error("[otel] Startup error:", err);
669
+ }
670
+ }
671
+ }
672
+
673
+ // src/logger.ts
674
+ function getLogger(serviceOverride, extraAttrs = {}, testProvider) {
675
+ if (!isInitialized()) {
676
+ throw new Error(
677
+ "OpenTelemetry is not initialized. Please call initialize() before getting a logger."
678
+ );
679
+ }
680
+ const { systemName, systemVersion, resourceAttributes } = detectTelemetryContext(serviceOverride);
681
+ const defaultAttrs = {
682
+ ...resourceAttributes,
683
+ ...extraAttrs
684
+ };
685
+ function emit(severityText, body, attrs = {}) {
686
+ const logger = testProvider ? testProvider.getLogger(systemName, systemVersion) : logs2.getLogger(systemName, systemVersion);
687
+ const span = trace.getSpan(context.active());
688
+ const spanContext = span?.spanContext();
689
+ logger.emit({
690
+ severityText,
691
+ severityNumber: LOG_SEVERITY_MAP[severityText],
692
+ body,
693
+ attributes: {
694
+ ...defaultAttrs,
695
+ ...spanContext && {
696
+ trace_id: spanContext.traceId,
697
+ span_id: spanContext.spanId
698
+ },
699
+ ...attrs
700
+ }
701
+ });
703
702
  }
703
+ return {
704
+ debug: (msg, attrs) => emit("DEBUG", msg, attrs),
705
+ info: (msg, attrs) => emit("INFO", msg, attrs),
706
+ notice: (msg, attrs) => emit("NOTICE", msg, attrs),
707
+ warn: (msg, attrs) => emit("WARNING", msg, attrs),
708
+ error: (msg, errOrAttrs, maybeAttrs = {}) => {
709
+ let body;
710
+ let attrs;
711
+ if (errOrAttrs instanceof Error) {
712
+ body = `${msg}: ${errOrAttrs.stack || errOrAttrs.message}`;
713
+ attrs = maybeAttrs;
714
+ } else {
715
+ body = msg instanceof Error ? msg.stack || msg.message : msg;
716
+ attrs = errOrAttrs || {};
717
+ }
718
+ emit("ERROR", body, attrs);
719
+ },
720
+ critical: (msg, attrs) => emit("CRITICAL", msg, attrs),
721
+ alert: (msg, attrs) => emit("ALERT", msg, attrs),
722
+ emergency: (msg, attrs) => emit("EMERGENCY", msg, attrs)
723
+ };
704
724
  }
705
725
 
706
726
  // src/metrics.ts
727
+ import { metrics } from "@opentelemetry/api";
707
728
  async function getMeter(componentNameOverride) {
708
729
  await initialize();
709
730
  const { componentName, systemName, systemVersion } = detectTelemetryContext(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sebspark/otel",
3
- "version": "0.4.4",
3
+ "version": "0.5.0",
4
4
  "license": "Apache-2.0",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",