@sebspark/otel 0.5.2 → 1.0.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/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:
@@ -42,6 +55,7 @@ import { getLogger } from '@sebspark/otel'
42
55
 
43
56
  const logger = getLogger()
44
57
 
58
+ // Will throw if OTEL is not yet initialized
45
59
  logger.debug('debug message')
46
60
  logger.info('something happened')
47
61
  logger.warn('almost bad')
@@ -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,62 +746,51 @@ 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
- sdk.start();
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
  const { systemName, systemVersion, resourceAttributes } = detectTelemetryContext(serviceOverride);
697
795
  const defaultAttrs = {
698
796
  ...resourceAttributes,
@@ -700,12 +798,9 @@ function getLogger(serviceOverride, extraAttrs = {}, testProvider) {
700
798
  };
701
799
  function emit(severityText, body, attrs = {}) {
702
800
  if (!isInitialized()) {
703
- initialize().then(() => {
704
- emit(severityText, body, attrs);
705
- });
706
- return;
801
+ throw new Error("OTEL must be initialized before calling getLogger()");
707
802
  }
708
- const logger = testProvider ? testProvider.getLogger(systemName, systemVersion) : import_api_logs2.logs.getLogger(systemName, systemVersion);
803
+ const logger = import_api_logs3.logs.getLogger(systemName, systemVersion);
709
804
  const span = import_api4.trace.getSpan(import_api4.context.active());
710
805
  const spanContext = span?.spanContext();
711
806
  logger.emit({
@@ -747,8 +842,10 @@ function getLogger(serviceOverride, extraAttrs = {}, testProvider) {
747
842
 
748
843
  // src/metrics.ts
749
844
  var import_api5 = require("@opentelemetry/api");
750
- async function getMeter(componentNameOverride) {
751
- await initialize();
845
+ function getMeter(componentNameOverride) {
846
+ if (!isInitialized()) {
847
+ throw new Error("OTEL must be initialized before calling getMeter()");
848
+ }
752
849
  const { componentName, systemName, systemVersion } = detectTelemetryContext(
753
850
  componentNameOverride
754
851
  );
@@ -757,8 +854,10 @@ async function getMeter(componentNameOverride) {
757
854
 
758
855
  // src/tracer.ts
759
856
  var import_api6 = require("@opentelemetry/api");
760
- async function getTracer(componentNameOverride) {
761
- await initialize();
857
+ function getTracer(componentNameOverride) {
858
+ if (!isInitialized()) {
859
+ throw new Error("OTEL must be initialized before calling getMeter()");
860
+ }
762
861
  const { componentName, systemName, systemVersion } = detectTelemetryContext(
763
862
  componentNameOverride
764
863
  );
@@ -840,12 +939,12 @@ function extractArgs(spanOptionsSpanOrFunc, spanOrFunc, func) {
840
939
  var isFunction = (value) => typeof value === "function";
841
940
  var isSpan = (value) => value !== null && value !== void 0 && isFunction(value.spanContext) && isFunction(value.end);
842
941
  var isSpanOptions = (value) => value !== null && value !== void 0 && (!!value.startTime || !!value.attributes || !!value.kind) && !isSpan(value);
843
-
844
- // src/index.ts
845
- initialize();
846
942
  // Annotate the CommonJS export names for ESM import in node:
847
943
  0 && (module.exports = {
848
944
  getLogger,
849
945
  getMeter,
850
- getTracer
946
+ getTracer,
947
+ initialize,
948
+ instrumentations,
949
+ isInitialized
851
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,62 +730,51 @@ 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
- sdk.start();
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
  const { systemName, systemVersion, resourceAttributes } = detectTelemetryContext(serviceOverride);
674
779
  const defaultAttrs = {
675
780
  ...resourceAttributes,
@@ -677,13 +782,10 @@ function getLogger(serviceOverride, extraAttrs = {}, testProvider) {
677
782
  };
678
783
  function emit(severityText, body, attrs = {}) {
679
784
  if (!isInitialized()) {
680
- initialize().then(() => {
681
- emit(severityText, body, attrs);
682
- });
683
- return;
785
+ throw new Error("OTEL must be initialized before calling getLogger()");
684
786
  }
685
- const logger = testProvider ? testProvider.getLogger(systemName, systemVersion) : logs2.getLogger(systemName, systemVersion);
686
- const span = trace.getSpan(context.active());
787
+ const logger = logs2.getLogger(systemName, systemVersion);
788
+ const span = trace2.getSpan(context.active());
687
789
  const spanContext = span?.spanContext();
688
790
  logger.emit({
689
791
  severityText,
@@ -723,27 +825,31 @@ function getLogger(serviceOverride, extraAttrs = {}, testProvider) {
723
825
  }
724
826
 
725
827
  // src/metrics.ts
726
- import { metrics } from "@opentelemetry/api";
727
- async function getMeter(componentNameOverride) {
728
- 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
+ }
729
833
  const { componentName, systemName, systemVersion } = detectTelemetryContext(
730
834
  componentNameOverride
731
835
  );
732
- return metrics.getMeter(componentName ?? systemName, systemVersion);
836
+ return metrics2.getMeter(componentName ?? systemName, systemVersion);
733
837
  }
734
838
 
735
839
  // src/tracer.ts
736
840
  import {
737
841
  context as context2,
738
842
  SpanStatusCode as SpanStatusCode3,
739
- trace as trace2
843
+ trace as trace3
740
844
  } from "@opentelemetry/api";
741
- async function getTracer(componentNameOverride) {
742
- await initialize();
845
+ function getTracer(componentNameOverride) {
846
+ if (!isInitialized()) {
847
+ throw new Error("OTEL must be initialized before calling getMeter()");
848
+ }
743
849
  const { componentName, systemName, systemVersion } = detectTelemetryContext(
744
850
  componentNameOverride
745
851
  );
746
- const tracer = trace2.getTracer(
852
+ const tracer = trace3.getTracer(
747
853
  componentName ?? systemName,
748
854
  systemVersion
749
855
  );
@@ -753,9 +859,9 @@ async function getTracer(componentNameOverride) {
753
859
  spanOrFunc,
754
860
  func
755
861
  );
756
- const parentContext = parent ? trace2.setSpan(context2.active(), parent) : context2.active();
862
+ const parentContext = parent ? trace3.setSpan(context2.active(), parent) : context2.active();
757
863
  const span = tracer.startSpan(name, options, parentContext);
758
- return await context2.with(trace2.setSpan(parentContext, span), async () => {
864
+ return await context2.with(trace3.setSpan(parentContext, span), async () => {
759
865
  try {
760
866
  const result = await fn(span);
761
867
  span.setStatus({ code: SpanStatusCode3.OK });
@@ -776,9 +882,9 @@ async function getTracer(componentNameOverride) {
776
882
  spanOrFunc,
777
883
  func
778
884
  );
779
- const parentContext = parent ? trace2.setSpan(context2.active(), parent) : context2.active();
885
+ const parentContext = parent ? trace3.setSpan(context2.active(), parent) : context2.active();
780
886
  const span = tracer.startSpan(name, options, parentContext);
781
- return context2.with(trace2.setSpan(parentContext, span), () => {
887
+ return context2.with(trace3.setSpan(parentContext, span), () => {
782
888
  try {
783
889
  const result = fn(span);
784
890
  span.setStatus({ code: SpanStatusCode3.OK });
@@ -821,11 +927,11 @@ function extractArgs(spanOptionsSpanOrFunc, spanOrFunc, func) {
821
927
  var isFunction = (value) => typeof value === "function";
822
928
  var isSpan = (value) => value !== null && value !== void 0 && isFunction(value.spanContext) && isFunction(value.end);
823
929
  var isSpanOptions = (value) => value !== null && value !== void 0 && (!!value.startTime || !!value.attributes || !!value.kind) && !isSpan(value);
824
-
825
- // src/index.ts
826
- initialize();
827
930
  export {
828
931
  getLogger,
829
932
  getMeter,
830
- getTracer
933
+ getTracer,
934
+ initialize,
935
+ instrumentations,
936
+ isInitialized
831
937
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sebspark/otel",
3
- "version": "0.5.2",
3
+ "version": "1.0.1",
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"