otel-express-collector 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 +20 -0
- package/dist/collector.d.ts +35 -0
- package/dist/collector.d.ts.map +1 -0
- package/dist/collector.js +158 -0
- package/dist/collector.js.map +1 -0
- package/dist/decorators.d.ts +16 -0
- package/dist/decorators.d.ts.map +1 -0
- package/dist/decorators.js +103 -0
- package/dist/decorators.js.map +1 -0
- package/dist/express.d.ts +23 -0
- package/dist/express.d.ts.map +1 -0
- package/dist/express.js +166 -0
- package/dist/express.js.map +1 -0
- package/dist/health.d.ts +28 -0
- package/dist/health.d.ts.map +1 -0
- package/dist/health.js +121 -0
- package/dist/health.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +43 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +21 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +137 -0
- package/dist/logger.js.map +1 -0
- package/dist/metrics.d.ts +39 -0
- package/dist/metrics.d.ts.map +1 -0
- package/dist/metrics.js +213 -0
- package/dist/metrics.js.map +1 -0
- package/dist/types.d.ts +49 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +55 -0
package/README.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# OpenTelemetry Express Collector
|
|
2
|
+
|
|
3
|
+
A comprehensive OpenTelemetry instrumentation package for Node.js Express microservices.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Automatic Instrumentation**: HTTP requests, database queries, and more
|
|
8
|
+
- **Structured Logging**: Winston integration with OpenTelemetry export
|
|
9
|
+
- **Metrics Collection**: HTTP, database, business, and system metrics
|
|
10
|
+
- **Distributed Tracing**: End-to-end trace correlation
|
|
11
|
+
- **Health Checks**: Built-in health, readiness, and liveness endpoints
|
|
12
|
+
- **Decorators**: Easy method-level tracing with decorators
|
|
13
|
+
- **TypeScript Support**: Full type definitions
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install otel-express-collector
|
|
19
|
+
# or
|
|
20
|
+
yarn add otel-express-collector
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { LoggerProvider } from '@opentelemetry/sdk-logs';
|
|
2
|
+
import { CollectorConfig } from './types';
|
|
3
|
+
interface ResolvedCollectorConfig {
|
|
4
|
+
serviceName: string;
|
|
5
|
+
serviceVersion: string;
|
|
6
|
+
otlpEndpoint: string;
|
|
7
|
+
tracesEndpoint: string;
|
|
8
|
+
metricsEndpoint: string;
|
|
9
|
+
logsEndpoint: string;
|
|
10
|
+
enableTracing: boolean;
|
|
11
|
+
enableMetrics: boolean;
|
|
12
|
+
enableLogging: boolean;
|
|
13
|
+
enableConsoleExport: boolean;
|
|
14
|
+
metricExportInterval: number;
|
|
15
|
+
logBatchSize: number;
|
|
16
|
+
resourceAttributes: Record<string, string | number | boolean>;
|
|
17
|
+
instrumentations: string[];
|
|
18
|
+
}
|
|
19
|
+
export declare class OpenTelemetryCollector {
|
|
20
|
+
private sdk;
|
|
21
|
+
private loggerProvider;
|
|
22
|
+
private isInitialized;
|
|
23
|
+
private isStarted;
|
|
24
|
+
private config;
|
|
25
|
+
constructor(config: CollectorConfig);
|
|
26
|
+
private initialize;
|
|
27
|
+
private getInstrumentations;
|
|
28
|
+
start(): Promise<void>;
|
|
29
|
+
shutdown(): Promise<void>;
|
|
30
|
+
isRunning(): boolean;
|
|
31
|
+
getLoggerProvider(): LoggerProvider | null;
|
|
32
|
+
getConfig(): Readonly<ResolvedCollectorConfig>;
|
|
33
|
+
}
|
|
34
|
+
export {};
|
|
35
|
+
//# sourceMappingURL=collector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collector.d.ts","sourceRoot":"","sources":["../src/collector.ts"],"names":[],"mappings":"AAYA,OAAO,EACL,cAAc,EAIf,MAAM,yBAAyB,CAAC;AASjC,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAK1C,UAAU,uBAAuB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IAEvB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IAErB,aAAa,EAAE,OAAO,CAAC;IACvB,aAAa,EAAE,OAAO,CAAC;IACvB,aAAa,EAAE,OAAO,CAAC;IACvB,mBAAmB,EAAE,OAAO,CAAC;IAE7B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,YAAY,EAAE,MAAM,CAAC;IAErB,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;IAC9D,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED,qBAAa,sBAAsB;IACjC,OAAO,CAAC,GAAG,CAAwB;IACnC,OAAO,CAAC,cAAc,CAA+B;IAErD,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,SAAS,CAAS;IAE1B,OAAO,CAAC,MAAM,CAA0B;gBAE5B,MAAM,EAAE,eAAe;YAuCrB,UAAU;IA0ExB,OAAO,CAAC,mBAAmB;IAgBd,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAMtB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAkB/B,SAAS,IAAI,OAAO;IAIpB,iBAAiB,IAAI,cAAc,GAAG,IAAI;IAK1C,SAAS,IAAI,QAAQ,CAAC,uBAAuB,CAAC;CAGtD"}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OpenTelemetryCollector = void 0;
|
|
4
|
+
const sdk_node_1 = require("@opentelemetry/sdk-node");
|
|
5
|
+
const exporter_trace_otlp_grpc_1 = require("@opentelemetry/exporter-trace-otlp-grpc");
|
|
6
|
+
const exporter_metrics_otlp_grpc_1 = require("@opentelemetry/exporter-metrics-otlp-grpc");
|
|
7
|
+
const exporter_logs_otlp_grpc_1 = require("@opentelemetry/exporter-logs-otlp-grpc");
|
|
8
|
+
const sdk_trace_base_1 = require("@opentelemetry/sdk-trace-base");
|
|
9
|
+
const sdk_metrics_1 = require("@opentelemetry/sdk-metrics");
|
|
10
|
+
const sdk_logs_1 = require("@opentelemetry/sdk-logs");
|
|
11
|
+
const api_logs_1 = require("@opentelemetry/api-logs");
|
|
12
|
+
const auto_instrumentations_node_1 = require("@opentelemetry/auto-instrumentations-node");
|
|
13
|
+
const resources_1 = require("@opentelemetry/resources");
|
|
14
|
+
const api_1 = require("@opentelemetry/api");
|
|
15
|
+
class OpenTelemetryCollector {
|
|
16
|
+
constructor(config) {
|
|
17
|
+
this.sdk = null;
|
|
18
|
+
this.loggerProvider = null;
|
|
19
|
+
this.isInitialized = false;
|
|
20
|
+
this.isStarted = false;
|
|
21
|
+
if (!config.serviceName)
|
|
22
|
+
throw new Error('serviceName is required');
|
|
23
|
+
if (!config.serviceVersion)
|
|
24
|
+
throw new Error('serviceVersion is required');
|
|
25
|
+
const otlpEndpoint = config.otlpEndpoint ?? 'http://localhost:4317';
|
|
26
|
+
this.config = {
|
|
27
|
+
serviceName: config.serviceName,
|
|
28
|
+
serviceVersion: config.serviceVersion,
|
|
29
|
+
otlpEndpoint,
|
|
30
|
+
tracesEndpoint: config.tracesEndpoint ?? otlpEndpoint,
|
|
31
|
+
metricsEndpoint: config.metricsEndpoint ?? otlpEndpoint,
|
|
32
|
+
logsEndpoint: config.logsEndpoint ?? otlpEndpoint,
|
|
33
|
+
enableTracing: config.enableTracing ?? true,
|
|
34
|
+
enableMetrics: config.enableMetrics ?? true,
|
|
35
|
+
enableLogging: config.enableLogging ?? true,
|
|
36
|
+
enableConsoleExport: config.enableConsoleExport ?? false,
|
|
37
|
+
metricExportInterval: config.metricExportInterval ?? 60000,
|
|
38
|
+
logBatchSize: config.logBatchSize ?? 512,
|
|
39
|
+
resourceAttributes: config.resourceAttributes ?? {},
|
|
40
|
+
instrumentations: config.instrumentations ?? [],
|
|
41
|
+
};
|
|
42
|
+
if (process.env.NODE_ENV === 'development' ||
|
|
43
|
+
this.config.enableConsoleExport) {
|
|
44
|
+
api_1.diag.setLogger(new api_1.DiagConsoleLogger(), api_1.DiagLogLevel.DEBUG);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/* =========================
|
|
48
|
+
INITIALIZATION
|
|
49
|
+
========================= */
|
|
50
|
+
async initialize() {
|
|
51
|
+
if (this.isInitialized)
|
|
52
|
+
return;
|
|
53
|
+
// ✅ DOC-ALIGNED RESOURCE ATTRIBUTES (PLAIN STRINGS)
|
|
54
|
+
const resource = (0, resources_1.resourceFromAttributes)({
|
|
55
|
+
'service.name': this.config.serviceName,
|
|
56
|
+
'service.version': this.config.serviceVersion,
|
|
57
|
+
'deployment.environment': process.env.NODE_ENV ?? 'development',
|
|
58
|
+
'process.runtime.name': 'nodejs',
|
|
59
|
+
'process.runtime.version': process.version,
|
|
60
|
+
...this.config.resourceAttributes,
|
|
61
|
+
});
|
|
62
|
+
/* -------- Traces & Metrics -------- */
|
|
63
|
+
this.sdk = new sdk_node_1.NodeSDK({
|
|
64
|
+
resource,
|
|
65
|
+
traceExporter: this.config.enableTracing
|
|
66
|
+
? this.config.enableConsoleExport
|
|
67
|
+
? new sdk_trace_base_1.ConsoleSpanExporter()
|
|
68
|
+
: new exporter_trace_otlp_grpc_1.OTLPTraceExporter({ url: this.config.tracesEndpoint })
|
|
69
|
+
: undefined,
|
|
70
|
+
metricReader: this.config.enableMetrics
|
|
71
|
+
? new sdk_metrics_1.PeriodicExportingMetricReader({
|
|
72
|
+
exporter: this.config.enableConsoleExport
|
|
73
|
+
? new sdk_metrics_1.ConsoleMetricExporter()
|
|
74
|
+
: new exporter_metrics_otlp_grpc_1.OTLPMetricExporter({ url: this.config.metricsEndpoint }),
|
|
75
|
+
exportIntervalMillis: this.config.metricExportInterval,
|
|
76
|
+
})
|
|
77
|
+
: undefined,
|
|
78
|
+
instrumentations: this.getInstrumentations(),
|
|
79
|
+
});
|
|
80
|
+
/* -------- Logs (SDK-LOGS DOC-ALIGNED) -------- */
|
|
81
|
+
if (this.config.enableLogging) {
|
|
82
|
+
const logExporter = this.config.enableConsoleExport
|
|
83
|
+
? new sdk_logs_1.ConsoleLogRecordExporter()
|
|
84
|
+
: new exporter_logs_otlp_grpc_1.OTLPLogExporter({ url: this.config.logsEndpoint });
|
|
85
|
+
this.loggerProvider = new sdk_logs_1.LoggerProvider({
|
|
86
|
+
resource,
|
|
87
|
+
loggerConfigurator: (0, sdk_logs_1.createLoggerConfigurator)([
|
|
88
|
+
{
|
|
89
|
+
pattern: '*',
|
|
90
|
+
config: {
|
|
91
|
+
minimumSeverity: api_logs_1.SeverityNumber.INFO,
|
|
92
|
+
traceBased: false,
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
]),
|
|
96
|
+
processors: [
|
|
97
|
+
new sdk_logs_1.BatchLogRecordProcessor(logExporter, {
|
|
98
|
+
maxExportBatchSize: this.config.logBatchSize,
|
|
99
|
+
}),
|
|
100
|
+
],
|
|
101
|
+
});
|
|
102
|
+
// REQUIRED by @opentelemetry/sdk-logs docs
|
|
103
|
+
api_logs_1.logs.setGlobalLoggerProvider(this.loggerProvider);
|
|
104
|
+
}
|
|
105
|
+
await this.sdk.start();
|
|
106
|
+
this.isInitialized = true;
|
|
107
|
+
this.isStarted = true;
|
|
108
|
+
console.log(`[otel] Started for ${this.config.serviceName}`);
|
|
109
|
+
}
|
|
110
|
+
/* =========================
|
|
111
|
+
INSTRUMENTATIONS
|
|
112
|
+
========================= */
|
|
113
|
+
getInstrumentations() {
|
|
114
|
+
return [
|
|
115
|
+
(0, auto_instrumentations_node_1.getNodeAutoInstrumentations)({
|
|
116
|
+
'@opentelemetry/instrumentation-http': { enabled: true },
|
|
117
|
+
'@opentelemetry/instrumentation-express': {
|
|
118
|
+
enabled: true,
|
|
119
|
+
ignoreLayers: ['/health', '/metrics'],
|
|
120
|
+
},
|
|
121
|
+
}),
|
|
122
|
+
];
|
|
123
|
+
}
|
|
124
|
+
/* =========================
|
|
125
|
+
LIFECYCLE
|
|
126
|
+
========================= */
|
|
127
|
+
async start() {
|
|
128
|
+
if (!this.isStarted) {
|
|
129
|
+
await this.initialize();
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
async shutdown() {
|
|
133
|
+
if (!this.isStarted)
|
|
134
|
+
return;
|
|
135
|
+
await this.sdk?.shutdown();
|
|
136
|
+
await this.loggerProvider?.shutdown();
|
|
137
|
+
this.sdk = null;
|
|
138
|
+
this.loggerProvider = null;
|
|
139
|
+
this.isStarted = false;
|
|
140
|
+
this.isInitialized = false;
|
|
141
|
+
console.log('[otel] Shutdown complete');
|
|
142
|
+
}
|
|
143
|
+
/* =========================
|
|
144
|
+
HELPERS (TEST + API SAFE)
|
|
145
|
+
========================= */
|
|
146
|
+
isRunning() {
|
|
147
|
+
return this.isStarted;
|
|
148
|
+
}
|
|
149
|
+
getLoggerProvider() {
|
|
150
|
+
return this.loggerProvider;
|
|
151
|
+
}
|
|
152
|
+
// ✅ ADDED BACK — fixes your test failure
|
|
153
|
+
getConfig() {
|
|
154
|
+
return this.config;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
exports.OpenTelemetryCollector = OpenTelemetryCollector;
|
|
158
|
+
//# sourceMappingURL=collector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collector.js","sourceRoot":"","sources":["../src/collector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Logger } from './logger';
|
|
2
|
+
export interface TraceOptions {
|
|
3
|
+
/** Custom span name */
|
|
4
|
+
name?: string;
|
|
5
|
+
/** Span attributes */
|
|
6
|
+
attributes?: Record<string, any>;
|
|
7
|
+
/** Logger instance for logging */
|
|
8
|
+
logger?: Logger;
|
|
9
|
+
/** Log method arguments (default: false) */
|
|
10
|
+
logArguments?: boolean;
|
|
11
|
+
/** Log return value (default: false) */
|
|
12
|
+
logReturnValue?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export declare function Trace(options?: TraceOptions): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => PropertyDescriptor;
|
|
15
|
+
export declare function TraceAsync(options?: TraceOptions): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => PropertyDescriptor;
|
|
16
|
+
//# sourceMappingURL=decorators.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decorators.d.ts","sourceRoot":"","sources":["../src/decorators.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAElC,MAAM,WAAW,YAAY;IAC3B,uBAAuB;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,sBAAsB;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAEjC,kCAAkC;IAClC,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,4CAA4C;IAC5C,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB,wCAAwC;IACxC,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,wBAAgB,KAAK,CAAC,OAAO,GAAE,YAAiB,IAE5C,QAAQ,GAAG,EACX,aAAa,MAAM,EACnB,YAAY,kBAAkB,wBAoEjC;AAED,wBAAgB,UAAU,CAAC,OAAO,GAAE,YAAiB,IAEjD,QAAQ,GAAG,EACX,aAAa,MAAM,EACnB,YAAY,kBAAkB,wBAyCjC"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Trace = Trace;
|
|
4
|
+
exports.TraceAsync = TraceAsync;
|
|
5
|
+
const api_1 = require("@opentelemetry/api");
|
|
6
|
+
function Trace(options = {}) {
|
|
7
|
+
return function (target, propertyKey, descriptor) {
|
|
8
|
+
const originalMethod = descriptor.value;
|
|
9
|
+
const className = target.constructor.name;
|
|
10
|
+
const spanName = options.name || `${className}.${propertyKey}`;
|
|
11
|
+
const logger = options.logger;
|
|
12
|
+
descriptor.value = async function (...args) {
|
|
13
|
+
const tracer = api_1.trace.getTracer(className);
|
|
14
|
+
return tracer.startActiveSpan(spanName, async (span) => {
|
|
15
|
+
try {
|
|
16
|
+
// Add custom attributes
|
|
17
|
+
if (options.attributes) {
|
|
18
|
+
span.setAttributes(options.attributes);
|
|
19
|
+
}
|
|
20
|
+
// Add class and method names as attributes
|
|
21
|
+
span.setAttribute('class.name', className);
|
|
22
|
+
span.setAttribute('method.name', propertyKey);
|
|
23
|
+
// Log method arguments if enabled
|
|
24
|
+
if (options.logArguments && logger) {
|
|
25
|
+
logger.debug(`Method ${spanName} called with arguments`, {
|
|
26
|
+
arguments: args,
|
|
27
|
+
traceId: span.spanContext().traceId,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
// Execute the original method
|
|
31
|
+
const result = await originalMethod.apply(this, args);
|
|
32
|
+
// Log return value if enabled
|
|
33
|
+
if (options.logReturnValue && logger) {
|
|
34
|
+
logger.debug(`Method ${spanName} returned`, {
|
|
35
|
+
result,
|
|
36
|
+
traceId: span.spanContext().traceId,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
span.setStatus({ code: api_1.SpanStatusCode.OK });
|
|
40
|
+
span.end();
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
// Record exception in span
|
|
45
|
+
span.recordException(error);
|
|
46
|
+
span.setStatus({
|
|
47
|
+
code: api_1.SpanStatusCode.ERROR,
|
|
48
|
+
message: error.message,
|
|
49
|
+
});
|
|
50
|
+
// Log error if logger is available
|
|
51
|
+
if (logger) {
|
|
52
|
+
logger.error(`Method ${spanName} failed`, {
|
|
53
|
+
error: error.message,
|
|
54
|
+
stack: error.stack,
|
|
55
|
+
traceId: span.spanContext().traceId,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
span.end();
|
|
59
|
+
throw error;
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
};
|
|
63
|
+
return descriptor;
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
function TraceAsync(options = {}) {
|
|
67
|
+
return function (target, propertyKey, descriptor) {
|
|
68
|
+
const originalMethod = descriptor.value;
|
|
69
|
+
const className = target.constructor.name;
|
|
70
|
+
const spanName = options.name || `${className}.${propertyKey}`;
|
|
71
|
+
descriptor.value = function (...args) {
|
|
72
|
+
const tracer = api_1.trace.getTracer(className);
|
|
73
|
+
const promise = originalMethod.apply(this, args);
|
|
74
|
+
if (!(promise instanceof Promise)) {
|
|
75
|
+
return promise;
|
|
76
|
+
}
|
|
77
|
+
const span = tracer.startSpan(spanName, {
|
|
78
|
+
attributes: {
|
|
79
|
+
'class.name': className,
|
|
80
|
+
'method.name': propertyKey,
|
|
81
|
+
...options.attributes,
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
return promise
|
|
85
|
+
.then((result) => {
|
|
86
|
+
span.setStatus({ code: api_1.SpanStatusCode.OK });
|
|
87
|
+
span.end();
|
|
88
|
+
return result;
|
|
89
|
+
})
|
|
90
|
+
.catch((error) => {
|
|
91
|
+
span.recordException(error);
|
|
92
|
+
span.setStatus({
|
|
93
|
+
code: api_1.SpanStatusCode.ERROR,
|
|
94
|
+
message: error.message,
|
|
95
|
+
});
|
|
96
|
+
span.end();
|
|
97
|
+
throw error;
|
|
98
|
+
});
|
|
99
|
+
};
|
|
100
|
+
return descriptor;
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=decorators.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decorators.js","sourceRoot":"","sources":["../src/decorators.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Request, Response, NextFunction, Application, Router } from 'express';
|
|
2
|
+
import { Logger } from './logger';
|
|
3
|
+
import { Metrics } from './metrics';
|
|
4
|
+
export interface ExpressMiddlewareConfig {
|
|
5
|
+
/** Service name for logging */
|
|
6
|
+
serviceName: string;
|
|
7
|
+
/** Logger instance */
|
|
8
|
+
logger?: Logger;
|
|
9
|
+
/** Metrics instance */
|
|
10
|
+
metrics?: Metrics;
|
|
11
|
+
/** Paths to exclude from tracing */
|
|
12
|
+
excludePaths?: string[];
|
|
13
|
+
/** Enable request/response body logging (default: false) */
|
|
14
|
+
logBody?: boolean;
|
|
15
|
+
/** Maximum body size to log in bytes (default: 1024) */
|
|
16
|
+
maxBodyLogSize?: number;
|
|
17
|
+
/** Custom span name formatter */
|
|
18
|
+
spanNameFormatter?: (req: Request) => string;
|
|
19
|
+
}
|
|
20
|
+
export declare function createOpenTelemetryMiddleware(config: ExpressMiddlewareConfig): (req: Request, res: Response, next: NextFunction) => void;
|
|
21
|
+
export declare function createErrorMiddleware(logger?: Logger): (error: Error, req: Request, res: Response, next: NextFunction) => void;
|
|
22
|
+
export declare function configureExpressApp(app: Application | Router, config: ExpressMiddlewareConfig): void;
|
|
23
|
+
//# sourceMappingURL=express.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"express.d.ts","sourceRoot":"","sources":["../src/express.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAE/E,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,MAAM,WAAW,uBAAuB;IACtC,+BAA+B;IAC/B,WAAW,EAAE,MAAM,CAAC;IAEpB,sBAAsB;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,uBAAuB;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,oCAAoC;IACpC,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IAExB,4DAA4D;IAC5D,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,wDAAwD;IACxD,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,iCAAiC;IACjC,iBAAiB,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,MAAM,CAAC;CAC9C;AAED,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,uBAAuB,IAWnE,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,UAsIxD;AAED,wBAAgB,qBAAqB,CAAC,MAAM,CAAC,EAAE,MAAM,IAC3C,OAAO,KAAK,EAAE,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,UA6BtE;AAED,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,WAAW,GAAG,MAAM,EACzB,MAAM,EAAE,uBAAuB,GAC9B,IAAI,CAMN"}
|
package/dist/express.js
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createOpenTelemetryMiddleware = createOpenTelemetryMiddleware;
|
|
4
|
+
exports.createErrorMiddleware = createErrorMiddleware;
|
|
5
|
+
exports.configureExpressApp = configureExpressApp;
|
|
6
|
+
const api_1 = require("@opentelemetry/api");
|
|
7
|
+
function createOpenTelemetryMiddleware(config) {
|
|
8
|
+
const { serviceName, logger, metrics, excludePaths = ['/health', '/metrics', '/favicon.ico'], logBody = false, maxBodyLogSize = 1024, spanNameFormatter = (req) => `${req.method} ${req.route?.path || req.path}` } = config;
|
|
9
|
+
return (req, res, next) => {
|
|
10
|
+
// Skip excluded paths
|
|
11
|
+
if (excludePaths.some(path => req.path.startsWith(path))) {
|
|
12
|
+
return next();
|
|
13
|
+
}
|
|
14
|
+
const startTime = Date.now();
|
|
15
|
+
const tracer = api_1.trace.getTracer(serviceName);
|
|
16
|
+
const spanName = spanNameFormatter(req);
|
|
17
|
+
// Create span for this request
|
|
18
|
+
const span = tracer.startSpan(spanName, {
|
|
19
|
+
attributes: {
|
|
20
|
+
'http.method': req.method,
|
|
21
|
+
'http.url': req.url,
|
|
22
|
+
'http.route': req.route?.path || req.path,
|
|
23
|
+
'http.host': req.headers.host,
|
|
24
|
+
'http.user_agent': req.headers['user-agent'],
|
|
25
|
+
'net.peer.ip': req.ip || req.socket.remoteAddress,
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
// Store trace context in request
|
|
29
|
+
req.traceId = span.spanContext().traceId;
|
|
30
|
+
req.spanId = span.spanContext().spanId;
|
|
31
|
+
req.startTime = startTime;
|
|
32
|
+
// Log request start
|
|
33
|
+
logger?.info('Incoming HTTP request', {
|
|
34
|
+
method: req.method,
|
|
35
|
+
url: req.url,
|
|
36
|
+
path: req.path,
|
|
37
|
+
query: req.query,
|
|
38
|
+
traceId: req.traceId,
|
|
39
|
+
...(logBody && req.body && {
|
|
40
|
+
body: truncateBody(req.body, maxBodyLogSize)
|
|
41
|
+
}),
|
|
42
|
+
});
|
|
43
|
+
// Increment active requests counter
|
|
44
|
+
metrics?.incrementActiveRequests();
|
|
45
|
+
// Capture response
|
|
46
|
+
const originalSend = res.send;
|
|
47
|
+
let responseBody;
|
|
48
|
+
res.send = function (body) {
|
|
49
|
+
responseBody = body;
|
|
50
|
+
return originalSend.call(this, body);
|
|
51
|
+
};
|
|
52
|
+
res.on('finish', () => {
|
|
53
|
+
const duration = Date.now() - startTime;
|
|
54
|
+
const route = req.route?.path || req.path;
|
|
55
|
+
// Decrement active requests counter
|
|
56
|
+
metrics?.decrementActiveRequests();
|
|
57
|
+
// Update span with response information
|
|
58
|
+
span.setAttributes({
|
|
59
|
+
'http.status_code': res.statusCode,
|
|
60
|
+
'http.response_content_length': res.get('Content-Length') || '0',
|
|
61
|
+
'http.flavor': req.httpVersion,
|
|
62
|
+
'http.response.duration_ms': duration,
|
|
63
|
+
});
|
|
64
|
+
// Record metrics
|
|
65
|
+
metrics?.recordHttpRequest({
|
|
66
|
+
method: req.method,
|
|
67
|
+
route,
|
|
68
|
+
statusCode: res.statusCode,
|
|
69
|
+
duration,
|
|
70
|
+
});
|
|
71
|
+
// Record response size if available
|
|
72
|
+
const contentLength = res.get('Content-Length');
|
|
73
|
+
if (contentLength) {
|
|
74
|
+
metrics?.recordHttpResponseSize(parseInt(contentLength), req.method, route, res.statusCode);
|
|
75
|
+
}
|
|
76
|
+
// Log response
|
|
77
|
+
const logLevel = res.statusCode >= 400 ? 'warn' : 'info';
|
|
78
|
+
logger?.[logLevel]('HTTP request completed', {
|
|
79
|
+
method: req.method,
|
|
80
|
+
url: req.url,
|
|
81
|
+
statusCode: res.statusCode,
|
|
82
|
+
duration,
|
|
83
|
+
traceId: req.traceId,
|
|
84
|
+
...(logBody && responseBody && {
|
|
85
|
+
response: truncateBody(responseBody, maxBodyLogSize)
|
|
86
|
+
}),
|
|
87
|
+
});
|
|
88
|
+
// Set span status based on HTTP status code
|
|
89
|
+
if (res.statusCode >= 400) {
|
|
90
|
+
span.setStatus({
|
|
91
|
+
code: api_1.SpanStatusCode.ERROR,
|
|
92
|
+
message: `HTTP ${res.statusCode}`,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
span.setStatus({ code: api_1.SpanStatusCode.OK });
|
|
97
|
+
}
|
|
98
|
+
span.end();
|
|
99
|
+
});
|
|
100
|
+
// Handle errors
|
|
101
|
+
res.on('error', (error) => {
|
|
102
|
+
logger?.error('HTTP response error', {
|
|
103
|
+
error: error.message,
|
|
104
|
+
stack: error.stack,
|
|
105
|
+
method: req.method,
|
|
106
|
+
url: req.url,
|
|
107
|
+
traceId: req.traceId,
|
|
108
|
+
});
|
|
109
|
+
span.recordException(error);
|
|
110
|
+
span.setStatus({
|
|
111
|
+
code: api_1.SpanStatusCode.ERROR,
|
|
112
|
+
message: error.message,
|
|
113
|
+
});
|
|
114
|
+
span.end();
|
|
115
|
+
});
|
|
116
|
+
// Continue processing
|
|
117
|
+
api_1.context.with(api_1.trace.setSpan(api_1.context.active(), span), () => {
|
|
118
|
+
next();
|
|
119
|
+
});
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
function createErrorMiddleware(logger) {
|
|
123
|
+
return (error, req, res, next) => {
|
|
124
|
+
const span = api_1.trace.getActiveSpan();
|
|
125
|
+
logger?.error('Unhandled error in Express middleware', {
|
|
126
|
+
error: error.message,
|
|
127
|
+
stack: error.stack,
|
|
128
|
+
method: req.method,
|
|
129
|
+
url: req.url,
|
|
130
|
+
traceId: req.traceId,
|
|
131
|
+
spanId: req.spanId,
|
|
132
|
+
});
|
|
133
|
+
if (span) {
|
|
134
|
+
span.recordException(error);
|
|
135
|
+
span.setStatus({
|
|
136
|
+
code: api_1.SpanStatusCode.ERROR,
|
|
137
|
+
message: error.message,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
// Send error response
|
|
141
|
+
res.status(500).json({
|
|
142
|
+
error: 'Internal Server Error',
|
|
143
|
+
message: process.env.NODE_ENV === 'production'
|
|
144
|
+
? 'An unexpected error occurred'
|
|
145
|
+
: error.message,
|
|
146
|
+
traceId: req.traceId,
|
|
147
|
+
});
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
function configureExpressApp(app, config) {
|
|
151
|
+
// Add OpenTelemetry middleware
|
|
152
|
+
app.use(createOpenTelemetryMiddleware(config));
|
|
153
|
+
// Add error handling middleware (should be last)
|
|
154
|
+
app.use(createErrorMiddleware(config.logger));
|
|
155
|
+
}
|
|
156
|
+
function truncateBody(body, maxSize) {
|
|
157
|
+
if (typeof body === 'string') {
|
|
158
|
+
return body.length > maxSize ? body.substring(0, maxSize) + '...' : body;
|
|
159
|
+
}
|
|
160
|
+
if (typeof body === 'object') {
|
|
161
|
+
const str = JSON.stringify(body);
|
|
162
|
+
return str.length > maxSize ? str.substring(0, maxSize) + '...' : body;
|
|
163
|
+
}
|
|
164
|
+
return body;
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=express.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"express.js","sourceRoot":"","sources":["../src/express.ts"],"names":[],"mappings":"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"}
|
package/dist/health.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Application, Router } from 'express';
|
|
2
|
+
import { OpenTelemetryCollector } from './collector';
|
|
3
|
+
import { Logger } from './logger';
|
|
4
|
+
import { HealthStatus } from './types';
|
|
5
|
+
export interface HealthCheckOptions {
|
|
6
|
+
/** Collector instance for checking OpenTelemetry health */
|
|
7
|
+
collector?: OpenTelemetryCollector;
|
|
8
|
+
/** Logger instance */
|
|
9
|
+
logger?: Logger;
|
|
10
|
+
/** Custom health checks */
|
|
11
|
+
checks?: Record<string, () => Promise<boolean>>;
|
|
12
|
+
/** Service name */
|
|
13
|
+
serviceName?: string;
|
|
14
|
+
/** Service version */
|
|
15
|
+
serviceVersion?: string;
|
|
16
|
+
}
|
|
17
|
+
export declare class HealthController {
|
|
18
|
+
private collector?;
|
|
19
|
+
private logger?;
|
|
20
|
+
private checks;
|
|
21
|
+
private serviceName;
|
|
22
|
+
private serviceVersion;
|
|
23
|
+
constructor(options?: HealthCheckOptions);
|
|
24
|
+
getHealthStatus(): Promise<HealthStatus>;
|
|
25
|
+
createHealthRouter(): Router;
|
|
26
|
+
registerHealthRoutes(app: Application | Router): void;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=health.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../src/health.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,WAAW,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,MAAM,WAAW,kBAAkB;IACjC,2DAA2D;IAC3D,SAAS,CAAC,EAAE,sBAAsB,CAAC;IAEnC,sBAAsB;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,2BAA2B;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;IAEhD,mBAAmB;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,sBAAsB;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,SAAS,CAAC,CAAyB;IAC3C,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,MAAM,CAAyC;IACvD,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,cAAc,CAAS;gBAEnB,OAAO,GAAE,kBAAuB;IAQ/B,eAAe,IAAI,OAAO,CAAC,YAAY,CAAC;IAoC9C,kBAAkB,IAAI,MAAM;IA+E5B,oBAAoB,CAAC,GAAG,EAAE,WAAW,GAAG,MAAM,GAAG,IAAI;CAI7D"}
|