@devopsplaybook.io/otel-utils 1.1.0-beta.21.b48a156 → 1.1.1-beta.22.d44c201
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/eslint.config.mjs +2 -1
- package/jest.config.js +14 -0
- package/package.json +24 -18
- package/src/createResource.spec.ts +20 -0
- package/tsconfig.json +2 -1
- package/tsconfig.spec.json +7 -0
- package/.github/workflows/npm-upgrade.yml +0 -16
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/eslint.config.mjs
CHANGED
|
@@ -4,7 +4,8 @@ import eslint from "@eslint/js";
|
|
|
4
4
|
import tseslint from "typescript-eslint";
|
|
5
5
|
|
|
6
6
|
export default tseslint.config(
|
|
7
|
+
{ ignores: ["dist/", "node_modules/"] },
|
|
7
8
|
eslint.configs.recommended,
|
|
8
9
|
...tseslint.configs.strict,
|
|
9
|
-
...tseslint.configs.stylistic
|
|
10
|
+
...tseslint.configs.stylistic,
|
|
10
11
|
);
|
package/jest.config.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
moduleFileExtensions: ["ts", "js"],
|
|
3
|
+
transform: {
|
|
4
|
+
"^.+\\.(ts|tsx)$": [
|
|
5
|
+
"ts-jest",
|
|
6
|
+
{
|
|
7
|
+
tsconfig: "tsconfig.spec.json",
|
|
8
|
+
},
|
|
9
|
+
],
|
|
10
|
+
},
|
|
11
|
+
testMatch: ["/**/src/**/*.spec.(ts|js)"],
|
|
12
|
+
testPathIgnorePatterns: ["/node_modules/", "/dist/"],
|
|
13
|
+
testEnvironment: "node",
|
|
14
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@devopsplaybook.io/otel-utils",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.1-beta.22.d44c201",
|
|
4
4
|
"description": "Utility to simplify integration with Open Telemetry",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Open",
|
|
@@ -16,34 +16,40 @@
|
|
|
16
16
|
"types": "dist/index.d.ts",
|
|
17
17
|
"scripts": {
|
|
18
18
|
"build": "tsc",
|
|
19
|
+
"lint": "eslint src",
|
|
20
|
+
"test": "jest --coverage",
|
|
19
21
|
"dependencies": ""
|
|
20
22
|
},
|
|
21
23
|
"dependencies": {
|
|
22
24
|
"@opentelemetry/api": "^1.9.1",
|
|
23
|
-
"@opentelemetry/api-logs": "^0.
|
|
24
|
-
"@opentelemetry/auto-instrumentations-node": "^0.
|
|
25
|
-
"@opentelemetry/context-async-hooks": "^2.
|
|
26
|
-
"@opentelemetry/core": "^2.
|
|
27
|
-
"@opentelemetry/exporter-logs-otlp-http": "^0.
|
|
28
|
-
"@opentelemetry/exporter-metrics-otlp-http": "^0.
|
|
29
|
-
"@opentelemetry/exporter-trace-otlp-http": "^0.
|
|
25
|
+
"@opentelemetry/api-logs": "^0.219.0",
|
|
26
|
+
"@opentelemetry/auto-instrumentations-node": "^0.77.0",
|
|
27
|
+
"@opentelemetry/context-async-hooks": "^2.8.0",
|
|
28
|
+
"@opentelemetry/core": "^2.8.0",
|
|
29
|
+
"@opentelemetry/exporter-logs-otlp-http": "^0.219.0",
|
|
30
|
+
"@opentelemetry/exporter-metrics-otlp-http": "^0.219.0",
|
|
31
|
+
"@opentelemetry/exporter-trace-otlp-http": "^0.219.0",
|
|
30
32
|
"@opentelemetry/id-generator-aws-xray": "^2.1.0",
|
|
31
|
-
"@opentelemetry/resources": "^2.
|
|
32
|
-
"@opentelemetry/sdk-logs": "^0.
|
|
33
|
-
"@opentelemetry/sdk-metrics": "^2.
|
|
34
|
-
"@opentelemetry/sdk-node": "^0.
|
|
35
|
-
"@opentelemetry/sdk-trace-base": "^2.
|
|
36
|
-
"@opentelemetry/sdk-trace-node": "^2.
|
|
37
|
-
"@opentelemetry/sdk-trace-web": "^2.
|
|
33
|
+
"@opentelemetry/resources": "^2.8.0",
|
|
34
|
+
"@opentelemetry/sdk-logs": "^0.219.0",
|
|
35
|
+
"@opentelemetry/sdk-metrics": "^2.8.0",
|
|
36
|
+
"@opentelemetry/sdk-node": "^0.219.0",
|
|
37
|
+
"@opentelemetry/sdk-trace-base": "^2.8.0",
|
|
38
|
+
"@opentelemetry/sdk-trace-node": "^2.8.0",
|
|
39
|
+
"@opentelemetry/sdk-trace-web": "^2.8.0",
|
|
38
40
|
"@opentelemetry/semantic-conventions": "^1.41.1"
|
|
39
41
|
},
|
|
40
42
|
"devDependencies": {
|
|
41
43
|
"@eslint/js": "^10.0.1",
|
|
42
|
-
"@types/
|
|
44
|
+
"@types/jest": "^30.0.0",
|
|
45
|
+
"@types/node": "^26.0.1",
|
|
43
46
|
"@types/sqlite3": "^5.1.0",
|
|
47
|
+
"eslint": "^10.5.0",
|
|
48
|
+
"jest": "^30.4.2",
|
|
49
|
+
"ts-jest": "^29.4.11",
|
|
44
50
|
"ts-node": "^10.9.2",
|
|
45
|
-
"typescript
|
|
46
|
-
"typescript": "^
|
|
51
|
+
"typescript": "^6.0.3",
|
|
52
|
+
"typescript-eslint": "^8.62.0"
|
|
47
53
|
},
|
|
48
54
|
"publishConfig": {
|
|
49
55
|
"access": "public"
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { createOTelResource } from "./utils/createResource";
|
|
2
|
+
import { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION, ATTR_NETWORK_LOCAL_ADDRESS } from "@opentelemetry/semantic-conventions";
|
|
3
|
+
|
|
4
|
+
describe("createOTelResource", () => {
|
|
5
|
+
it("should create a resource with the provided service name and version", () => {
|
|
6
|
+
const resource = createOTelResource("test-service", "1.0.0");
|
|
7
|
+
const attrs = resource.attributes;
|
|
8
|
+
|
|
9
|
+
expect(attrs[ATTR_SERVICE_NAME]).toBe("test-service");
|
|
10
|
+
expect(attrs[ATTR_SERVICE_VERSION]).toBe("1.0.0");
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it("should include the local hostname as network local address", () => {
|
|
14
|
+
const resource = createOTelResource("test-service", "1.0.0");
|
|
15
|
+
const attrs = resource.attributes;
|
|
16
|
+
|
|
17
|
+
expect(attrs[ATTR_NETWORK_LOCAL_ADDRESS]).toBeDefined();
|
|
18
|
+
expect(typeof attrs[ATTR_NETWORK_LOCAL_ADDRESS]).toBe("string");
|
|
19
|
+
});
|
|
20
|
+
});
|
package/tsconfig.json
CHANGED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
name: NPM Upgrade
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
schedule:
|
|
5
|
-
- cron: "0 6 * * 1"
|
|
6
|
-
|
|
7
|
-
workflow_dispatch:
|
|
8
|
-
|
|
9
|
-
jobs:
|
|
10
|
-
npm-upgrade:
|
|
11
|
-
uses: devopsplaybook-io/common-utils/.github/workflows/reusable-npm-upgrade.yml@main
|
|
12
|
-
permissions:
|
|
13
|
-
contents: write
|
|
14
|
-
pull-requests: write
|
|
15
|
-
with:
|
|
16
|
-
npm_services: '[]'
|