@sebspark/otel 0.1.0 → 0.2.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 +144 -81
- package/dist/index.d.mts +8 -4
- package/dist/index.d.ts +8 -4
- package/dist/index.js +651 -85
- package/dist/index.mjs +656 -89
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
# `@sebspark/otel`
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Unified **OpenTelemetry** implementation for logging, tracing, and metrics — with environment detection, auto‑instrumentation, and clean console output for local development.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Use logger, tracer, and metrics
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
Install:
|
|
8
10
|
|
|
9
11
|
```sh
|
|
10
12
|
npm install @sebspark/otel
|
|
@@ -14,145 +16,206 @@ yarn add @sebspark/otel
|
|
|
14
16
|
pnpm add @sebspark/otel
|
|
15
17
|
```
|
|
16
18
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
The **OpenTelemetry SDK** is automatically initialized when you import `@sebspark/otel`.
|
|
19
|
+
### Initialization
|
|
20
20
|
|
|
21
|
-
**This
|
|
21
|
+
**This must be the first import in your application:**
|
|
22
22
|
|
|
23
23
|
```ts
|
|
24
24
|
import '@sebspark/otel'
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
Automatically:
|
|
28
28
|
|
|
29
|
-
-
|
|
30
|
-
|
|
31
|
-
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
-
|
|
35
|
-
|
|
36
|
-
|
|
29
|
+
- Initializes the OpenTelemetry SDK
|
|
30
|
+
- Auto‑instruments common libraries like **HTTP**, **gRPC**, **Redis**, **PostgreSQL**
|
|
31
|
+
- Enables W3C Trace Context propagation
|
|
32
|
+
- Detects environment and adds `resourceAttributes`
|
|
33
|
+
- Links logs with `trace_id` and `span_id`
|
|
34
|
+
- Handles graceful shutdown on `SIGTERM`
|
|
35
|
+
|
|
36
|
+
---
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
### Logging
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
```ts
|
|
41
|
+
import { getLogger } from '@sebspark/otel'
|
|
41
42
|
|
|
42
|
-
|
|
43
|
+
const logger = getLogger()
|
|
43
44
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
CLOUD_PROVIDER | cloud.provider | e.g. 'gcp', 'aws', etc.
|
|
45
|
+
logger.debug('debug message')
|
|
46
|
+
logger.info('something happened')
|
|
47
|
+
logger.warn('almost bad')
|
|
48
|
+
logger.error('very bad')
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Logs inside active spans automatically include:
|
|
52
|
+
- `trace_id`
|
|
53
|
+
- `span_id`
|
|
54
|
+
- `service.name`
|
|
55
|
+
- `service.version`
|
|
56
56
|
|
|
57
57
|
---
|
|
58
58
|
|
|
59
|
-
###
|
|
59
|
+
### Tracing
|
|
60
60
|
|
|
61
|
-
|
|
61
|
+
```ts
|
|
62
|
+
import { getTracer } from '@sebspark/otel'
|
|
63
|
+
|
|
64
|
+
const tracer = getTracer()
|
|
65
|
+
|
|
66
|
+
await tracer.withTrace('trace.name', async (span) => {
|
|
67
|
+
span.setAttribute('user.id', '123')
|
|
68
|
+
// do something...
|
|
69
|
+
})
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
If the callback throws:
|
|
73
|
+
- Span is marked as `ERROR`
|
|
74
|
+
- Exception is recorded
|
|
75
|
+
- Span is ended properly
|
|
76
|
+
|
|
77
|
+
Synchronous variant:
|
|
62
78
|
|
|
63
79
|
```ts
|
|
64
|
-
|
|
80
|
+
tracer.withTraceSync('init.config', (span) => {
|
|
81
|
+
// synchronous code
|
|
82
|
+
span.setStatus({ code: SpanStatusCode.OK })
|
|
83
|
+
})
|
|
84
|
+
```
|
|
65
85
|
|
|
66
|
-
|
|
86
|
+
Nested:
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
await tracer.withTrace('trace.name', async (span1) => {
|
|
90
|
+
span1.setAttribute('user.id', '123')
|
|
91
|
+
|
|
92
|
+
await tracer.withTrace('trace.name2', span1, async (span2) => {
|
|
93
|
+
// do stuff
|
|
94
|
+
})
|
|
95
|
+
})
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Manual span usage:
|
|
67
99
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
100
|
+
```ts
|
|
101
|
+
const span = tracer.startSpan('manual-operation')
|
|
102
|
+
span.setAttribute('manual', true)
|
|
103
|
+
// work...
|
|
104
|
+
span.end()
|
|
72
105
|
```
|
|
73
106
|
|
|
74
107
|
---
|
|
75
108
|
|
|
76
109
|
### Metrics
|
|
77
110
|
|
|
78
|
-
You can use the metrics API to create and export custom application-level metrics.
|
|
79
|
-
|
|
80
111
|
```ts
|
|
81
112
|
import { getMeter } from '@sebspark/otel'
|
|
82
113
|
|
|
83
114
|
const meter = getMeter()
|
|
84
115
|
|
|
85
116
|
const counter = meter.createCounter('http_requests_total', {
|
|
86
|
-
description: 'Total number of HTTP requests'
|
|
117
|
+
description: 'Total number of HTTP requests',
|
|
87
118
|
})
|
|
88
119
|
|
|
89
120
|
counter.add(1, {
|
|
90
121
|
route: '/api/hello',
|
|
91
|
-
method: 'GET'
|
|
122
|
+
method: 'GET',
|
|
92
123
|
})
|
|
93
124
|
```
|
|
94
125
|
|
|
95
126
|
---
|
|
96
127
|
|
|
97
|
-
|
|
128
|
+
## Configure for cloud use (with OpenTelemetry Collector)
|
|
98
129
|
|
|
99
|
-
|
|
130
|
+
When deployed to **Cloud Run**, **GKE**, or other cloud environments, telemetry automatically exports to your configured **OpenTelemetry Collector**.
|
|
100
131
|
|
|
101
|
-
|
|
132
|
+
Set these environment variables:
|
|
102
133
|
|
|
103
|
-
|
|
104
|
-
|
|
134
|
+
| Variable | Description | Example |
|
|
135
|
+
|-------------------------------|---------------------------------|-------------------------------|
|
|
136
|
+
| `OTEL_EXPORTER_OTLP_ENDPOINT` | Collector endpoint | `http://otel-collector:4318` |
|
|
137
|
+
| `OTEL_SERVICE_NAME` | Override detected service name | `trade-api` |
|
|
138
|
+
| `OTEL_SERVICE_VERSION` | Version of this instance | `1.2.3` |
|
|
105
139
|
|
|
106
|
-
|
|
107
|
-
```
|
|
140
|
+
Additional GCP/Kubernetes context is auto‑detected:
|
|
108
141
|
|
|
109
|
-
|
|
142
|
+
| Env Variable | Attribute Key | Example |
|
|
143
|
+
|---------------------------|-----------------------|-------------------|
|
|
144
|
+
| `K_SERVICE` | `cloud.run.service` | `trade-api` |
|
|
145
|
+
| `K_REVISION` | `cloud.run.revision` | `trade-api-v15` |
|
|
146
|
+
| `POD_NAME` | `k8s.pod_name` | `api-1234` |
|
|
147
|
+
| `KUBERNETES_SERVICE_HOST` | `cloud.orchestrator` | `kubernetes` |
|
|
148
|
+
| `GCP_PROJECT` | `cloud.account.id` | `my-gcp-project` |
|
|
110
149
|
|
|
111
|
-
|
|
112
|
-
const tracer = getTracer('my-custom-service')
|
|
113
|
-
```
|
|
150
|
+
---
|
|
114
151
|
|
|
115
|
-
|
|
152
|
+
## Configure for local use (dev logging)
|
|
116
153
|
|
|
117
|
-
**
|
|
154
|
+
In development, `@sebspark/otel` outputs human-readable **logs**, **spans**, and **metrics** directly to the console.
|
|
118
155
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
### Environment variables
|
|
159
|
+
|
|
160
|
+
| Variable | Affects | Values | Description |
|
|
161
|
+
|----------------|---------|------------------------------------------|-----------------------------------------------------------------------------------------|
|
|
162
|
+
| `LOG_LEVEL` | Logs | `debug,info,warn,error` | Minimum severity to print |
|
|
163
|
+
| `SPAN_LEVEL` | Traces | `OK`, `ERROR`, `UNSET` (comma-separated) | Only trees containing **at least one** span with one of these statuses will be printed |
|
|
164
|
+
| `METRIC_FILTER`| Metrics | Glob patterns (comma-separated) | Only metrics matching any of the patterns are shown |
|
|
165
|
+
|
|
166
|
+
---
|
|
125
167
|
|
|
126
|
-
|
|
168
|
+
### Logs
|
|
169
|
+
|
|
170
|
+
Filtered by `LOG_LEVEL`:
|
|
171
|
+
|
|
172
|
+
```sh
|
|
173
|
+
LOG_LEVEL=warn yarn dev
|
|
174
|
+
```
|
|
127
175
|
|
|
128
176
|
```ts
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
})
|
|
177
|
+
⚠️ [trade-api@1.2.3] GET /orders/limit-exceeded WARN trace_id=abc123 span_id=def456
|
|
178
|
+
❌ [trade-api@1.2.3] Order validation failed ERROR trace_id=abc123 span_id=def456
|
|
132
179
|
```
|
|
133
180
|
|
|
134
|
-
|
|
181
|
+
---
|
|
135
182
|
|
|
136
|
-
|
|
183
|
+
### Spans
|
|
137
184
|
|
|
138
|
-
|
|
139
|
-
- The error is recorded via `span.recordException()`
|
|
140
|
-
- The span is always ended correctly
|
|
185
|
+
Filtered by `SPAN_LEVEL` — the entire span **tree** is printed only if **at least one** span in the tree matches the status.
|
|
141
186
|
|
|
142
|
-
|
|
187
|
+
```sh
|
|
188
|
+
SPAN_LEVEL=ERROR yarn dev
|
|
189
|
+
```
|
|
143
190
|
|
|
144
191
|
```ts
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
192
|
+
[test@1.0.0] 12:00:00.000
|
|
193
|
+
└─ express ████████████████████ OK (0 ms–1.00 s)
|
|
194
|
+
└─ middleware:auth ███████ OK (0 ms–0.20 s)
|
|
195
|
+
└─ handler:getUser ████████████████████ ERROR (0 ms–1.00 s)
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
```sh
|
|
199
|
+
SPAN_LEVEL=OK,ERROR yarn dev
|
|
149
200
|
```
|
|
150
201
|
|
|
151
|
-
|
|
202
|
+
```ts
|
|
203
|
+
[test@1.0.0] 12:01:00.000
|
|
204
|
+
└─ express ████████████████████ OK (0 ms–1.00 s)
|
|
205
|
+
└─ middleware:auth ███████ OK (0 ms–0.20 s)
|
|
206
|
+
```
|
|
152
207
|
|
|
153
|
-
|
|
208
|
+
---
|
|
154
209
|
|
|
155
|
-
|
|
156
|
-
- `parent_span_name`
|
|
210
|
+
### 📈 Metrics
|
|
157
211
|
|
|
158
|
-
|
|
212
|
+
Filtered by `METRIC_FILTER`:
|
|
213
|
+
|
|
214
|
+
```sh
|
|
215
|
+
METRIC_FILTER=http.*,db.* yarn dev
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
```ts
|
|
219
|
+
📊 [trade-api@1.2.3] 12:00:00.000 📊 express http.server.duration 240ms {route=/api/hello method=GET}
|
|
220
|
+
📊 [trade-api@1.2.3] 12:00:01.000 📊 pg db.query.count 1 {query=SELECT * FROM users}
|
|
221
|
+
```
|
package/dist/index.d.mts
CHANGED
|
@@ -13,19 +13,23 @@ declare function getLogger(serviceOverride?: string, extraAttrs?: Attrs): {
|
|
|
13
13
|
emergency: (msg: string, attrs?: Attrs) => void;
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
-
declare function getMeter(
|
|
16
|
+
declare function getMeter(componentNameOverride?: string): _opentelemetry_api.Meter;
|
|
17
17
|
|
|
18
18
|
type OtelTracer = ReturnType<typeof trace.getTracer>;
|
|
19
19
|
type Span = ReturnType<OtelTracer['startSpan']>;
|
|
20
|
-
type Func<T> = (span
|
|
21
|
-
type SyncFunc<T> = (span
|
|
20
|
+
type Func<T> = (span: Span) => Promise<T> | T;
|
|
21
|
+
type SyncFunc<T> = (span: Span) => T;
|
|
22
22
|
type WithTrace = {
|
|
23
23
|
<T>(name: string, fn: Func<T>): Promise<T>;
|
|
24
24
|
<T>(name: string, options: SpanOptions, fn: Func<T>): Promise<T>;
|
|
25
|
+
<T>(name: string, parent: Span, fn: Func<T>): Promise<T>;
|
|
26
|
+
<T>(name: string, options: SpanOptions, parent: Span, fn: Func<T>): Promise<T>;
|
|
25
27
|
};
|
|
26
28
|
type WithTraceSync = {
|
|
27
29
|
<T>(name: string, fn: SyncFunc<T>): T;
|
|
28
30
|
<T>(name: string, options: SpanOptions, fn: SyncFunc<T>): T;
|
|
31
|
+
<T>(name: string, parent: Span, fn: SyncFunc<T>): T;
|
|
32
|
+
<T>(name: string, options: SpanOptions, parent: Span, fn: SyncFunc<T>): T;
|
|
29
33
|
};
|
|
30
34
|
/**
|
|
31
35
|
* Extended tracer with helper methods for span-wrapped execution
|
|
@@ -41,6 +45,6 @@ interface Tracer extends OtelTracer {
|
|
|
41
45
|
* @param serviceOverride - Optional override for service name
|
|
42
46
|
* @returns Tracer with helpers
|
|
43
47
|
*/
|
|
44
|
-
declare function getTracer(
|
|
48
|
+
declare function getTracer(componentNameOverride?: string): Tracer;
|
|
45
49
|
|
|
46
50
|
export { getLogger, getMeter, getTracer };
|
package/dist/index.d.ts
CHANGED
|
@@ -13,19 +13,23 @@ declare function getLogger(serviceOverride?: string, extraAttrs?: Attrs): {
|
|
|
13
13
|
emergency: (msg: string, attrs?: Attrs) => void;
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
-
declare function getMeter(
|
|
16
|
+
declare function getMeter(componentNameOverride?: string): _opentelemetry_api.Meter;
|
|
17
17
|
|
|
18
18
|
type OtelTracer = ReturnType<typeof trace.getTracer>;
|
|
19
19
|
type Span = ReturnType<OtelTracer['startSpan']>;
|
|
20
|
-
type Func<T> = (span
|
|
21
|
-
type SyncFunc<T> = (span
|
|
20
|
+
type Func<T> = (span: Span) => Promise<T> | T;
|
|
21
|
+
type SyncFunc<T> = (span: Span) => T;
|
|
22
22
|
type WithTrace = {
|
|
23
23
|
<T>(name: string, fn: Func<T>): Promise<T>;
|
|
24
24
|
<T>(name: string, options: SpanOptions, fn: Func<T>): Promise<T>;
|
|
25
|
+
<T>(name: string, parent: Span, fn: Func<T>): Promise<T>;
|
|
26
|
+
<T>(name: string, options: SpanOptions, parent: Span, fn: Func<T>): Promise<T>;
|
|
25
27
|
};
|
|
26
28
|
type WithTraceSync = {
|
|
27
29
|
<T>(name: string, fn: SyncFunc<T>): T;
|
|
28
30
|
<T>(name: string, options: SpanOptions, fn: SyncFunc<T>): T;
|
|
31
|
+
<T>(name: string, parent: Span, fn: SyncFunc<T>): T;
|
|
32
|
+
<T>(name: string, options: SpanOptions, parent: Span, fn: SyncFunc<T>): T;
|
|
29
33
|
};
|
|
30
34
|
/**
|
|
31
35
|
* Extended tracer with helper methods for span-wrapped execution
|
|
@@ -41,6 +45,6 @@ interface Tracer extends OtelTracer {
|
|
|
41
45
|
* @param serviceOverride - Optional override for service name
|
|
42
46
|
* @returns Tracer with helpers
|
|
43
47
|
*/
|
|
44
|
-
declare function getTracer(
|
|
48
|
+
declare function getTracer(componentNameOverride?: string): Tracer;
|
|
45
49
|
|
|
46
50
|
export { getLogger, getMeter, getTracer };
|