@shuttle-labs/node-observability 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.
@@ -0,0 +1,3 @@
1
+ export { ObservabilityModule } from './nestjs';
2
+ export { getMetricsMeter } from './metrics';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getMetricsMeter = exports.ObservabilityModule = void 0;
4
+ var nestjs_1 = require("./nestjs");
5
+ Object.defineProperty(exports, "ObservabilityModule", { enumerable: true, get: function () { return nestjs_1.ObservabilityModule; } });
6
+ var metrics_1 = require("./metrics");
7
+ Object.defineProperty(exports, "getMetricsMeter", { enumerable: true, get: function () { return metrics_1.getMetricsMeter; } });
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,mCAA+C;AAAtC,6GAAA,mBAAmB,OAAA;AAC5B,qCAA4C;AAAnC,0GAAA,eAAe,OAAA"}
@@ -0,0 +1,10 @@
1
+ import { type Meter } from '@opentelemetry/api';
2
+ /**
3
+ * Returns an OTel Meter. Call after register() has initialized the SDK.
4
+ * Usage:
5
+ * const meter = getMetricsMeter();
6
+ * const counter = meter.createCounter('my_counter');
7
+ * counter.add(1, { label: 'value' });
8
+ */
9
+ export declare const getMetricsMeter: (name?: string, version?: string) => Meter;
10
+ //# sourceMappingURL=metrics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../src/metrics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,KAAK,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAEzD;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,GAAI,OAAO,MAAM,EAAE,UAAU,MAAM,KAAG,KAIjE,CAAC"}
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getMetricsMeter = void 0;
4
+ const api_1 = require("@opentelemetry/api");
5
+ /**
6
+ * Returns an OTel Meter. Call after register() has initialized the SDK.
7
+ * Usage:
8
+ * const meter = getMetricsMeter();
9
+ * const counter = meter.createCounter('my_counter');
10
+ * counter.add(1, { label: 'value' });
11
+ */
12
+ const getMetricsMeter = (name, version) => {
13
+ const svcName = name ?? process.env.OTEL_SERVICE_NAME ?? 'unknown-service';
14
+ const svcVersion = version ?? process.env.OTEL_SERVICE_VERSION ?? '1.0.0';
15
+ return api_1.metrics.getMeter(svcName, svcVersion);
16
+ };
17
+ exports.getMetricsMeter = getMetricsMeter;
18
+ //# sourceMappingURL=metrics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics.js","sourceRoot":"","sources":["../src/metrics.ts"],"names":[],"mappings":";;;AAAA,4CAAyD;AAEzD;;;;;;GAMG;AACI,MAAM,eAAe,GAAG,CAAC,IAAa,EAAE,OAAgB,EAAS,EAAE;IACxE,MAAM,OAAO,GAAG,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,iBAAiB,CAAC;IAC3E,MAAM,UAAU,GAAG,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,OAAO,CAAC;IAC1E,OAAO,aAAO,CAAC,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;AAC/C,CAAC,CAAC;AAJW,QAAA,eAAe,mBAI1B"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Drop-in replacement for LoggerModule in NestJS apps.
3
+ * - Development: pino-pretty (colorized, readable)
4
+ * - Production: pino-opentelemetry-transport → OTLP → SigNoz
5
+ * (reads OTEL_SERVICE_NAME + OTEL_EXPORTER_OTLP_ENDPOINT from env)
6
+ */
7
+ export declare class ObservabilityModule {
8
+ }
9
+ //# sourceMappingURL=nestjs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nestjs.d.ts","sourceRoot":"","sources":["../src/nestjs.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,qBAYa,mBAAmB;CAAG"}
package/dist/nestjs.js ADDED
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
3
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
4
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
5
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
6
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
7
+ var _, done = false;
8
+ for (var i = decorators.length - 1; i >= 0; i--) {
9
+ var context = {};
10
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
11
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
12
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
13
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
14
+ if (kind === "accessor") {
15
+ if (result === void 0) continue;
16
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
17
+ if (_ = accept(result.get)) descriptor.get = _;
18
+ if (_ = accept(result.set)) descriptor.set = _;
19
+ if (_ = accept(result.init)) initializers.unshift(_);
20
+ }
21
+ else if (_ = accept(result)) {
22
+ if (kind === "field") initializers.unshift(_);
23
+ else descriptor[key] = _;
24
+ }
25
+ }
26
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
27
+ done = true;
28
+ };
29
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
30
+ var useValue = arguments.length > 2;
31
+ for (var i = 0; i < initializers.length; i++) {
32
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
33
+ }
34
+ return useValue ? value : void 0;
35
+ };
36
+ Object.defineProperty(exports, "__esModule", { value: true });
37
+ exports.ObservabilityModule = void 0;
38
+ const common_1 = require("@nestjs/common");
39
+ const nestjs_pino_1 = require("nestjs-pino");
40
+ /**
41
+ * Drop-in replacement for LoggerModule in NestJS apps.
42
+ * - Development: pino-pretty (colorized, readable)
43
+ * - Production: pino-opentelemetry-transport → OTLP → SigNoz
44
+ * (reads OTEL_SERVICE_NAME + OTEL_EXPORTER_OTLP_ENDPOINT from env)
45
+ */
46
+ let ObservabilityModule = (() => {
47
+ let _classDecorators = [(0, common_1.Module)({
48
+ imports: [
49
+ nestjs_pino_1.LoggerModule.forRoot({
50
+ pinoHttp: {
51
+ level: process.env.NODE_ENV === 'production' ? 'info' : 'debug',
52
+ transport: process.env.NODE_ENV !== 'production'
53
+ ? { target: 'pino-pretty', options: { colorize: true, singleLine: true } }
54
+ : { target: 'pino-opentelemetry-transport' },
55
+ },
56
+ }),
57
+ ],
58
+ })];
59
+ let _classDescriptor;
60
+ let _classExtraInitializers = [];
61
+ let _classThis;
62
+ var ObservabilityModule = class {
63
+ static { _classThis = this; }
64
+ static {
65
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
66
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
67
+ ObservabilityModule = _classThis = _classDescriptor.value;
68
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
69
+ __runInitializers(_classThis, _classExtraInitializers);
70
+ }
71
+ };
72
+ return ObservabilityModule = _classThis;
73
+ })();
74
+ exports.ObservabilityModule = ObservabilityModule;
75
+ //# sourceMappingURL=nestjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nestjs.js","sourceRoot":"","sources":["../src/nestjs.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2CAAwC;AACxC,6CAA2C;AAE3C;;;;;GAKG;IAaU,mBAAmB;4BAZ/B,IAAA,eAAM,EAAC;YACN,OAAO,EAAE;gBACP,0BAAY,CAAC,OAAO,CAAC;oBACnB,QAAQ,EAAE;wBACR,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO;wBAC/D,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY;4BAC9C,CAAC,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,EAAE;4BAC1E,CAAC,CAAC,EAAE,MAAM,EAAE,8BAA8B,EAAE;qBAC/C;iBACF,CAAC;aACH;SACF,CAAC;;;;;;;;YACF,6KAAmC;;;YAAtB,uDAAmB;;;;;AAAnB,kDAAmB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=register.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../src/register.ts"],"names":[],"mappings":""}
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const sdk_node_1 = require("@opentelemetry/sdk-node");
4
+ const auto_instrumentations_node_1 = require("@opentelemetry/auto-instrumentations-node");
5
+ const exporter_metrics_otlp_http_1 = require("@opentelemetry/exporter-metrics-otlp-http");
6
+ const sdk_metrics_1 = require("@opentelemetry/sdk-metrics");
7
+ // Guard against double-initialization (e.g. hot reload, test environments)
8
+ const g = global;
9
+ if (!g.__otelSdkInitialized) {
10
+ g.__otelSdkInitialized = true;
11
+ const exportIntervalMillis = Number(process.env.OTEL_METRIC_EXPORT_INTERVAL ?? 15000);
12
+ const sdk = new sdk_node_1.NodeSDK({
13
+ // Resource (service.name, deployment.environment) is read automatically
14
+ // from OTEL_SERVICE_NAME and OTEL_RESOURCE_ATTRIBUTES env vars
15
+ // Traces — exported via OTEL_EXPORTER_OTLP_ENDPOINT (set by deploy-ecs action)
16
+ // Metrics
17
+ metricReader: new sdk_metrics_1.PeriodicExportingMetricReader({
18
+ exporter: new exporter_metrics_otlp_http_1.OTLPMetricExporter(),
19
+ exportIntervalMillis: Number.isFinite(exportIntervalMillis) ? exportIntervalMillis : 15000,
20
+ }),
21
+ // Auto-instrumentation: HTTP, NestJS, Express, TypeORM, Kafka, Redis, pg, etc.
22
+ instrumentations: [
23
+ (0, auto_instrumentations_node_1.getNodeAutoInstrumentations)({
24
+ // fs instrumentation is very noisy — disable it
25
+ '@opentelemetry/instrumentation-fs': { enabled: false },
26
+ }),
27
+ ],
28
+ });
29
+ sdk.start();
30
+ process.on('SIGTERM', () => {
31
+ sdk.shutdown().catch(() => { });
32
+ });
33
+ }
34
+ //# sourceMappingURL=register.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register.js","sourceRoot":"","sources":["../src/register.ts"],"names":[],"mappings":";;AAAA,sDAAkD;AAClD,0FAAwF;AACxF,0FAA+E;AAC/E,4DAA2E;AAE3E,2EAA2E;AAC3E,MAAM,CAAC,GAAG,MAA4D,CAAC;AACvE,IAAI,CAAC,CAAC,CAAC,oBAAoB,EAAE,CAAC;IAC5B,CAAC,CAAC,oBAAoB,GAAG,IAAI,CAAC;IAE9B,MAAM,oBAAoB,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,2BAA2B,IAAI,KAAK,CAAC,CAAC;IAEtF,MAAM,GAAG,GAAG,IAAI,kBAAO,CAAC;QACtB,wEAAwE;QACxE,+DAA+D;QAE/D,+EAA+E;QAC/E,UAAU;QACV,YAAY,EAAE,IAAI,2CAA6B,CAAC;YAC9C,QAAQ,EAAE,IAAI,+CAAkB,EAAE;YAClC,oBAAoB,EAAE,MAAM,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,KAAK;SAC3F,CAAC;QAEF,+EAA+E;QAC/E,gBAAgB,EAAE;YAChB,IAAA,wDAA2B,EAAC;gBAC1B,gDAAgD;gBAChD,mCAAmC,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE;aACxD,CAAC;SACH;KACF,CAAC,CAAC;IAEH,GAAG,CAAC,KAAK,EAAE,CAAC;IAEZ,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;QACzB,GAAG,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;AACL,CAAC"}
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@shuttle-labs/node-observability",
3
+ "version": "1.0.0",
4
+ "description": "Shared OTel observability for Node.js services — traces, logs, metrics",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "exports": {
8
+ ".": "./dist/index.js",
9
+ "./register": "./dist/register.js",
10
+ "./nestjs": "./dist/nestjs.js"
11
+ },
12
+ "dependencies": {
13
+ "@opentelemetry/api": "^1.9.0",
14
+ "@opentelemetry/auto-instrumentations-node": "^0.71.0",
15
+ "@opentelemetry/exporter-metrics-otlp-http": "^0.205.0",
16
+ "@opentelemetry/exporter-trace-otlp-http": "^0.213.0",
17
+ "@opentelemetry/resources": "^2.1.0",
18
+ "@opentelemetry/sdk-metrics": "^2.1.0",
19
+ "@opentelemetry/sdk-node": "^0.213.0",
20
+ "@opentelemetry/semantic-conventions": "^1.37.0",
21
+ "pino": "^9.0.0",
22
+ "pino-opentelemetry-transport": "^3.0.0"
23
+ },
24
+ "peerDependencies": {
25
+ "nestjs-pino": "^4.0.0",
26
+ "pino-http": "^10.0.0"
27
+ },
28
+ "peerDependenciesMeta": {
29
+ "nestjs-pino": {
30
+ "optional": true
31
+ },
32
+ "pino-http": {
33
+ "optional": true
34
+ }
35
+ },
36
+ "devDependencies": {
37
+ "@nestjs/common": "^11.0.0",
38
+ "@types/node": "^22.0.0",
39
+ "typescript": "^5.0.0"
40
+ },
41
+ "publishConfig": {
42
+ "access": "public"
43
+ },
44
+ "scripts": {
45
+ "build": "tsc"
46
+ }
47
+ }
package/src/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export { ObservabilityModule } from './nestjs';
2
+ export { getMetricsMeter } from './metrics';
package/src/metrics.ts ADDED
@@ -0,0 +1,14 @@
1
+ import { metrics, type Meter } from '@opentelemetry/api';
2
+
3
+ /**
4
+ * Returns an OTel Meter. Call after register() has initialized the SDK.
5
+ * Usage:
6
+ * const meter = getMetricsMeter();
7
+ * const counter = meter.createCounter('my_counter');
8
+ * counter.add(1, { label: 'value' });
9
+ */
10
+ export const getMetricsMeter = (name?: string, version?: string): Meter => {
11
+ const svcName = name ?? process.env.OTEL_SERVICE_NAME ?? 'unknown-service';
12
+ const svcVersion = version ?? process.env.OTEL_SERVICE_VERSION ?? '1.0.0';
13
+ return metrics.getMeter(svcName, svcVersion);
14
+ };
package/src/nestjs.ts ADDED
@@ -0,0 +1,22 @@
1
+ import { Module } from '@nestjs/common';
2
+ import { LoggerModule } from 'nestjs-pino';
3
+
4
+ /**
5
+ * Drop-in replacement for LoggerModule in NestJS apps.
6
+ * - Development: pino-pretty (colorized, readable)
7
+ * - Production: pino-opentelemetry-transport → OTLP → SigNoz
8
+ * (reads OTEL_SERVICE_NAME + OTEL_EXPORTER_OTLP_ENDPOINT from env)
9
+ */
10
+ @Module({
11
+ imports: [
12
+ LoggerModule.forRoot({
13
+ pinoHttp: {
14
+ level: process.env.NODE_ENV === 'production' ? 'info' : 'debug',
15
+ transport: process.env.NODE_ENV !== 'production'
16
+ ? { target: 'pino-pretty', options: { colorize: true, singleLine: true } }
17
+ : { target: 'pino-opentelemetry-transport' },
18
+ },
19
+ }),
20
+ ],
21
+ })
22
+ export class ObservabilityModule {}
@@ -0,0 +1,38 @@
1
+ import { NodeSDK } from '@opentelemetry/sdk-node';
2
+ import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
3
+ import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http';
4
+ import { PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics';
5
+
6
+ // Guard against double-initialization (e.g. hot reload, test environments)
7
+ const g = global as typeof global & { __otelSdkInitialized?: boolean };
8
+ if (!g.__otelSdkInitialized) {
9
+ g.__otelSdkInitialized = true;
10
+
11
+ const exportIntervalMillis = Number(process.env.OTEL_METRIC_EXPORT_INTERVAL ?? 15000);
12
+
13
+ const sdk = new NodeSDK({
14
+ // Resource (service.name, deployment.environment) is read automatically
15
+ // from OTEL_SERVICE_NAME and OTEL_RESOURCE_ATTRIBUTES env vars
16
+
17
+ // Traces — exported via OTEL_EXPORTER_OTLP_ENDPOINT (set by deploy-ecs action)
18
+ // Metrics
19
+ metricReader: new PeriodicExportingMetricReader({
20
+ exporter: new OTLPMetricExporter(),
21
+ exportIntervalMillis: Number.isFinite(exportIntervalMillis) ? exportIntervalMillis : 15000,
22
+ }),
23
+
24
+ // Auto-instrumentation: HTTP, NestJS, Express, TypeORM, Kafka, Redis, pg, etc.
25
+ instrumentations: [
26
+ getNodeAutoInstrumentations({
27
+ // fs instrumentation is very noisy — disable it
28
+ '@opentelemetry/instrumentation-fs': { enabled: false },
29
+ }),
30
+ ],
31
+ });
32
+
33
+ sdk.start();
34
+
35
+ process.on('SIGTERM', () => {
36
+ sdk.shutdown().catch(() => {});
37
+ });
38
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,17 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "commonjs",
5
+ "lib": ["ES2022"],
6
+ "outDir": "dist",
7
+ "rootDir": "src",
8
+ "strict": true,
9
+ "esModuleInterop": true,
10
+ "skipLibCheck": true,
11
+ "declaration": true,
12
+ "declarationMap": true,
13
+ "sourceMap": true
14
+ },
15
+ "include": ["src"],
16
+ "exclude": ["node_modules", "dist"]
17
+ }