@sebspark/otel 0.5.1 → 1.0.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/README.md CHANGED
@@ -21,7 +21,20 @@ pnpm add @sebspark/otel
21
21
  **This must be the first import in your application:**
22
22
 
23
23
  ```ts
24
- import '@sebspark/otel'
24
+ import { initialize, instrumentation } from '@sebspark/otel'
25
+
26
+ async function start () {
27
+ await initialize(
28
+ instrumentation.undici,
29
+ instrumentation.http,
30
+ instrumentation.express,
31
+ instrumentation.redis,
32
+ )
33
+
34
+ // start your application
35
+ }
36
+
37
+ start()
25
38
  ```
26
39
 
27
40
  Automatically:
@@ -38,6 +51,7 @@ Automatically:
38
51
  ### Logging
39
52
 
40
53
  ```ts
54
+ // Will throw if OTEL is not yet initialized
41
55
  import { getLogger } from '@sebspark/otel'
42
56
 
43
57
  const logger = getLogger()
@@ -61,7 +75,8 @@ Logs inside active spans automatically include:
61
75
  ```ts
62
76
  import { getTracer } from '@sebspark/otel'
63
77
 
64
- const tracer = getTracer() // async to ensure otel initialization
78
+ // Will throw if OTEL is not yet initialized
79
+ const tracer = getTracer()
65
80
 
66
81
  await tracer.withTrace('trace.name', async (span) => {
67
82
  span.setAttribute('user.id', '123')
@@ -111,7 +126,8 @@ span.end()
111
126
  ```ts
112
127
  import { getMeter } from '@sebspark/otel'
113
128
 
114
- const meter = getMeter() // async to ensure otel initialization
129
+ // Will throw if OTEL is not yet initialized
130
+ const meter = getMeter()
115
131
 
116
132
  const counter = meter.createCounter('http_requests_total', {
117
133
  description: 'Total number of HTTP requests',
package/dist/index.d.mts CHANGED
@@ -1,9 +1,30 @@
1
- import { LoggerProvider } from '@opentelemetry/api-logs';
1
+ import { Instrumentation } from '@opentelemetry/instrumentation';
2
+ import { DnsInstrumentation } from '@opentelemetry/instrumentation-dns';
3
+ import { ExpressInstrumentation } from '@opentelemetry/instrumentation-express';
4
+ import { FsInstrumentation } from '@opentelemetry/instrumentation-fs';
5
+ import { GrpcInstrumentation } from '@opentelemetry/instrumentation-grpc';
6
+ import { NetInstrumentation } from '@opentelemetry/instrumentation-net';
7
+ import { RedisInstrumentation } from '@opentelemetry/instrumentation-redis';
8
+ import { SocketIoInstrumentation } from '@opentelemetry/instrumentation-socket.io';
9
+ import { UndiciInstrumentation } from '@opentelemetry/instrumentation-undici';
2
10
  import * as _opentelemetry_api from '@opentelemetry/api';
3
11
  import { trace, SpanOptions } from '@opentelemetry/api';
4
12
 
13
+ declare const instrumentations: {
14
+ readonly http: Instrumentation;
15
+ readonly express: ExpressInstrumentation;
16
+ readonly grpc: GrpcInstrumentation;
17
+ readonly redis: RedisInstrumentation;
18
+ readonly dns: DnsInstrumentation;
19
+ readonly net: NetInstrumentation;
20
+ readonly fs: FsInstrumentation;
21
+ readonly undici: UndiciInstrumentation;
22
+ readonly socketIo: SocketIoInstrumentation;
23
+ };
24
+
5
25
  type Attrs = Record<string, any>;
6
- declare function getLogger(serviceOverride?: string, extraAttrs?: Attrs, testProvider?: LoggerProvider): {
26
+ type Logger = ReturnType<typeof getLogger>;
27
+ declare function getLogger(serviceOverride?: string, extraAttrs?: Attrs): {
7
28
  debug: (msg: string, attrs?: Attrs) => void;
8
29
  info: (msg: string, attrs?: Attrs) => void;
9
30
  notice: (msg: string, attrs?: Attrs) => void;
@@ -14,7 +35,10 @@ declare function getLogger(serviceOverride?: string, extraAttrs?: Attrs, testPro
14
35
  emergency: (msg: string, attrs?: Attrs) => void;
15
36
  };
16
37
 
17
- declare function getMeter(componentNameOverride?: string): Promise<_opentelemetry_api.Meter>;
38
+ declare function getMeter(componentNameOverride?: string): _opentelemetry_api.Meter;
39
+
40
+ declare function initialize(...instrumentations: Instrumentation[]): Promise<void>;
41
+ declare function isInitialized(): boolean;
18
42
 
19
43
  type OtelTracer = ReturnType<typeof trace.getTracer>;
20
44
  type Span = ReturnType<OtelTracer['startSpan']>;
@@ -46,6 +70,6 @@ interface Tracer extends OtelTracer {
46
70
  * @param serviceOverride - Optional override for service name
47
71
  * @returns Tracer with helpers
48
72
  */
49
- declare function getTracer(componentNameOverride?: string): Promise<Tracer>;
73
+ declare function getTracer(componentNameOverride?: string): Tracer;
50
74
 
51
- export { getLogger, getMeter, getTracer };
75
+ export { type Logger, getLogger, getMeter, getTracer, initialize, instrumentations, isInitialized };
package/dist/index.d.ts CHANGED
@@ -1,9 +1,30 @@
1
- import { LoggerProvider } from '@opentelemetry/api-logs';
1
+ import { Instrumentation } from '@opentelemetry/instrumentation';
2
+ import { DnsInstrumentation } from '@opentelemetry/instrumentation-dns';
3
+ import { ExpressInstrumentation } from '@opentelemetry/instrumentation-express';
4
+ import { FsInstrumentation } from '@opentelemetry/instrumentation-fs';
5
+ import { GrpcInstrumentation } from '@opentelemetry/instrumentation-grpc';
6
+ import { NetInstrumentation } from '@opentelemetry/instrumentation-net';
7
+ import { RedisInstrumentation } from '@opentelemetry/instrumentation-redis';
8
+ import { SocketIoInstrumentation } from '@opentelemetry/instrumentation-socket.io';
9
+ import { UndiciInstrumentation } from '@opentelemetry/instrumentation-undici';
2
10
  import * as _opentelemetry_api from '@opentelemetry/api';
3
11
  import { trace, SpanOptions } from '@opentelemetry/api';
4
12
 
13
+ declare const instrumentations: {
14
+ readonly http: Instrumentation;
15
+ readonly express: ExpressInstrumentation;
16
+ readonly grpc: GrpcInstrumentation;
17
+ readonly redis: RedisInstrumentation;
18
+ readonly dns: DnsInstrumentation;
19
+ readonly net: NetInstrumentation;
20
+ readonly fs: FsInstrumentation;
21
+ readonly undici: UndiciInstrumentation;
22
+ readonly socketIo: SocketIoInstrumentation;
23
+ };
24
+
5
25
  type Attrs = Record<string, any>;
6
- declare function getLogger(serviceOverride?: string, extraAttrs?: Attrs, testProvider?: LoggerProvider): {
26
+ type Logger = ReturnType<typeof getLogger>;
27
+ declare function getLogger(serviceOverride?: string, extraAttrs?: Attrs): {
7
28
  debug: (msg: string, attrs?: Attrs) => void;
8
29
  info: (msg: string, attrs?: Attrs) => void;
9
30
  notice: (msg: string, attrs?: Attrs) => void;
@@ -14,7 +35,10 @@ declare function getLogger(serviceOverride?: string, extraAttrs?: Attrs, testPro
14
35
  emergency: (msg: string, attrs?: Attrs) => void;
15
36
  };
16
37
 
17
- declare function getMeter(componentNameOverride?: string): Promise<_opentelemetry_api.Meter>;
38
+ declare function getMeter(componentNameOverride?: string): _opentelemetry_api.Meter;
39
+
40
+ declare function initialize(...instrumentations: Instrumentation[]): Promise<void>;
41
+ declare function isInitialized(): boolean;
18
42
 
19
43
  type OtelTracer = ReturnType<typeof trace.getTracer>;
20
44
  type Span = ReturnType<OtelTracer['startSpan']>;
@@ -46,6 +70,6 @@ interface Tracer extends OtelTracer {
46
70
  * @param serviceOverride - Optional override for service name
47
71
  * @returns Tracer with helpers
48
72
  */
49
- declare function getTracer(componentNameOverride?: string): Promise<Tracer>;
73
+ declare function getTracer(componentNameOverride?: string): Tracer;
50
74
 
51
- export { getLogger, getMeter, getTracer };
75
+ export { type Logger, getLogger, getMeter, getTracer, initialize, instrumentations, isInitialized };
package/dist/index.js CHANGED
@@ -32,26 +32,92 @@ var index_exports = {};
32
32
  __export(index_exports, {
33
33
  getLogger: () => getLogger,
34
34
  getMeter: () => getMeter,
35
- getTracer: () => getTracer
35
+ getTracer: () => getTracer,
36
+ initialize: () => initialize,
37
+ instrumentations: () => instrumentations,
38
+ isInitialized: () => isInitialized
36
39
  });
37
40
  module.exports = __toCommonJS(index_exports);
38
41
 
39
- // src/otel.ts
40
- var import_api3 = require("@opentelemetry/api");
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");
42
+ // src/instrumentations.ts
43
+ var import_instrumentation_dns = require("@opentelemetry/instrumentation-dns");
44
+ var import_instrumentation_express = require("@opentelemetry/instrumentation-express");
45
+ var import_instrumentation_fs = require("@opentelemetry/instrumentation-fs");
46
+ var import_instrumentation_grpc = require("@opentelemetry/instrumentation-grpc");
47
+ var import_instrumentation_http = require("@opentelemetry/instrumentation-http");
48
+ var import_instrumentation_net = require("@opentelemetry/instrumentation-net");
49
+ var import_instrumentation_redis = require("@opentelemetry/instrumentation-redis");
50
+ var import_instrumentation_socket = require("@opentelemetry/instrumentation-socket.io");
51
+ var import_instrumentation_undici = require("@opentelemetry/instrumentation-undici");
52
+ var _http;
53
+ var _express;
54
+ var _grpc;
55
+ var _redis;
56
+ var _dns;
57
+ var _net;
58
+ var _fs;
59
+ var _undici;
60
+ var _socketIo;
61
+ var instrumentations = {
62
+ get http() {
63
+ if (!_http) {
64
+ _http = new import_instrumentation_http.HttpInstrumentation();
65
+ }
66
+ return _http;
67
+ },
68
+ get express() {
69
+ if (!_express) {
70
+ _express = new import_instrumentation_express.ExpressInstrumentation();
71
+ }
72
+ return _express;
73
+ },
74
+ get grpc() {
75
+ if (!_grpc) {
76
+ _grpc = new import_instrumentation_grpc.GrpcInstrumentation();
77
+ }
78
+ return _grpc;
79
+ },
80
+ get redis() {
81
+ if (!_redis) {
82
+ _redis = new import_instrumentation_redis.RedisInstrumentation();
83
+ }
84
+ return _redis;
85
+ },
86
+ get dns() {
87
+ if (!_dns) {
88
+ _dns = new import_instrumentation_dns.DnsInstrumentation();
89
+ }
90
+ return _dns;
91
+ },
92
+ get net() {
93
+ if (!_net) {
94
+ _net = new import_instrumentation_net.NetInstrumentation();
95
+ }
96
+ return _net;
97
+ },
98
+ get fs() {
99
+ if (!_fs) {
100
+ _fs = new import_instrumentation_fs.FsInstrumentation();
101
+ }
102
+ return _fs;
103
+ },
104
+ get undici() {
105
+ if (!_undici) {
106
+ _undici = new import_instrumentation_undici.UndiciInstrumentation();
107
+ }
108
+ return _undici;
109
+ },
110
+ get socketIo() {
111
+ if (!_socketIo) {
112
+ _socketIo = new import_instrumentation_socket.SocketIoInstrumentation();
113
+ }
114
+ return _socketIo;
115
+ }
116
+ };
52
117
 
53
- // src/loggers/console-log-pretty-exporter.ts
54
- var import_core = require("@opentelemetry/core");
118
+ // src/logger.ts
119
+ var import_api4 = require("@opentelemetry/api");
120
+ var import_api_logs3 = require("@opentelemetry/api-logs");
55
121
 
56
122
  // src/consts.ts
57
123
  var LOG_SEVERITY_MAP = {
@@ -68,6 +134,23 @@ var LOG_SEVERITY_MAP = {
68
134
  EMERGENCY: 23
69
135
  };
70
136
 
137
+ // src/otel.ts
138
+ var import_api3 = require("@opentelemetry/api");
139
+ var import_api_logs2 = require("@opentelemetry/api-logs");
140
+ var import_sdk_node = require("@opentelemetry/sdk-node");
141
+
142
+ // src/providers.ts
143
+ var import_exporter_logs_otlp_http = require("@opentelemetry/exporter-logs-otlp-http");
144
+ var import_exporter_metrics_otlp_http = require("@opentelemetry/exporter-metrics-otlp-http");
145
+ var import_exporter_trace_otlp_http = require("@opentelemetry/exporter-trace-otlp-http");
146
+ var import_sdk_logs = require("@opentelemetry/sdk-logs");
147
+ var import_sdk_metrics = require("@opentelemetry/sdk-metrics");
148
+ var import_sdk_trace_node = require("@opentelemetry/sdk-trace-node");
149
+
150
+ // src/loggers/console-log-pretty-exporter.ts
151
+ var import_api_logs = require("@opentelemetry/api-logs");
152
+ var import_core = require("@opentelemetry/core");
153
+
71
154
  // src/loggers/formatters/shared.ts
72
155
  var import_semantic_conventions = require("@opentelemetry/semantic-conventions");
73
156
  var import_fast_safe_stringify = __toESM(require("fast-safe-stringify"));
@@ -398,7 +481,19 @@ var ConsoleLogPrettyExporter = class {
398
481
  _sendLogRecords(logRecords, done) {
399
482
  for (const record of logRecords) {
400
483
  if ((record.severityNumber ?? 0) >= this.logThreshold) {
401
- console.log(formatLogRecord(record));
484
+ const formatted = formatLogRecord(record);
485
+ const severity = record.severityNumber || import_api_logs.SeverityNumber.UNSPECIFIED;
486
+ if (severity >= import_api_logs.SeverityNumber.ERROR) {
487
+ console.error(formatted);
488
+ } else if (severity >= import_api_logs.SeverityNumber.WARN) {
489
+ console.warn(formatted);
490
+ } else if (severity >= import_api_logs.SeverityNumber.INFO) {
491
+ console.info(formatted);
492
+ } else if (severity >= import_api_logs.SeverityNumber.DEBUG) {
493
+ console.debug(formatted);
494
+ } else {
495
+ console.trace(formatted);
496
+ }
402
497
  }
403
498
  }
404
499
  done?.({ code: import_core.ExportResultCode.SUCCESS });
@@ -473,8 +568,8 @@ var ConsoleMetricPrettyExporter = class {
473
568
  scopeMetrics: filteredScopes
474
569
  };
475
570
  }
476
- export(metrics2, resultCallback) {
477
- const filtered = this.filterMetrics(metrics2);
571
+ export(metrics3, resultCallback) {
572
+ const filtered = this.filterMetrics(metrics3);
478
573
  if (filtered) {
479
574
  console.log(formatMetrics(filtered));
480
575
  }
@@ -579,6 +674,8 @@ var getMetricReader = (otlpEndpoint) => {
579
674
  };
580
675
 
581
676
  // src/resource.ts
677
+ var import_resource_detector_container = require("@opentelemetry/resource-detector-container");
678
+ var import_resource_detector_gcp = require("@opentelemetry/resource-detector-gcp");
582
679
  var import_resources = require("@opentelemetry/resources");
583
680
 
584
681
  // src/otel-context.ts
@@ -626,7 +723,19 @@ function detectTelemetryContext(componentNameOverride) {
626
723
 
627
724
  // src/resource.ts
628
725
  var getResource = async () => {
629
- const baseRes = await (0, import_resources.detectResources)();
726
+ const baseRes = await (0, import_resources.detectResources)({
727
+ detectors: [
728
+ import_resource_detector_container.containerDetector,
729
+ import_resources.envDetector,
730
+ import_resource_detector_gcp.gcpDetector,
731
+ import_resources.osDetector,
732
+ import_resources.processDetector,
733
+ import_resources.serviceInstanceIdDetector
734
+ ]
735
+ });
736
+ if (baseRes.waitForAsyncAttributes) {
737
+ await baseRes.waitForAsyncAttributes();
738
+ }
630
739
  const { resourceAttributes } = detectTelemetryContext();
631
740
  const customRes = (0, import_resources.resourceFromAttributes)(resourceAttributes);
632
741
  const resource = baseRes.merge(customRes);
@@ -637,66 +746,53 @@ var getResource = async () => {
637
746
  };
638
747
 
639
748
  // src/otel.ts
749
+ import_api3.diag.disable();
750
+ import_api3.diag.setLogger(new import_api3.DiagConsoleLogger(), import_api3.DiagLogLevel.ERROR);
640
751
  var initialization;
641
- async function initialize() {
752
+ async function initialize(...instrumentations2) {
642
753
  if (!initialization) {
643
- import_api3.diag.setLogger(new import_api3.DiagConsoleLogger(), import_api3.DiagLogLevel.ERROR);
644
- initialization = initializeOtel();
754
+ initialization = _initialize(instrumentations2);
645
755
  }
646
756
  return initialization;
647
757
  }
648
758
  function isInitialized() {
649
- return initialization !== void 0;
759
+ return !!initialization;
650
760
  }
651
- async function initializeOtel() {
761
+ async function _initialize(instrumentations2) {
652
762
  try {
653
763
  const serviceName = process.env.OTEL_SERVICE_NAME ?? "unknown-service";
654
764
  const otlpEndpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT;
655
- const isTestMode = process.env.NODE_ENV === "test" || process.env.VITEST === "true";
656
765
  const resource = await getResource();
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
- }
766
+ import_api_logs2.logs.disable();
767
+ import_api3.trace.disable();
768
+ import_api3.metrics.disable();
769
+ const logProvider = getLogProvider(resource, otlpEndpoint);
770
+ import_api_logs2.logs.setGlobalLoggerProvider(logProvider);
663
771
  const spanProcessor = getSpanProcessor(otlpEndpoint);
664
772
  const metricReader = getMetricReader(otlpEndpoint);
665
773
  const sdk = new import_sdk_node.NodeSDK({
666
774
  spanProcessor,
667
775
  metricReader,
668
- instrumentations: [(0, import_auto_instrumentations_node.getNodeAutoInstrumentations)()],
776
+ instrumentations: instrumentations2,
669
777
  resource
670
778
  });
671
779
  await sdk.start();
672
780
  console.log(`[otel] Telemetry initialized for "${serviceName}"`);
673
781
  process.on("SIGTERM", async () => {
674
782
  console.log("[otel] Shutting down...");
675
- const shutdownPromises = [sdk.shutdown()];
676
- if (logProvider) {
677
- shutdownPromises.push(logProvider.shutdown());
678
- }
679
- await Promise.all(shutdownPromises);
783
+ await Promise.all([sdk.shutdown(), logProvider.shutdown()]);
680
784
  console.log("[otel] Shutdown complete.");
681
785
  process.exit(0);
682
786
  });
683
787
  } catch (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
- }
788
+ console.error("[otel] Startup error:", err);
689
789
  }
690
790
  }
691
791
 
692
792
  // 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) {
793
+ function getLogger(serviceOverride, extraAttrs = {}) {
696
794
  if (!isInitialized()) {
697
- throw new Error(
698
- "OpenTelemetry is not initialized. Please call initialize() before getting a logger."
699
- );
795
+ throw new Error("OTEL must be initialized before calling getLogger()");
700
796
  }
701
797
  const { systemName, systemVersion, resourceAttributes } = detectTelemetryContext(serviceOverride);
702
798
  const defaultAttrs = {
@@ -704,7 +800,7 @@ function getLogger(serviceOverride, extraAttrs = {}, testProvider) {
704
800
  ...extraAttrs
705
801
  };
706
802
  function emit(severityText, body, attrs = {}) {
707
- const logger = testProvider ? testProvider.getLogger(systemName, systemVersion) : import_api_logs2.logs.getLogger(systemName, systemVersion);
803
+ const logger = import_api_logs3.logs.getLogger(systemName, systemVersion);
708
804
  const span = import_api4.trace.getSpan(import_api4.context.active());
709
805
  const spanContext = span?.spanContext();
710
806
  logger.emit({
@@ -746,8 +842,10 @@ function getLogger(serviceOverride, extraAttrs = {}, testProvider) {
746
842
 
747
843
  // src/metrics.ts
748
844
  var import_api5 = require("@opentelemetry/api");
749
- async function getMeter(componentNameOverride) {
750
- await initialize();
845
+ function getMeter(componentNameOverride) {
846
+ if (!isInitialized()) {
847
+ throw new Error("OTEL must be initialized before calling getMeter()");
848
+ }
751
849
  const { componentName, systemName, systemVersion } = detectTelemetryContext(
752
850
  componentNameOverride
753
851
  );
@@ -756,8 +854,10 @@ async function getMeter(componentNameOverride) {
756
854
 
757
855
  // src/tracer.ts
758
856
  var import_api6 = require("@opentelemetry/api");
759
- async function getTracer(componentNameOverride) {
760
- await initialize();
857
+ function getTracer(componentNameOverride) {
858
+ if (!isInitialized()) {
859
+ throw new Error("OTEL must be initialized before calling getMeter()");
860
+ }
761
861
  const { componentName, systemName, systemVersion } = detectTelemetryContext(
762
862
  componentNameOverride
763
863
  );
@@ -839,12 +939,12 @@ function extractArgs(spanOptionsSpanOrFunc, spanOrFunc, func) {
839
939
  var isFunction = (value) => typeof value === "function";
840
940
  var isSpan = (value) => value !== null && value !== void 0 && isFunction(value.spanContext) && isFunction(value.end);
841
941
  var isSpanOptions = (value) => value !== null && value !== void 0 && (!!value.startTime || !!value.attributes || !!value.kind) && !isSpan(value);
842
-
843
- // src/index.ts
844
- initialize();
845
942
  // Annotate the CommonJS export names for ESM import in node:
846
943
  0 && (module.exports = {
847
944
  getLogger,
848
945
  getMeter,
849
- getTracer
946
+ getTracer,
947
+ initialize,
948
+ instrumentations,
949
+ isInitialized
850
950
  });
package/dist/index.mjs CHANGED
@@ -1,7 +1,107 @@
1
+ // src/instrumentations.ts
2
+ import { DnsInstrumentation } from "@opentelemetry/instrumentation-dns";
3
+ import { ExpressInstrumentation } from "@opentelemetry/instrumentation-express";
4
+ import { FsInstrumentation } from "@opentelemetry/instrumentation-fs";
5
+ import { GrpcInstrumentation } from "@opentelemetry/instrumentation-grpc";
6
+ import { HttpInstrumentation } from "@opentelemetry/instrumentation-http";
7
+ import { NetInstrumentation } from "@opentelemetry/instrumentation-net";
8
+ import { RedisInstrumentation } from "@opentelemetry/instrumentation-redis";
9
+ import { SocketIoInstrumentation } from "@opentelemetry/instrumentation-socket.io";
10
+ import { UndiciInstrumentation } from "@opentelemetry/instrumentation-undici";
11
+ var _http;
12
+ var _express;
13
+ var _grpc;
14
+ var _redis;
15
+ var _dns;
16
+ var _net;
17
+ var _fs;
18
+ var _undici;
19
+ var _socketIo;
20
+ var instrumentations = {
21
+ get http() {
22
+ if (!_http) {
23
+ _http = new HttpInstrumentation();
24
+ }
25
+ return _http;
26
+ },
27
+ get express() {
28
+ if (!_express) {
29
+ _express = new ExpressInstrumentation();
30
+ }
31
+ return _express;
32
+ },
33
+ get grpc() {
34
+ if (!_grpc) {
35
+ _grpc = new GrpcInstrumentation();
36
+ }
37
+ return _grpc;
38
+ },
39
+ get redis() {
40
+ if (!_redis) {
41
+ _redis = new RedisInstrumentation();
42
+ }
43
+ return _redis;
44
+ },
45
+ get dns() {
46
+ if (!_dns) {
47
+ _dns = new DnsInstrumentation();
48
+ }
49
+ return _dns;
50
+ },
51
+ get net() {
52
+ if (!_net) {
53
+ _net = new NetInstrumentation();
54
+ }
55
+ return _net;
56
+ },
57
+ get fs() {
58
+ if (!_fs) {
59
+ _fs = new FsInstrumentation();
60
+ }
61
+ return _fs;
62
+ },
63
+ get undici() {
64
+ if (!_undici) {
65
+ _undici = new UndiciInstrumentation();
66
+ }
67
+ return _undici;
68
+ },
69
+ get socketIo() {
70
+ if (!_socketIo) {
71
+ _socketIo = new SocketIoInstrumentation();
72
+ }
73
+ return _socketIo;
74
+ }
75
+ };
76
+
77
+ // src/logger.ts
78
+ import { context, trace as trace2 } from "@opentelemetry/api";
79
+ import { logs as logs2 } from "@opentelemetry/api-logs";
80
+
81
+ // src/consts.ts
82
+ var LOG_SEVERITY_MAP = {
83
+ TRACE: 1,
84
+ DEBUG: 5,
85
+ INFO: 9,
86
+ NOTICE: 10,
87
+ WARNING: 13,
88
+ WARN: 13,
89
+ ERROR: 17,
90
+ FATAL: 21,
91
+ CRITICAL: 21,
92
+ ALERT: 22,
93
+ EMERGENCY: 23
94
+ };
95
+
1
96
  // src/otel.ts
2
- import { DiagConsoleLogger, DiagLogLevel, diag } from "@opentelemetry/api";
97
+ import {
98
+ DiagConsoleLogger,
99
+ DiagLogLevel,
100
+ diag,
101
+ metrics,
102
+ trace
103
+ } from "@opentelemetry/api";
3
104
  import { logs } from "@opentelemetry/api-logs";
4
- import { getNodeAutoInstrumentations } from "@opentelemetry/auto-instrumentations-node";
5
105
  import { NodeSDK } from "@opentelemetry/sdk-node";
6
106
 
7
107
  // src/providers.ts
@@ -19,23 +119,9 @@ import {
19
119
  } from "@opentelemetry/sdk-trace-node";
20
120
 
21
121
  // src/loggers/console-log-pretty-exporter.ts
122
+ import { SeverityNumber } from "@opentelemetry/api-logs";
22
123
  import { ExportResultCode } from "@opentelemetry/core";
23
124
 
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
-
39
125
  // src/loggers/formatters/shared.ts
40
126
  import {
41
127
  ATTR_SERVICE_NAME,
@@ -369,7 +455,19 @@ var ConsoleLogPrettyExporter = class {
369
455
  _sendLogRecords(logRecords, done) {
370
456
  for (const record of logRecords) {
371
457
  if ((record.severityNumber ?? 0) >= this.logThreshold) {
372
- console.log(formatLogRecord(record));
458
+ const formatted = formatLogRecord(record);
459
+ const severity = record.severityNumber || SeverityNumber.UNSPECIFIED;
460
+ if (severity >= SeverityNumber.ERROR) {
461
+ console.error(formatted);
462
+ } else if (severity >= SeverityNumber.WARN) {
463
+ console.warn(formatted);
464
+ } else if (severity >= SeverityNumber.INFO) {
465
+ console.info(formatted);
466
+ } else if (severity >= SeverityNumber.DEBUG) {
467
+ console.debug(formatted);
468
+ } else {
469
+ console.trace(formatted);
470
+ }
373
471
  }
374
472
  }
375
473
  done?.({ code: ExportResultCode.SUCCESS });
@@ -444,8 +542,8 @@ var ConsoleMetricPrettyExporter = class {
444
542
  scopeMetrics: filteredScopes
445
543
  };
446
544
  }
447
- export(metrics2, resultCallback) {
448
- const filtered = this.filterMetrics(metrics2);
545
+ export(metrics3, resultCallback) {
546
+ const filtered = this.filterMetrics(metrics3);
449
547
  if (filtered) {
450
548
  console.log(formatMetrics(filtered));
451
549
  }
@@ -550,9 +648,15 @@ var getMetricReader = (otlpEndpoint) => {
550
648
  };
551
649
 
552
650
  // src/resource.ts
651
+ import { containerDetector } from "@opentelemetry/resource-detector-container";
652
+ import { gcpDetector } from "@opentelemetry/resource-detector-gcp";
553
653
  import {
554
654
  detectResources,
555
- resourceFromAttributes
655
+ envDetector,
656
+ osDetector,
657
+ processDetector,
658
+ resourceFromAttributes,
659
+ serviceInstanceIdDetector
556
660
  } from "@opentelemetry/resources";
557
661
 
558
662
  // src/otel-context.ts
@@ -603,7 +707,19 @@ function detectTelemetryContext(componentNameOverride) {
603
707
 
604
708
  // src/resource.ts
605
709
  var getResource = async () => {
606
- const baseRes = await detectResources();
710
+ const baseRes = await detectResources({
711
+ detectors: [
712
+ containerDetector,
713
+ envDetector,
714
+ gcpDetector,
715
+ osDetector,
716
+ processDetector,
717
+ serviceInstanceIdDetector
718
+ ]
719
+ });
720
+ if (baseRes.waitForAsyncAttributes) {
721
+ await baseRes.waitForAsyncAttributes();
722
+ }
607
723
  const { resourceAttributes } = detectTelemetryContext();
608
724
  const customRes = resourceFromAttributes(resourceAttributes);
609
725
  const resource = baseRes.merge(customRes);
@@ -614,66 +730,53 @@ var getResource = async () => {
614
730
  };
615
731
 
616
732
  // src/otel.ts
733
+ diag.disable();
734
+ diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.ERROR);
617
735
  var initialization;
618
- async function initialize() {
736
+ async function initialize(...instrumentations2) {
619
737
  if (!initialization) {
620
- diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.ERROR);
621
- initialization = initializeOtel();
738
+ initialization = _initialize(instrumentations2);
622
739
  }
623
740
  return initialization;
624
741
  }
625
742
  function isInitialized() {
626
- return initialization !== void 0;
743
+ return !!initialization;
627
744
  }
628
- async function initializeOtel() {
745
+ async function _initialize(instrumentations2) {
629
746
  try {
630
747
  const serviceName = process.env.OTEL_SERVICE_NAME ?? "unknown-service";
631
748
  const otlpEndpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT;
632
- const isTestMode = process.env.NODE_ENV === "test" || process.env.VITEST === "true";
633
749
  const resource = await getResource();
634
- let logProvider;
635
- const shouldSetupLogProvider = !isTestMode || !!process.env.LOG_LEVEL;
636
- if (shouldSetupLogProvider) {
637
- logProvider = getLogProvider(resource, otlpEndpoint);
638
- logs.setGlobalLoggerProvider(logProvider);
639
- }
750
+ logs.disable();
751
+ trace.disable();
752
+ metrics.disable();
753
+ const logProvider = getLogProvider(resource, otlpEndpoint);
754
+ logs.setGlobalLoggerProvider(logProvider);
640
755
  const spanProcessor = getSpanProcessor(otlpEndpoint);
641
756
  const metricReader = getMetricReader(otlpEndpoint);
642
757
  const sdk = new NodeSDK({
643
758
  spanProcessor,
644
759
  metricReader,
645
- instrumentations: [getNodeAutoInstrumentations()],
760
+ instrumentations: instrumentations2,
646
761
  resource
647
762
  });
648
763
  await sdk.start();
649
764
  console.log(`[otel] Telemetry initialized for "${serviceName}"`);
650
765
  process.on("SIGTERM", async () => {
651
766
  console.log("[otel] Shutting down...");
652
- const shutdownPromises = [sdk.shutdown()];
653
- if (logProvider) {
654
- shutdownPromises.push(logProvider.shutdown());
655
- }
656
- await Promise.all(shutdownPromises);
767
+ await Promise.all([sdk.shutdown(), logProvider.shutdown()]);
657
768
  console.log("[otel] Shutdown complete.");
658
769
  process.exit(0);
659
770
  });
660
771
  } catch (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
- }
772
+ console.error("[otel] Startup error:", err);
666
773
  }
667
774
  }
668
775
 
669
776
  // 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) {
777
+ function getLogger(serviceOverride, extraAttrs = {}) {
673
778
  if (!isInitialized()) {
674
- throw new Error(
675
- "OpenTelemetry is not initialized. Please call initialize() before getting a logger."
676
- );
779
+ throw new Error("OTEL must be initialized before calling getLogger()");
677
780
  }
678
781
  const { systemName, systemVersion, resourceAttributes } = detectTelemetryContext(serviceOverride);
679
782
  const defaultAttrs = {
@@ -681,8 +784,8 @@ function getLogger(serviceOverride, extraAttrs = {}, testProvider) {
681
784
  ...extraAttrs
682
785
  };
683
786
  function emit(severityText, body, attrs = {}) {
684
- const logger = testProvider ? testProvider.getLogger(systemName, systemVersion) : logs2.getLogger(systemName, systemVersion);
685
- const span = trace.getSpan(context.active());
787
+ const logger = logs2.getLogger(systemName, systemVersion);
788
+ const span = trace2.getSpan(context.active());
686
789
  const spanContext = span?.spanContext();
687
790
  logger.emit({
688
791
  severityText,
@@ -722,27 +825,31 @@ function getLogger(serviceOverride, extraAttrs = {}, testProvider) {
722
825
  }
723
826
 
724
827
  // src/metrics.ts
725
- import { metrics } from "@opentelemetry/api";
726
- async function getMeter(componentNameOverride) {
727
- await initialize();
828
+ import { metrics as metrics2 } from "@opentelemetry/api";
829
+ function getMeter(componentNameOverride) {
830
+ if (!isInitialized()) {
831
+ throw new Error("OTEL must be initialized before calling getMeter()");
832
+ }
728
833
  const { componentName, systemName, systemVersion } = detectTelemetryContext(
729
834
  componentNameOverride
730
835
  );
731
- return metrics.getMeter(componentName ?? systemName, systemVersion);
836
+ return metrics2.getMeter(componentName ?? systemName, systemVersion);
732
837
  }
733
838
 
734
839
  // src/tracer.ts
735
840
  import {
736
841
  context as context2,
737
842
  SpanStatusCode as SpanStatusCode3,
738
- trace as trace2
843
+ trace as trace3
739
844
  } from "@opentelemetry/api";
740
- async function getTracer(componentNameOverride) {
741
- await initialize();
845
+ function getTracer(componentNameOverride) {
846
+ if (!isInitialized()) {
847
+ throw new Error("OTEL must be initialized before calling getMeter()");
848
+ }
742
849
  const { componentName, systemName, systemVersion } = detectTelemetryContext(
743
850
  componentNameOverride
744
851
  );
745
- const tracer = trace2.getTracer(
852
+ const tracer = trace3.getTracer(
746
853
  componentName ?? systemName,
747
854
  systemVersion
748
855
  );
@@ -752,9 +859,9 @@ async function getTracer(componentNameOverride) {
752
859
  spanOrFunc,
753
860
  func
754
861
  );
755
- const parentContext = parent ? trace2.setSpan(context2.active(), parent) : context2.active();
862
+ const parentContext = parent ? trace3.setSpan(context2.active(), parent) : context2.active();
756
863
  const span = tracer.startSpan(name, options, parentContext);
757
- return await context2.with(trace2.setSpan(parentContext, span), async () => {
864
+ return await context2.with(trace3.setSpan(parentContext, span), async () => {
758
865
  try {
759
866
  const result = await fn(span);
760
867
  span.setStatus({ code: SpanStatusCode3.OK });
@@ -775,9 +882,9 @@ async function getTracer(componentNameOverride) {
775
882
  spanOrFunc,
776
883
  func
777
884
  );
778
- const parentContext = parent ? trace2.setSpan(context2.active(), parent) : context2.active();
885
+ const parentContext = parent ? trace3.setSpan(context2.active(), parent) : context2.active();
779
886
  const span = tracer.startSpan(name, options, parentContext);
780
- return context2.with(trace2.setSpan(parentContext, span), () => {
887
+ return context2.with(trace3.setSpan(parentContext, span), () => {
781
888
  try {
782
889
  const result = fn(span);
783
890
  span.setStatus({ code: SpanStatusCode3.OK });
@@ -820,11 +927,11 @@ function extractArgs(spanOptionsSpanOrFunc, spanOrFunc, func) {
820
927
  var isFunction = (value) => typeof value === "function";
821
928
  var isSpan = (value) => value !== null && value !== void 0 && isFunction(value.spanContext) && isFunction(value.end);
822
929
  var isSpanOptions = (value) => value !== null && value !== void 0 && (!!value.startTime || !!value.attributes || !!value.kind) && !isSpan(value);
823
-
824
- // src/index.ts
825
- initialize();
826
930
  export {
827
931
  getLogger,
828
932
  getMeter,
829
- getTracer
933
+ getTracer,
934
+ initialize,
935
+ instrumentations,
936
+ isInitialized
830
937
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sebspark/otel",
3
- "version": "0.5.1",
3
+ "version": "1.0.0",
4
4
  "license": "Apache-2.0",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -17,16 +17,27 @@
17
17
  },
18
18
  "dependencies": {
19
19
  "@opentelemetry/api": "1.9.0",
20
- "@opentelemetry/api-logs": "0.206.0",
21
- "@opentelemetry/auto-instrumentations-node": "0.65.0",
22
- "@opentelemetry/exporter-logs-otlp-http": "0.206.0",
23
- "@opentelemetry/exporter-metrics-otlp-http": "0.206.0",
24
- "@opentelemetry/exporter-trace-otlp-http": "0.206.0",
25
- "@opentelemetry/resources": "2.1.0",
26
- "@opentelemetry/sdk-logs": "0.206.0",
27
- "@opentelemetry/sdk-metrics": "2.1.0",
28
- "@opentelemetry/sdk-node": "0.206.0",
29
- "@opentelemetry/sdk-trace-node": "2.1.0",
20
+ "@opentelemetry/api-logs": "0.207.0",
21
+ "@opentelemetry/exporter-logs-otlp-http": "0.207.0",
22
+ "@opentelemetry/exporter-metrics-otlp-http": "0.207.0",
23
+ "@opentelemetry/exporter-trace-otlp-http": "0.207.0",
24
+ "@opentelemetry/instrumentation": "0.207.0",
25
+ "@opentelemetry/instrumentation-dns": "0.51.0",
26
+ "@opentelemetry/instrumentation-express": "0.56.0",
27
+ "@opentelemetry/instrumentation-fs": "0.27.0",
28
+ "@opentelemetry/instrumentation-grpc": "0.207.0",
29
+ "@opentelemetry/instrumentation-http": "0.207.0",
30
+ "@opentelemetry/instrumentation-net": "0.51.0",
31
+ "@opentelemetry/instrumentation-redis": "0.56.0",
32
+ "@opentelemetry/instrumentation-socket.io": "0.54.0",
33
+ "@opentelemetry/instrumentation-undici": "0.18.0",
34
+ "@opentelemetry/resource-detector-container": "0.7.10",
35
+ "@opentelemetry/resource-detector-gcp": "0.42.0",
36
+ "@opentelemetry/resources": "2.2.0",
37
+ "@opentelemetry/sdk-logs": "0.207.0",
38
+ "@opentelemetry/sdk-metrics": "2.2.0",
39
+ "@opentelemetry/sdk-node": "0.207.0",
40
+ "@opentelemetry/sdk-trace-node": "2.2.0",
30
41
  "@opentelemetry/semantic-conventions": "1.37.0",
31
42
  "fast-safe-stringify": "2.1.1",
32
43
  "kleur": "4.1.5"