@devopsplaybook.io/otel-utils 1.0.18 → 1.1.0-beta.21.15fb757
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 +165 -1
- package/dist/src/ModuleLogger.js +0 -1
- package/dist/src/StandardLogger.d.ts +2 -1
- package/dist/src/StandardLogger.js +7 -45
- package/dist/src/StandardMeter.d.ts +3 -3
- package/dist/src/StandardMeter.js +10 -54
- package/dist/src/StandardTracer.d.ts +2 -0
- package/dist/src/StandardTracer.js +8 -11
- package/dist/src/models/ConfigOTelInterface.d.ts +7 -7
- package/dist/src/utils/createResource.d.ts +1 -0
- package/dist/src/utils/createResource.js +47 -0
- package/package.json +15 -10
- package/src/ModuleLogger.ts +1 -2
- package/src/StandardLogger.ts +13 -22
- package/src/StandardMeter.ts +22 -29
- package/src/StandardTracer.ts +16 -20
- package/src/models/ConfigOTelInterface.ts +7 -7
- package/src/utils/createResource.ts +20 -0
package/README.md
CHANGED
|
@@ -1 +1,165 @@
|
|
|
1
|
-
# otel-utils
|
|
1
|
+
# otel-utils
|
|
2
|
+
|
|
3
|
+
Utility library that simplifies OpenTelemetry integration for Node.js services. Provides standardized tracing, structured logging, and metrics export with minimal boilerplate.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @devopsplaybook.io/otel-utils
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Configuration
|
|
12
|
+
|
|
13
|
+
All classes accept a `ConfigOTelInterface` object:
|
|
14
|
+
|
|
15
|
+
| Field | Type | Default | Description |
|
|
16
|
+
| --------------------------------------------------------- | ---------- | ------- | ------------------------------- |
|
|
17
|
+
| `SERVICE_ID` | `string` | — | Service identifier (required) |
|
|
18
|
+
| `VERSION` | `string` | — | Service version (required) |
|
|
19
|
+
| `OPENTELEMETRY_COLLECTOR_HTTP_TRACES` | `string?` | — | OTLP HTTP endpoint for traces |
|
|
20
|
+
| `OPENTELEMETRY_COLLECTOR_HTTP_METRICS` | `string?` | — | OTLP HTTP endpoint for metrics |
|
|
21
|
+
| `OPENTELEMETRY_COLLECTOR_HTTP_LOGS` | `string?` | — | OTLP HTTP endpoint for logs |
|
|
22
|
+
| `OPENTELEMETRY_COLLECTOR_EXPORT_LOGS_INTERVAL_SECONDS` | `number?` | `60` | Log export interval |
|
|
23
|
+
| `OPENTELEMETRY_COLLECTOR_EXPORT_METRICS_INTERVAL_SECONDS` | `number?` | `60` | Metrics export interval |
|
|
24
|
+
| `OPENTELEMETRY_COLLECTOR_AWS` | `boolean?` | — | AWS-specific feature flag |
|
|
25
|
+
| `OPENTELEMETRY_COLLECT_AUTHORIZATION_HEADER` | `string?` | — | Bearer token for collector auth |
|
|
26
|
+
|
|
27
|
+
When a collector endpoint is not provided, the corresponding signal (traces, logs, or metrics) is initialized with no export — the provider is still available but no data is sent.
|
|
28
|
+
|
|
29
|
+
## Exported Classes
|
|
30
|
+
|
|
31
|
+
### StandardTracer
|
|
32
|
+
|
|
33
|
+
Sets up a global `NodeTracerProvider` with:
|
|
34
|
+
|
|
35
|
+
- AWS X-Ray ID generator (`AWSXRayIdGenerator`)
|
|
36
|
+
- OTLP HTTP trace exporter (optional, when `OPENTELEMETRY_COLLECTOR_HTTP_TRACES` is set)
|
|
37
|
+
- `AsyncHooksContextManager` for automatic context propagation
|
|
38
|
+
- Service resource attributes (name, version, hostname)
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
import { StandardTracer } from "@devopsplaybook.io/otel-utils";
|
|
42
|
+
|
|
43
|
+
const tracer = new StandardTracer(config);
|
|
44
|
+
const span = tracer.startSpan("my-operation");
|
|
45
|
+
// ... do work ...
|
|
46
|
+
span.end();
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**Methods:**
|
|
50
|
+
|
|
51
|
+
- `startSpan(name, parentSpan?)` — Creates a span. When no `parentSpan` is provided, adds `http.request_method=BACKEND` and `http.route` attributes. Span names are sanitized to `[a-zA-Z0-9-_/]`.
|
|
52
|
+
- `static updateHttpHeader(context, headers?)` — Injects W3C trace context into an HTTP headers object for propagation to downstream services.
|
|
53
|
+
|
|
54
|
+
### StandardLogger
|
|
55
|
+
|
|
56
|
+
Initializes a `LoggerProvider` with an OTLP log exporter and a `BatchLogRecordProcessor` (`maxQueueSize: 2048`).
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
import { StandardLogger } from "@devopsplaybook.io/otel-utils";
|
|
60
|
+
|
|
61
|
+
const logger = new StandardLogger();
|
|
62
|
+
logger.initOTel(config);
|
|
63
|
+
|
|
64
|
+
const moduleLog = logger.createModuleLogger("my-module");
|
|
65
|
+
moduleLog.info("Hello world");
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
**Methods:**
|
|
69
|
+
|
|
70
|
+
- `initOTel(config)` — Initializes the logger provider and optional OTLP exporter.
|
|
71
|
+
- `getLogger()` — Returns the underlying OTel `Logger` or `undefined`.
|
|
72
|
+
- `createModuleLogger(moduleName)` — Creates a `ModuleLogger` scoped to a module name.
|
|
73
|
+
|
|
74
|
+
### ModuleLogger
|
|
75
|
+
|
|
76
|
+
Scoped logger that prefixes all output with a module name. Logs to both `console.log` and (when available) the OTel Logger.
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
const log = logger.createModuleLogger("api");
|
|
80
|
+
log.info("request received");
|
|
81
|
+
log.warn("rate limit approaching");
|
|
82
|
+
log.error("connection failed", new Error("timeout"));
|
|
83
|
+
log.info("processing complete", activeSpan); // attach trace context
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**Methods:**
|
|
87
|
+
|
|
88
|
+
- `info(message, context?)` — Log at INFO level.
|
|
89
|
+
- `warn(message, context?)` — Log at WARN level.
|
|
90
|
+
- `error(message, error?, context?)` — Log at ERROR level with optional `Error` and span context. Attaches `exception.type`, `exception.message`, and `exception.stacktrace` attributes.
|
|
91
|
+
|
|
92
|
+
When a `Span` is passed as `context`, the log record includes `span.id` and `trace.id` attributes for trace correlation.
|
|
93
|
+
|
|
94
|
+
### StandardMeter
|
|
95
|
+
|
|
96
|
+
Creates a `MeterProvider` with an optional `PeriodicExportingMetricReader` (`concurrencyLimit: 5`). Provides convenience factories for common metric types.
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
import { StandardMeter } from "@devopsplaybook.io/otel-utils";
|
|
100
|
+
|
|
101
|
+
const meter = new StandardMeter(config);
|
|
102
|
+
|
|
103
|
+
const requestCount = meter.createCounter("requests.total");
|
|
104
|
+
requestCount.add(1);
|
|
105
|
+
|
|
106
|
+
const latency = meter.createHistogram("requests.latency");
|
|
107
|
+
latency.record(42);
|
|
108
|
+
|
|
109
|
+
const activeUsers = meter.createUpDownCounter("users.active");
|
|
110
|
+
activeUsers.add(1);
|
|
111
|
+
|
|
112
|
+
const cpuGauge = meter.createObservableGauge(
|
|
113
|
+
"cpu.usage",
|
|
114
|
+
(result) => result.observe(cpuPercent),
|
|
115
|
+
"Current CPU usage",
|
|
116
|
+
);
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
**Methods:**
|
|
120
|
+
|
|
121
|
+
- `createCounter(key)` — Creates a `Counter` with name `${serviceName}.${key}`.
|
|
122
|
+
- `createUpDownCounter(key)` — Creates an `UpDownCounter`.
|
|
123
|
+
- `createHistogram(key)` — Creates a `Histogram`.
|
|
124
|
+
- `createObservableGauge(key, callback, description?)` — Creates an `ObservableGauge` with a callback. Description is optional.
|
|
125
|
+
|
|
126
|
+
## Internal Utilities
|
|
127
|
+
|
|
128
|
+
### createOTelResource
|
|
129
|
+
|
|
130
|
+
Shared internal utility that creates an `OTelResource` with `service.name`, `service.version`, and `network.local.address` (hostname). The hostname is cached at module load time to minimize system calls.
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
// Used internally by StandardTracer, StandardLogger, and StandardMeter
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Architecture
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
Application
|
|
140
|
+
├── StandardTracer ──► OTLP Trace Exporter ──► Collector / otel-light
|
|
141
|
+
├── StandardLogger ──► OTLP Log Exporter ──► Collector / otel-light
|
|
142
|
+
│ └── ModuleLogger (scoped per module)
|
|
143
|
+
└── StandardMeter ──► OTLP Metric Exporter ──► Collector / otel-light
|
|
144
|
+
└── PeriodicExportingMetricReader
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
All three signals share the same service identity (name + version) and resource attributes via `createOTelResource`. Export is optional per signal — only configured when the corresponding `OPENTELEMETRY_COLLECTOR_HTTP_*` endpoint is set.
|
|
148
|
+
|
|
149
|
+
## Dependencies
|
|
150
|
+
|
|
151
|
+
- `@opentelemetry/api` / `@opentelemetry/api-logs` — OpenTelemetry API interfaces
|
|
152
|
+
- `@opentelemetry/sdk-trace-node` / `@opentelemetry/sdk-trace-base` — Tracing SDK
|
|
153
|
+
- `@opentelemetry/sdk-metrics` — Metrics SDK
|
|
154
|
+
- `@opentelemetry/sdk-logs` — Logging SDK
|
|
155
|
+
- `@opentelemetry/exporter-trace-otlp-http` / `@opentelemetry/exporter-metrics-otlp-http` / `@opentelemetry/exporter-logs-otlp-http` — OTLP HTTP exporters
|
|
156
|
+
- `@opentelemetry/id-generator-aws-xray` — AWS X-Ray trace ID format
|
|
157
|
+
- `@opentelemetry/context-async-hooks` — Async context management
|
|
158
|
+
- `@opentelemetry/core` — W3C trace context propagation
|
|
159
|
+
- `@opentelemetry/resources` / `@opentelemetry/semantic-conventions` — Resource attributes
|
|
160
|
+
|
|
161
|
+
## Build
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
npm run build # tsc → dist/
|
|
165
|
+
```
|
package/dist/src/ModuleLogger.js
CHANGED
|
@@ -21,7 +21,6 @@ class ModuleLogger {
|
|
|
21
21
|
let formattedMessage = message;
|
|
22
22
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
23
23
|
const attributes = { "log.type": "custom" };
|
|
24
|
-
formattedMessage = message;
|
|
25
24
|
if (error) {
|
|
26
25
|
attributes["exception.type"] = error.name;
|
|
27
26
|
attributes["exception.message"] = error.message;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { Logger as OTelLogger } from "@opentelemetry/api-logs";
|
|
2
2
|
import { ConfigOTelInterface } from "./models/ConfigOTelInterface";
|
|
3
3
|
import { ModuleLogger } from "./ModuleLogger";
|
|
4
|
-
|
|
4
|
+
import type { StandardLoggerInterface } from "./models/StandardLoggerInterface";
|
|
5
|
+
export declare class StandardLogger implements StandardLoggerInterface {
|
|
5
6
|
private logger?;
|
|
6
7
|
private serviceVersion?;
|
|
7
8
|
private serviceName?;
|
|
@@ -1,53 +1,20 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
3
|
exports.StandardLogger = void 0;
|
|
37
4
|
const exporter_logs_otlp_http_1 = require("@opentelemetry/exporter-logs-otlp-http");
|
|
38
|
-
const resources_1 = require("@opentelemetry/resources");
|
|
39
5
|
const sdk_logs_1 = require("@opentelemetry/sdk-logs");
|
|
40
|
-
const
|
|
41
|
-
const os = __importStar(require("os"));
|
|
6
|
+
const createResource_1 = require("./utils/createResource");
|
|
42
7
|
const ModuleLogger_1 = require("./ModuleLogger");
|
|
43
8
|
class StandardLogger {
|
|
44
9
|
initOTel(config) {
|
|
10
|
+
var _a;
|
|
45
11
|
this.serviceName = config.SERVICE_ID;
|
|
46
12
|
this.serviceVersion = config.VERSION;
|
|
47
13
|
if (config.OPENTELEMETRY_COLLECTOR_HTTP_LOGS) {
|
|
48
14
|
const exporterHeaders = {};
|
|
49
15
|
if (config.OPENTELEMETRY_COLLECT_AUTHORIZATION_HEADER) {
|
|
50
|
-
exporterHeaders["Authorization"] =
|
|
16
|
+
exporterHeaders["Authorization"] =
|
|
17
|
+
`Bearer ${config.OPENTELEMETRY_COLLECT_AUTHORIZATION_HEADER}`;
|
|
51
18
|
}
|
|
52
19
|
const exporter = new exporter_logs_otlp_http_1.OTLPLogExporter({
|
|
53
20
|
url: config.OPENTELEMETRY_COLLECTOR_HTTP_LOGS,
|
|
@@ -56,16 +23,11 @@ class StandardLogger {
|
|
|
56
23
|
const loggerProvider = new sdk_logs_1.LoggerProvider({
|
|
57
24
|
processors: [
|
|
58
25
|
new sdk_logs_1.BatchLogRecordProcessor(exporter, {
|
|
59
|
-
maxQueueSize:
|
|
60
|
-
scheduledDelayMillis: config.OPENTELEMETRY_COLLECTOR_EXPORT_LOGS_INTERVAL_SECONDS *
|
|
61
|
-
1000,
|
|
26
|
+
maxQueueSize: 2048,
|
|
27
|
+
scheduledDelayMillis: ((_a = config.OPENTELEMETRY_COLLECTOR_EXPORT_LOGS_INTERVAL_SECONDS) !== null && _a !== void 0 ? _a : 60) * 1000,
|
|
62
28
|
}),
|
|
63
29
|
],
|
|
64
|
-
resource: (0,
|
|
65
|
-
[semantic_conventions_1.ATTR_SERVICE_NAME]: `${this.serviceName}`,
|
|
66
|
-
[semantic_conventions_1.ATTR_SERVICE_VERSION]: `${this.serviceVersion}`,
|
|
67
|
-
[semantic_conventions_1.ATTR_NETWORK_LOCAL_ADDRESS]: os.hostname(),
|
|
68
|
-
}),
|
|
30
|
+
resource: (0, createResource_1.createOTelResource)(this.serviceName, this.serviceVersion),
|
|
69
31
|
});
|
|
70
32
|
this.logger = loggerProvider.getLogger(`${this.serviceName}:${this.serviceVersion}`);
|
|
71
33
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Counter, Histogram, ObservableGauge } from "@opentelemetry/api";
|
|
1
|
+
import { Counter, Histogram, ObservableGauge, UpDownCounter } from "@opentelemetry/api";
|
|
2
2
|
import { ConfigOTelInterface } from "./models/ConfigOTelInterface";
|
|
3
3
|
export declare class StandardMeter {
|
|
4
4
|
private meter;
|
|
@@ -6,7 +6,7 @@ export declare class StandardMeter {
|
|
|
6
6
|
private serviceName;
|
|
7
7
|
constructor(config: ConfigOTelInterface);
|
|
8
8
|
createCounter(key: string): Counter;
|
|
9
|
-
createUpDownCounter(key: string):
|
|
9
|
+
createUpDownCounter(key: string): UpDownCounter;
|
|
10
10
|
createHistogram(key: string): Histogram;
|
|
11
|
-
createObservableGauge(key: string, callback: (observableResult: any) => void, description?:
|
|
11
|
+
createObservableGauge(key: string, callback: (observableResult: any) => void, description?: string): ObservableGauge;
|
|
12
12
|
}
|
|
@@ -1,46 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
3
|
exports.StandardMeter = void 0;
|
|
37
4
|
const exporter_metrics_otlp_http_1 = require("@opentelemetry/exporter-metrics-otlp-http");
|
|
38
|
-
const
|
|
5
|
+
const createResource_1 = require("./utils/createResource");
|
|
39
6
|
const sdk_metrics_1 = require("@opentelemetry/sdk-metrics");
|
|
40
|
-
const semantic_conventions_1 = require("@opentelemetry/semantic-conventions");
|
|
41
|
-
const os = __importStar(require("os"));
|
|
42
7
|
class StandardMeter {
|
|
43
8
|
constructor(config) {
|
|
9
|
+
var _a;
|
|
44
10
|
this.serviceName = config.SERVICE_ID;
|
|
45
11
|
this.serviceVersion = config.VERSION;
|
|
46
12
|
let meterProvider;
|
|
@@ -48,34 +14,26 @@ class StandardMeter {
|
|
|
48
14
|
const collectorOptions = {
|
|
49
15
|
url: config.OPENTELEMETRY_COLLECTOR_HTTP_METRICS,
|
|
50
16
|
headers: {},
|
|
51
|
-
concurrencyLimit:
|
|
17
|
+
concurrencyLimit: 5,
|
|
52
18
|
};
|
|
53
19
|
if (config.OPENTELEMETRY_COLLECT_AUTHORIZATION_HEADER) {
|
|
54
|
-
collectorOptions.headers["Authorization"] =
|
|
20
|
+
collectorOptions.headers["Authorization"] =
|
|
21
|
+
`Bearer ${config.OPENTELEMETRY_COLLECT_AUTHORIZATION_HEADER}`;
|
|
55
22
|
}
|
|
56
23
|
const metricExporter = new exporter_metrics_otlp_http_1.OTLPMetricExporter(collectorOptions);
|
|
57
24
|
meterProvider = new sdk_metrics_1.MeterProvider({
|
|
58
|
-
resource: (0,
|
|
59
|
-
[semantic_conventions_1.ATTR_SERVICE_NAME]: `${this.serviceName}`,
|
|
60
|
-
[semantic_conventions_1.ATTR_SERVICE_VERSION]: `${this.serviceVersion}`,
|
|
61
|
-
[semantic_conventions_1.ATTR_NETWORK_LOCAL_ADDRESS]: os.hostname(),
|
|
62
|
-
}),
|
|
25
|
+
resource: (0, createResource_1.createOTelResource)(this.serviceName, this.serviceVersion),
|
|
63
26
|
readers: [
|
|
64
27
|
new sdk_metrics_1.PeriodicExportingMetricReader({
|
|
65
28
|
exporter: metricExporter,
|
|
66
|
-
exportIntervalMillis: config.OPENTELEMETRY_COLLECTOR_EXPORT_METRICS_INTERVAL_SECONDS *
|
|
67
|
-
1000,
|
|
29
|
+
exportIntervalMillis: ((_a = config.OPENTELEMETRY_COLLECTOR_EXPORT_METRICS_INTERVAL_SECONDS) !== null && _a !== void 0 ? _a : 60) * 1000,
|
|
68
30
|
}),
|
|
69
31
|
],
|
|
70
32
|
});
|
|
71
33
|
}
|
|
72
34
|
else {
|
|
73
35
|
meterProvider = new sdk_metrics_1.MeterProvider({
|
|
74
|
-
resource: (0,
|
|
75
|
-
[semantic_conventions_1.ATTR_SERVICE_NAME]: `${this.serviceName}`,
|
|
76
|
-
[semantic_conventions_1.ATTR_SERVICE_VERSION]: `${this.serviceVersion}`,
|
|
77
|
-
[semantic_conventions_1.ATTR_NETWORK_LOCAL_ADDRESS]: os.hostname(),
|
|
78
|
-
}),
|
|
36
|
+
resource: (0, createResource_1.createOTelResource)(this.serviceName, this.serviceVersion),
|
|
79
37
|
});
|
|
80
38
|
}
|
|
81
39
|
this.meter = meterProvider.getMeter(`${this.serviceName}:${this.serviceVersion}`);
|
|
@@ -91,10 +49,8 @@ class StandardMeter {
|
|
|
91
49
|
}
|
|
92
50
|
createObservableGauge(key,
|
|
93
51
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
94
|
-
callback,
|
|
95
|
-
|
|
96
|
-
description = null) {
|
|
97
|
-
const observableGauge = this.meter.createObservableGauge(key, description);
|
|
52
|
+
callback, description) {
|
|
53
|
+
const observableGauge = this.meter.createObservableGauge(key, description ? { description } : undefined);
|
|
98
54
|
observableGauge.addCallback(callback);
|
|
99
55
|
return observableGauge;
|
|
100
56
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { Span } from "@opentelemetry/sdk-trace-base";
|
|
2
2
|
import { ConfigOTelInterface } from "./models/ConfigOTelInterface";
|
|
3
3
|
export declare class StandardTracer {
|
|
4
|
+
private static readonly SPAN_NAME_SANITIZE_RE;
|
|
5
|
+
private static readonly PROPAGATOR;
|
|
4
6
|
private tracer;
|
|
5
7
|
private serviceVersion;
|
|
6
8
|
private serviceName;
|
|
@@ -39,11 +39,10 @@ const context_async_hooks_1 = require("@opentelemetry/context-async-hooks");
|
|
|
39
39
|
const core_1 = require("@opentelemetry/core");
|
|
40
40
|
const exporter_trace_otlp_http_1 = require("@opentelemetry/exporter-trace-otlp-http");
|
|
41
41
|
const id_generator_aws_xray_1 = require("@opentelemetry/id-generator-aws-xray");
|
|
42
|
-
const resources_1 = require("@opentelemetry/resources");
|
|
43
42
|
const sdk_trace_base_1 = require("@opentelemetry/sdk-trace-base");
|
|
44
43
|
const sdk_trace_node_1 = require("@opentelemetry/sdk-trace-node");
|
|
45
44
|
const semantic_conventions_1 = require("@opentelemetry/semantic-conventions");
|
|
46
|
-
const
|
|
45
|
+
const createResource_1 = require("./utils/createResource");
|
|
47
46
|
class StandardTracer {
|
|
48
47
|
constructor(config) {
|
|
49
48
|
this.serviceName = config.SERVICE_ID;
|
|
@@ -52,7 +51,8 @@ class StandardTracer {
|
|
|
52
51
|
if (config.OPENTELEMETRY_COLLECTOR_HTTP_TRACES) {
|
|
53
52
|
const exporterHeaders = {};
|
|
54
53
|
if (config.OPENTELEMETRY_COLLECT_AUTHORIZATION_HEADER) {
|
|
55
|
-
exporterHeaders["Authorization"] =
|
|
54
|
+
exporterHeaders["Authorization"] =
|
|
55
|
+
`Bearer ${config.OPENTELEMETRY_COLLECT_AUTHORIZATION_HEADER}`;
|
|
56
56
|
}
|
|
57
57
|
const exporter = new exporter_trace_otlp_http_1.OTLPTraceExporter({
|
|
58
58
|
url: config.OPENTELEMETRY_COLLECTOR_HTTP_TRACES,
|
|
@@ -62,11 +62,7 @@ class StandardTracer {
|
|
|
62
62
|
}
|
|
63
63
|
const traceProvider = new sdk_trace_node_1.NodeTracerProvider({
|
|
64
64
|
idGenerator: new id_generator_aws_xray_1.AWSXRayIdGenerator(),
|
|
65
|
-
resource: (0,
|
|
66
|
-
[semantic_conventions_1.ATTR_SERVICE_NAME]: `${this.serviceName}`,
|
|
67
|
-
[semantic_conventions_1.ATTR_SERVICE_VERSION]: `${this.serviceVersion}`,
|
|
68
|
-
[semantic_conventions_1.ATTR_NETWORK_LOCAL_ADDRESS]: os.hostname(),
|
|
69
|
-
}),
|
|
65
|
+
resource: (0, createResource_1.createOTelResource)(this.serviceName, this.serviceVersion),
|
|
70
66
|
spanProcessors,
|
|
71
67
|
});
|
|
72
68
|
traceProvider.register();
|
|
@@ -76,7 +72,7 @@ class StandardTracer {
|
|
|
76
72
|
this.tracer = api_1.default.trace.getTracer(`${this.serviceName}:${this.serviceVersion}`);
|
|
77
73
|
}
|
|
78
74
|
startSpan(name, parentSpan) {
|
|
79
|
-
const sanitizedName = String(name).replace(
|
|
75
|
+
const sanitizedName = String(name).replace(StandardTracer.SPAN_NAME_SANITIZE_RE, "_");
|
|
80
76
|
if (parentSpan) {
|
|
81
77
|
return this.tracer.startSpan(sanitizedName, undefined, api_1.default.trace.setSpan(api_1.default.context.active(), parentSpan));
|
|
82
78
|
}
|
|
@@ -90,11 +86,12 @@ class StandardTracer {
|
|
|
90
86
|
if (!headers) {
|
|
91
87
|
headers = {};
|
|
92
88
|
}
|
|
93
|
-
|
|
94
|
-
propagator.inject(api_1.trace.setSpanContext(api_1.ROOT_CONTEXT, context.spanContext()),
|
|
89
|
+
StandardTracer.PROPAGATOR.inject(api_1.trace.setSpanContext(api_1.ROOT_CONTEXT, context.spanContext()),
|
|
95
90
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
96
91
|
headers, api_1.defaultTextMapSetter);
|
|
97
92
|
return headers;
|
|
98
93
|
}
|
|
99
94
|
}
|
|
100
95
|
exports.StandardTracer = StandardTracer;
|
|
96
|
+
StandardTracer.SPAN_NAME_SANITIZE_RE = /[^a-zA-Z0-9-_/]/g;
|
|
97
|
+
StandardTracer.PROPAGATOR = new core_1.W3CTraceContextPropagator();
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
export interface ConfigOTelInterface {
|
|
2
2
|
SERVICE_ID: string;
|
|
3
3
|
VERSION: string;
|
|
4
|
-
OPENTELEMETRY_COLLECTOR_HTTP_TRACES
|
|
5
|
-
OPENTELEMETRY_COLLECTOR_HTTP_METRICS
|
|
6
|
-
OPENTELEMETRY_COLLECTOR_HTTP_LOGS
|
|
7
|
-
OPENTELEMETRY_COLLECTOR_EXPORT_LOGS_INTERVAL_SECONDS
|
|
8
|
-
OPENTELEMETRY_COLLECTOR_EXPORT_METRICS_INTERVAL_SECONDS
|
|
9
|
-
OPENTELEMETRY_COLLECTOR_AWS
|
|
10
|
-
OPENTELEMETRY_COLLECT_AUTHORIZATION_HEADER
|
|
4
|
+
OPENTELEMETRY_COLLECTOR_HTTP_TRACES?: string;
|
|
5
|
+
OPENTELEMETRY_COLLECTOR_HTTP_METRICS?: string;
|
|
6
|
+
OPENTELEMETRY_COLLECTOR_HTTP_LOGS?: string;
|
|
7
|
+
OPENTELEMETRY_COLLECTOR_EXPORT_LOGS_INTERVAL_SECONDS?: number;
|
|
8
|
+
OPENTELEMETRY_COLLECTOR_EXPORT_METRICS_INTERVAL_SECONDS?: number;
|
|
9
|
+
OPENTELEMETRY_COLLECTOR_AWS?: boolean;
|
|
10
|
+
OPENTELEMETRY_COLLECT_AUTHORIZATION_HEADER?: string;
|
|
11
11
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function createOTelResource(serviceName: string, serviceVersion: string): import("@opentelemetry/resources").Resource;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.createOTelResource = createOTelResource;
|
|
37
|
+
const resources_1 = require("@opentelemetry/resources");
|
|
38
|
+
const semantic_conventions_1 = require("@opentelemetry/semantic-conventions");
|
|
39
|
+
const os = __importStar(require("os"));
|
|
40
|
+
const CACHED_HOSTNAME = os.hostname();
|
|
41
|
+
function createOTelResource(serviceName, serviceVersion) {
|
|
42
|
+
return (0, resources_1.resourceFromAttributes)({
|
|
43
|
+
[semantic_conventions_1.ATTR_SERVICE_NAME]: serviceName,
|
|
44
|
+
[semantic_conventions_1.ATTR_SERVICE_VERSION]: serviceVersion,
|
|
45
|
+
[semantic_conventions_1.ATTR_NETWORK_LOCAL_ADDRESS]: CACHED_HOSTNAME,
|
|
46
|
+
});
|
|
47
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@devopsplaybook.io/otel-utils",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.1.0-beta.21.15fb757",
|
|
4
4
|
"description": "Utility to simplify integration with Open Telemetry",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Open",
|
|
@@ -20,24 +20,29 @@
|
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"@opentelemetry/api": "^1.9.1",
|
|
23
|
-
"@opentelemetry/api-logs": "^0.
|
|
24
|
-
"@opentelemetry/auto-instrumentations-node": "^0.
|
|
25
|
-
"@opentelemetry/
|
|
26
|
-
"@opentelemetry/
|
|
23
|
+
"@opentelemetry/api-logs": "^0.218.0",
|
|
24
|
+
"@opentelemetry/auto-instrumentations-node": "^0.76.0",
|
|
25
|
+
"@opentelemetry/context-async-hooks": "^2.7.1",
|
|
26
|
+
"@opentelemetry/core": "^2.7.1",
|
|
27
|
+
"@opentelemetry/exporter-logs-otlp-http": "^0.218.0",
|
|
28
|
+
"@opentelemetry/exporter-metrics-otlp-http": "^0.218.0",
|
|
29
|
+
"@opentelemetry/exporter-trace-otlp-http": "^0.218.0",
|
|
27
30
|
"@opentelemetry/id-generator-aws-xray": "^2.1.0",
|
|
28
31
|
"@opentelemetry/resources": "^2.7.1",
|
|
29
|
-
"@opentelemetry/sdk-logs": "^0.
|
|
30
|
-
"@opentelemetry/sdk-
|
|
32
|
+
"@opentelemetry/sdk-logs": "^0.218.0",
|
|
33
|
+
"@opentelemetry/sdk-metrics": "^2.7.1",
|
|
34
|
+
"@opentelemetry/sdk-node": "^0.218.0",
|
|
31
35
|
"@opentelemetry/sdk-trace-base": "^2.7.1",
|
|
36
|
+
"@opentelemetry/sdk-trace-node": "^2.7.1",
|
|
32
37
|
"@opentelemetry/sdk-trace-web": "^2.7.1",
|
|
33
|
-
"@opentelemetry/semantic-conventions": "^1.
|
|
38
|
+
"@opentelemetry/semantic-conventions": "^1.41.1"
|
|
34
39
|
},
|
|
35
40
|
"devDependencies": {
|
|
36
41
|
"@eslint/js": "^10.0.1",
|
|
37
|
-
"@types/node": "^25.
|
|
42
|
+
"@types/node": "^25.9.1",
|
|
38
43
|
"@types/sqlite3": "^5.1.0",
|
|
39
44
|
"ts-node": "^10.9.2",
|
|
40
|
-
"typescript-eslint": "^8.59.
|
|
45
|
+
"typescript-eslint": "^8.59.4",
|
|
41
46
|
"typescript": "^6.0.3"
|
|
42
47
|
},
|
|
43
48
|
"publishConfig": {
|
package/src/ModuleLogger.ts
CHANGED
|
@@ -28,14 +28,13 @@ export class ModuleLogger {
|
|
|
28
28
|
message: string,
|
|
29
29
|
severityNumber = SeverityNumber.INFO,
|
|
30
30
|
error?: Error | null,
|
|
31
|
-
context?: Span
|
|
31
|
+
context?: Span,
|
|
32
32
|
): void {
|
|
33
33
|
let formattedMessage = message;
|
|
34
34
|
|
|
35
35
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
36
36
|
const attributes: Record<string, any> = { "log.type": "custom" };
|
|
37
37
|
|
|
38
|
-
formattedMessage = message;
|
|
39
38
|
if (error) {
|
|
40
39
|
attributes["exception.type"] = error.name;
|
|
41
40
|
attributes["exception.message"] = error.message;
|
package/src/StandardLogger.ts
CHANGED
|
@@ -1,21 +1,17 @@
|
|
|
1
|
-
import type { Logger
|
|
1
|
+
import type { Logger as OTelLogger } from "@opentelemetry/api-logs";
|
|
2
2
|
import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-http";
|
|
3
|
-
import { resourceFromAttributes } from "@opentelemetry/resources";
|
|
4
3
|
import {
|
|
5
4
|
BatchLogRecordProcessor,
|
|
6
5
|
LoggerProvider,
|
|
7
6
|
} from "@opentelemetry/sdk-logs";
|
|
8
|
-
import {
|
|
9
|
-
ATTR_NETWORK_LOCAL_ADDRESS,
|
|
10
|
-
ATTR_SERVICE_NAME,
|
|
11
|
-
ATTR_SERVICE_VERSION,
|
|
12
|
-
} from "@opentelemetry/semantic-conventions";
|
|
13
|
-
import * as os from "os";
|
|
14
7
|
import { ConfigOTelInterface } from "./models/ConfigOTelInterface";
|
|
8
|
+
import { createOTelResource } from "./utils/createResource";
|
|
15
9
|
import { ModuleLogger } from "./ModuleLogger";
|
|
16
10
|
|
|
17
|
-
|
|
18
|
-
|
|
11
|
+
import type { StandardLoggerInterface } from "./models/StandardLoggerInterface";
|
|
12
|
+
|
|
13
|
+
export class StandardLogger implements StandardLoggerInterface {
|
|
14
|
+
private logger?: OTelLogger;
|
|
19
15
|
private serviceVersion?: string;
|
|
20
16
|
private serviceName?: string;
|
|
21
17
|
|
|
@@ -26,9 +22,8 @@ export class StandardLogger {
|
|
|
26
22
|
if (config.OPENTELEMETRY_COLLECTOR_HTTP_LOGS) {
|
|
27
23
|
const exporterHeaders: Record<string, string> = {};
|
|
28
24
|
if (config.OPENTELEMETRY_COLLECT_AUTHORIZATION_HEADER) {
|
|
29
|
-
exporterHeaders[
|
|
30
|
-
|
|
31
|
-
] = `Bearer ${config.OPENTELEMETRY_COLLECT_AUTHORIZATION_HEADER}`;
|
|
25
|
+
exporterHeaders["Authorization"] =
|
|
26
|
+
`Bearer ${config.OPENTELEMETRY_COLLECT_AUTHORIZATION_HEADER}`;
|
|
32
27
|
}
|
|
33
28
|
const exporter = new OTLPLogExporter({
|
|
34
29
|
url: config.OPENTELEMETRY_COLLECTOR_HTTP_LOGS,
|
|
@@ -38,21 +33,17 @@ export class StandardLogger {
|
|
|
38
33
|
const loggerProvider = new LoggerProvider({
|
|
39
34
|
processors: [
|
|
40
35
|
new BatchLogRecordProcessor(exporter, {
|
|
41
|
-
maxQueueSize:
|
|
36
|
+
maxQueueSize: 2048,
|
|
42
37
|
scheduledDelayMillis:
|
|
43
|
-
config.OPENTELEMETRY_COLLECTOR_EXPORT_LOGS_INTERVAL_SECONDS
|
|
44
|
-
|
|
38
|
+
(config.OPENTELEMETRY_COLLECTOR_EXPORT_LOGS_INTERVAL_SECONDS ??
|
|
39
|
+
60) * 1000,
|
|
45
40
|
}),
|
|
46
41
|
],
|
|
47
|
-
resource:
|
|
48
|
-
[ATTR_SERVICE_NAME]: `${this.serviceName}`,
|
|
49
|
-
[ATTR_SERVICE_VERSION]: `${this.serviceVersion}`,
|
|
50
|
-
[ATTR_NETWORK_LOCAL_ADDRESS]: os.hostname(),
|
|
51
|
-
}),
|
|
42
|
+
resource: createOTelResource(this.serviceName, this.serviceVersion),
|
|
52
43
|
});
|
|
53
44
|
|
|
54
45
|
this.logger = loggerProvider.getLogger(
|
|
55
|
-
`${this.serviceName}:${this.serviceVersion}
|
|
46
|
+
`${this.serviceName}:${this.serviceVersion}`,
|
|
56
47
|
);
|
|
57
48
|
}
|
|
58
49
|
}
|
package/src/StandardMeter.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
Counter,
|
|
3
|
+
Histogram,
|
|
4
|
+
Meter,
|
|
5
|
+
ObservableGauge,
|
|
6
|
+
UpDownCounter,
|
|
7
|
+
} from "@opentelemetry/api";
|
|
2
8
|
import { OTLPMetricExporter } from "@opentelemetry/exporter-metrics-otlp-http";
|
|
3
|
-
import {
|
|
9
|
+
import { createOTelResource } from "./utils/createResource";
|
|
4
10
|
import {
|
|
5
11
|
MeterProvider,
|
|
6
12
|
PeriodicExportingMetricReader,
|
|
7
13
|
} from "@opentelemetry/sdk-metrics";
|
|
8
|
-
import {
|
|
9
|
-
ATTR_NETWORK_LOCAL_ADDRESS,
|
|
10
|
-
ATTR_SERVICE_NAME,
|
|
11
|
-
ATTR_SERVICE_VERSION,
|
|
12
|
-
} from "@opentelemetry/semantic-conventions";
|
|
13
|
-
import * as os from "os";
|
|
14
14
|
import { ConfigOTelInterface } from "./models/ConfigOTelInterface";
|
|
15
15
|
|
|
16
16
|
export class StandardMeter {
|
|
@@ -26,40 +26,31 @@ export class StandardMeter {
|
|
|
26
26
|
const collectorOptions = {
|
|
27
27
|
url: config.OPENTELEMETRY_COLLECTOR_HTTP_METRICS,
|
|
28
28
|
headers: {} as Record<string, string>,
|
|
29
|
-
concurrencyLimit:
|
|
29
|
+
concurrencyLimit: 5,
|
|
30
30
|
};
|
|
31
31
|
if (config.OPENTELEMETRY_COLLECT_AUTHORIZATION_HEADER) {
|
|
32
|
-
collectorOptions.headers[
|
|
33
|
-
|
|
34
|
-
] = `Bearer ${config.OPENTELEMETRY_COLLECT_AUTHORIZATION_HEADER}`;
|
|
32
|
+
collectorOptions.headers["Authorization"] =
|
|
33
|
+
`Bearer ${config.OPENTELEMETRY_COLLECT_AUTHORIZATION_HEADER}`;
|
|
35
34
|
}
|
|
36
35
|
const metricExporter = new OTLPMetricExporter(collectorOptions);
|
|
37
36
|
meterProvider = new MeterProvider({
|
|
38
|
-
resource:
|
|
39
|
-
[ATTR_SERVICE_NAME]: `${this.serviceName}`,
|
|
40
|
-
[ATTR_SERVICE_VERSION]: `${this.serviceVersion}`,
|
|
41
|
-
[ATTR_NETWORK_LOCAL_ADDRESS]: os.hostname(),
|
|
42
|
-
}),
|
|
37
|
+
resource: createOTelResource(this.serviceName, this.serviceVersion),
|
|
43
38
|
readers: [
|
|
44
39
|
new PeriodicExportingMetricReader({
|
|
45
40
|
exporter: metricExporter,
|
|
46
41
|
exportIntervalMillis:
|
|
47
|
-
config.OPENTELEMETRY_COLLECTOR_EXPORT_METRICS_INTERVAL_SECONDS
|
|
48
|
-
|
|
42
|
+
(config.OPENTELEMETRY_COLLECTOR_EXPORT_METRICS_INTERVAL_SECONDS ??
|
|
43
|
+
60) * 1000,
|
|
49
44
|
}),
|
|
50
45
|
],
|
|
51
46
|
});
|
|
52
47
|
} else {
|
|
53
48
|
meterProvider = new MeterProvider({
|
|
54
|
-
resource:
|
|
55
|
-
[ATTR_SERVICE_NAME]: `${this.serviceName}`,
|
|
56
|
-
[ATTR_SERVICE_VERSION]: `${this.serviceVersion}`,
|
|
57
|
-
[ATTR_NETWORK_LOCAL_ADDRESS]: os.hostname(),
|
|
58
|
-
}),
|
|
49
|
+
resource: createOTelResource(this.serviceName, this.serviceVersion),
|
|
59
50
|
});
|
|
60
51
|
}
|
|
61
52
|
this.meter = meterProvider.getMeter(
|
|
62
|
-
`${this.serviceName}:${this.serviceVersion}
|
|
53
|
+
`${this.serviceName}:${this.serviceVersion}`,
|
|
63
54
|
);
|
|
64
55
|
}
|
|
65
56
|
|
|
@@ -67,7 +58,7 @@ export class StandardMeter {
|
|
|
67
58
|
return this.meter.createCounter(`${this.serviceName}.${key}`);
|
|
68
59
|
}
|
|
69
60
|
|
|
70
|
-
public createUpDownCounter(key: string):
|
|
61
|
+
public createUpDownCounter(key: string): UpDownCounter {
|
|
71
62
|
return this.meter.createUpDownCounter(`${this.serviceName}.${key}`);
|
|
72
63
|
}
|
|
73
64
|
|
|
@@ -79,10 +70,12 @@ export class StandardMeter {
|
|
|
79
70
|
key: string,
|
|
80
71
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
81
72
|
callback: (observableResult: any) => void,
|
|
82
|
-
|
|
83
|
-
description: any = null
|
|
73
|
+
description?: string,
|
|
84
74
|
): ObservableGauge {
|
|
85
|
-
const observableGauge = this.meter.createObservableGauge(
|
|
75
|
+
const observableGauge = this.meter.createObservableGauge(
|
|
76
|
+
key,
|
|
77
|
+
description ? { description } : undefined,
|
|
78
|
+
);
|
|
86
79
|
observableGauge.addCallback(callback);
|
|
87
80
|
return observableGauge;
|
|
88
81
|
}
|
package/src/StandardTracer.ts
CHANGED
|
@@ -8,20 +8,19 @@ import { AsyncHooksContextManager } from "@opentelemetry/context-async-hooks";
|
|
|
8
8
|
import { W3CTraceContextPropagator } from "@opentelemetry/core";
|
|
9
9
|
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
|
|
10
10
|
import { AWSXRayIdGenerator } from "@opentelemetry/id-generator-aws-xray";
|
|
11
|
-
import { resourceFromAttributes } from "@opentelemetry/resources";
|
|
12
11
|
import { BatchSpanProcessor, Span } from "@opentelemetry/sdk-trace-base";
|
|
13
12
|
import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
|
|
14
13
|
import {
|
|
15
14
|
ATTR_HTTP_REQUEST_METHOD,
|
|
16
15
|
ATTR_HTTP_ROUTE,
|
|
17
|
-
ATTR_NETWORK_LOCAL_ADDRESS,
|
|
18
|
-
ATTR_SERVICE_NAME,
|
|
19
|
-
ATTR_SERVICE_VERSION,
|
|
20
16
|
} from "@opentelemetry/semantic-conventions";
|
|
21
|
-
import * as os from "os";
|
|
22
17
|
import { ConfigOTelInterface } from "./models/ConfigOTelInterface";
|
|
18
|
+
import { createOTelResource } from "./utils/createResource";
|
|
23
19
|
|
|
24
20
|
export class StandardTracer {
|
|
21
|
+
private static readonly SPAN_NAME_SANITIZE_RE = /[^a-zA-Z0-9-_/]/g;
|
|
22
|
+
private static readonly PROPAGATOR = new W3CTraceContextPropagator();
|
|
23
|
+
|
|
25
24
|
private tracer: Tracer;
|
|
26
25
|
private serviceVersion: string;
|
|
27
26
|
private serviceName: string;
|
|
@@ -34,9 +33,8 @@ export class StandardTracer {
|
|
|
34
33
|
if (config.OPENTELEMETRY_COLLECTOR_HTTP_TRACES) {
|
|
35
34
|
const exporterHeaders: Record<string, string> = {};
|
|
36
35
|
if (config.OPENTELEMETRY_COLLECT_AUTHORIZATION_HEADER) {
|
|
37
|
-
exporterHeaders[
|
|
38
|
-
|
|
39
|
-
] = `Bearer ${config.OPENTELEMETRY_COLLECT_AUTHORIZATION_HEADER}`;
|
|
36
|
+
exporterHeaders["Authorization"] =
|
|
37
|
+
`Bearer ${config.OPENTELEMETRY_COLLECT_AUTHORIZATION_HEADER}`;
|
|
40
38
|
}
|
|
41
39
|
const exporter = new OTLPTraceExporter({
|
|
42
40
|
url: config.OPENTELEMETRY_COLLECTOR_HTTP_TRACES,
|
|
@@ -46,11 +44,7 @@ export class StandardTracer {
|
|
|
46
44
|
}
|
|
47
45
|
const traceProvider = new NodeTracerProvider({
|
|
48
46
|
idGenerator: new AWSXRayIdGenerator(),
|
|
49
|
-
resource:
|
|
50
|
-
[ATTR_SERVICE_NAME]: `${this.serviceName}`,
|
|
51
|
-
[ATTR_SERVICE_VERSION]: `${this.serviceVersion}`,
|
|
52
|
-
[ATTR_NETWORK_LOCAL_ADDRESS]: os.hostname(),
|
|
53
|
-
}),
|
|
47
|
+
resource: createOTelResource(this.serviceName, this.serviceVersion),
|
|
54
48
|
spanProcessors,
|
|
55
49
|
});
|
|
56
50
|
traceProvider.register();
|
|
@@ -58,24 +52,27 @@ export class StandardTracer {
|
|
|
58
52
|
contextManager.enable();
|
|
59
53
|
opentelemetry.context.setGlobalContextManager(contextManager);
|
|
60
54
|
this.tracer = opentelemetry.trace.getTracer(
|
|
61
|
-
`${this.serviceName}:${this.serviceVersion}
|
|
55
|
+
`${this.serviceName}:${this.serviceVersion}`,
|
|
62
56
|
);
|
|
63
57
|
}
|
|
64
58
|
|
|
65
59
|
public startSpan(name: string, parentSpan?: Span): Span {
|
|
66
|
-
const sanitizedName = String(name).replace(
|
|
60
|
+
const sanitizedName = String(name).replace(
|
|
61
|
+
StandardTracer.SPAN_NAME_SANITIZE_RE,
|
|
62
|
+
"_",
|
|
63
|
+
);
|
|
67
64
|
if (parentSpan) {
|
|
68
65
|
return this.tracer.startSpan(
|
|
69
66
|
sanitizedName,
|
|
70
67
|
undefined,
|
|
71
|
-
opentelemetry.trace.setSpan(opentelemetry.context.active(), parentSpan)
|
|
68
|
+
opentelemetry.trace.setSpan(opentelemetry.context.active(), parentSpan),
|
|
72
69
|
) as Span;
|
|
73
70
|
}
|
|
74
71
|
const span = this.tracer.startSpan(sanitizedName) as Span;
|
|
75
72
|
span.setAttribute(ATTR_HTTP_REQUEST_METHOD, `BACKEND`);
|
|
76
73
|
span.setAttribute(
|
|
77
74
|
ATTR_HTTP_ROUTE,
|
|
78
|
-
`${this.serviceName}-${this.serviceVersion}-${sanitizedName}
|
|
75
|
+
`${this.serviceName}-${this.serviceVersion}-${sanitizedName}`,
|
|
79
76
|
);
|
|
80
77
|
return span;
|
|
81
78
|
}
|
|
@@ -85,12 +82,11 @@ export class StandardTracer {
|
|
|
85
82
|
if (!headers) {
|
|
86
83
|
headers = {};
|
|
87
84
|
}
|
|
88
|
-
|
|
89
|
-
propagator.inject(
|
|
85
|
+
StandardTracer.PROPAGATOR.inject(
|
|
90
86
|
trace.setSpanContext(ROOT_CONTEXT, context.spanContext()),
|
|
91
87
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
92
88
|
headers as any,
|
|
93
|
-
defaultTextMapSetter
|
|
89
|
+
defaultTextMapSetter,
|
|
94
90
|
);
|
|
95
91
|
return headers;
|
|
96
92
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
export interface ConfigOTelInterface {
|
|
2
2
|
SERVICE_ID: string;
|
|
3
3
|
VERSION: string;
|
|
4
|
-
OPENTELEMETRY_COLLECTOR_HTTP_TRACES
|
|
5
|
-
OPENTELEMETRY_COLLECTOR_HTTP_METRICS
|
|
6
|
-
OPENTELEMETRY_COLLECTOR_HTTP_LOGS
|
|
7
|
-
OPENTELEMETRY_COLLECTOR_EXPORT_LOGS_INTERVAL_SECONDS
|
|
8
|
-
OPENTELEMETRY_COLLECTOR_EXPORT_METRICS_INTERVAL_SECONDS
|
|
9
|
-
OPENTELEMETRY_COLLECTOR_AWS
|
|
10
|
-
OPENTELEMETRY_COLLECT_AUTHORIZATION_HEADER
|
|
4
|
+
OPENTELEMETRY_COLLECTOR_HTTP_TRACES?: string;
|
|
5
|
+
OPENTELEMETRY_COLLECTOR_HTTP_METRICS?: string;
|
|
6
|
+
OPENTELEMETRY_COLLECTOR_HTTP_LOGS?: string;
|
|
7
|
+
OPENTELEMETRY_COLLECTOR_EXPORT_LOGS_INTERVAL_SECONDS?: number;
|
|
8
|
+
OPENTELEMETRY_COLLECTOR_EXPORT_METRICS_INTERVAL_SECONDS?: number;
|
|
9
|
+
OPENTELEMETRY_COLLECTOR_AWS?: boolean;
|
|
10
|
+
OPENTELEMETRY_COLLECT_AUTHORIZATION_HEADER?: string;
|
|
11
11
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { resourceFromAttributes } from "@opentelemetry/resources";
|
|
2
|
+
import {
|
|
3
|
+
ATTR_NETWORK_LOCAL_ADDRESS,
|
|
4
|
+
ATTR_SERVICE_NAME,
|
|
5
|
+
ATTR_SERVICE_VERSION,
|
|
6
|
+
} from "@opentelemetry/semantic-conventions";
|
|
7
|
+
import * as os from "os";
|
|
8
|
+
|
|
9
|
+
const CACHED_HOSTNAME = os.hostname();
|
|
10
|
+
|
|
11
|
+
export function createOTelResource(
|
|
12
|
+
serviceName: string,
|
|
13
|
+
serviceVersion: string,
|
|
14
|
+
) {
|
|
15
|
+
return resourceFromAttributes({
|
|
16
|
+
[ATTR_SERVICE_NAME]: serviceName,
|
|
17
|
+
[ATTR_SERVICE_VERSION]: serviceVersion,
|
|
18
|
+
[ATTR_NETWORK_LOCAL_ADDRESS]: CACHED_HOSTNAME,
|
|
19
|
+
});
|
|
20
|
+
}
|