@manifest-cyber/observability-ts 0.2.2 โ 0.2.3
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 +74 -469
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,211 +1,114 @@
|
|
|
1
1
|
# @manifest-cyber/observability-ts
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> Unified observability library for Manifest Cyber's TypeScript services - **Prometheus metrics** and **OpenTelemetry tracing**.
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@manifest-cyber/observability-ts)
|
|
6
|
-
[](https://opensource.org/licenses/MIT)
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
## ๐ฆ Installation
|
|
7
|
+
## Installation
|
|
11
8
|
|
|
12
9
|
```bash
|
|
13
10
|
npm install @manifest-cyber/observability-ts
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
### Tracing Peer Dependencies (Optional)
|
|
17
|
-
|
|
18
|
-
To use tracing features, install OpenTelemetry dependencies:
|
|
19
11
|
|
|
20
|
-
|
|
12
|
+
# Optional: for tracing features
|
|
21
13
|
npm install @opentelemetry/sdk-node @opentelemetry/exporter-trace-otlp-grpc
|
|
22
14
|
```
|
|
23
15
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
## ๐ Quick Start
|
|
16
|
+
## Quick Start
|
|
27
17
|
|
|
28
|
-
### Metrics
|
|
18
|
+
### Metrics
|
|
29
19
|
|
|
30
20
|
```typescript
|
|
31
21
|
import { createCounter, startMetricsServer } from '@manifest-cyber/observability-ts';
|
|
32
22
|
|
|
33
|
-
// Create a counter
|
|
34
23
|
const requestsTotal = createCounter({
|
|
35
24
|
name: 'http_requests_total',
|
|
36
25
|
help: 'Total HTTP requests',
|
|
37
26
|
labelNames: ['method', 'status'],
|
|
38
27
|
});
|
|
39
28
|
|
|
40
|
-
// Start metrics server
|
|
41
29
|
await startMetricsServer({ serviceName: 'my-service' });
|
|
42
30
|
|
|
43
|
-
// Increment counter
|
|
44
31
|
requestsTotal.inc({ method: 'GET', status: '200' });
|
|
45
32
|
```
|
|
46
33
|
|
|
47
|
-
###
|
|
34
|
+
### Tracing
|
|
48
35
|
|
|
49
36
|
```typescript
|
|
50
|
-
import {
|
|
51
|
-
createCounter,
|
|
52
|
-
startMetricsServer,
|
|
53
|
-
initTracing,
|
|
54
|
-
withSpan,
|
|
55
|
-
} from '@manifest-cyber/observability-ts';
|
|
37
|
+
import { initTracing, withSpan } from '@manifest-cyber/observability-ts';
|
|
56
38
|
|
|
57
|
-
// Initialize both
|
|
58
39
|
await initTracing({ serviceName: 'my-service' });
|
|
59
|
-
await startMetricsServer({ serviceName: 'my-service' });
|
|
60
40
|
|
|
61
|
-
// Use both together
|
|
62
41
|
await withSpan('process.request', async (span) => {
|
|
63
42
|
span.setAttribute('user.id', userId);
|
|
64
|
-
requestsTotal.inc({ method: 'GET', status: '200' });
|
|
65
43
|
return await processRequest();
|
|
66
44
|
});
|
|
67
45
|
```
|
|
68
46
|
|
|
69
|
-
### Tree-Shakeable Imports
|
|
47
|
+
### Tree-Shakeable Imports
|
|
70
48
|
|
|
71
49
|
```typescript
|
|
72
|
-
|
|
73
|
-
import {
|
|
74
|
-
createCounter,
|
|
75
|
-
startMetricsServer,
|
|
76
|
-
} from '@manifest-cyber/observability-ts/metrics';
|
|
77
|
-
import { initTracing, withSpan } from '@manifest-cyber/observability-ts/tracing';
|
|
50
|
+
import { createCounter } from '@manifest-cyber/observability-ts/metrics';
|
|
51
|
+
import { initTracing } from '@manifest-cyber/observability-ts/tracing';
|
|
78
52
|
```
|
|
79
53
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
## ๐ Features
|
|
83
|
-
|
|
84
|
-
### Metrics (Prometheus)
|
|
85
|
-
|
|
86
|
-
- โ
**Counter, Gauge, Histogram, Summary** - Standard Prometheus metric types
|
|
87
|
-
- โ
**HTTP Metrics Server** - Built-in `/metrics` endpoint on port 9090
|
|
88
|
-
- โ
**Instrumentation Helpers** - Timer utilities, operation tracking
|
|
89
|
-
- โ
**Pre-configured Buckets** - Optimized for latency, database, and external calls
|
|
90
|
-
- โ
**Type-safe** - Full TypeScript support with generic label types
|
|
91
|
-
|
|
92
|
-
### Tracing (OpenTelemetry)
|
|
93
|
-
|
|
94
|
-
- โ
**W3C Trace Context** - Standard trace propagation across HTTP and message queues
|
|
95
|
-
- โ
**OTLP Export** - Export to VictoriaTraces, Jaeger, Tempo, etc.
|
|
96
|
-
- โ
**Automatic Instrumentation** - HTTP, gRPC, database calls (via sdk-node)
|
|
97
|
-
- โ
**Manual Spans** - Fine-grained control with `createSpan()` and `withSpan()`
|
|
98
|
-
- โ
**Message Queue Integration** - SQS and RabbitMQ trace propagation helpers
|
|
99
|
-
- โ
**Logger Integration** - Correlate logs with traces using logger-ts
|
|
100
|
-
- โ
**Flexible Sampling** - Environment-based sampling configuration
|
|
101
|
-
|
|
102
|
-
---
|
|
54
|
+
## Features
|
|
103
55
|
|
|
104
|
-
|
|
56
|
+
**Metrics (Prometheus)**
|
|
57
|
+
- Counter, Gauge, Histogram, Summary
|
|
58
|
+
- HTTP metrics server (`/metrics` on port 9090)
|
|
59
|
+
- Timer utilities and operation tracking
|
|
60
|
+
- Type-safe with TypeScript generics
|
|
105
61
|
|
|
106
|
-
|
|
107
|
-
-
|
|
108
|
-
-
|
|
62
|
+
**Tracing (OpenTelemetry)**
|
|
63
|
+
- W3C Trace Context propagation
|
|
64
|
+
- OTLP export (VictoriaTraces, Jaeger, Tempo)
|
|
65
|
+
- Automatic HTTP/gRPC/database instrumentation
|
|
66
|
+
- Manual span creation with `createSpan()` and `withSpan()`
|
|
67
|
+
- SQS and RabbitMQ trace propagation
|
|
68
|
+
- Logger integration for trace correlation
|
|
109
69
|
|
|
110
|
-
|
|
70
|
+
## API Overview
|
|
111
71
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
### Metrics API
|
|
115
|
-
|
|
116
|
-
#### Creating Metrics
|
|
72
|
+
### Metrics
|
|
117
73
|
|
|
118
74
|
```typescript
|
|
119
|
-
import {
|
|
120
|
-
createCounter,
|
|
121
|
-
createHistogram,
|
|
122
|
-
createGauge,
|
|
123
|
-
} from '@manifest-cyber/observability-ts/metrics';
|
|
75
|
+
import { createCounter, createHistogram, createGauge } from '@manifest-cyber/observability-ts/metrics';
|
|
124
76
|
|
|
125
|
-
// Counter
|
|
77
|
+
// Counter
|
|
126
78
|
const counter = createCounter({
|
|
127
79
|
name: 'operation_total',
|
|
128
80
|
help: 'Total operations',
|
|
129
81
|
labelNames: ['type', 'status'],
|
|
130
82
|
});
|
|
83
|
+
counter.inc({ type: 'api', status: 'success' });
|
|
131
84
|
|
|
132
|
-
// Histogram
|
|
85
|
+
// Histogram
|
|
133
86
|
const histogram = createHistogram({
|
|
134
87
|
name: 'request_duration_seconds',
|
|
135
|
-
help: 'Request duration
|
|
88
|
+
help: 'Request duration',
|
|
136
89
|
labelNames: ['route', 'method'],
|
|
137
|
-
buckets: [0.1, 0.5, 1, 2, 5],
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
// Gauge - Current value that can go up or down
|
|
141
|
-
const gauge = createGauge({
|
|
142
|
-
name: 'active_connections',
|
|
143
|
-
help: 'Number of active connections',
|
|
144
90
|
});
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
#### Using Metrics
|
|
148
|
-
|
|
149
|
-
```typescript
|
|
150
|
-
// Counter
|
|
151
|
-
counter.inc({ type: 'api', status: 'success' }); // +1
|
|
152
|
-
counter.inc({ type: 'api', status: 'success' }, 5); // +5
|
|
153
|
-
|
|
154
|
-
// Histogram
|
|
155
91
|
histogram.observe({ route: '/api/users', method: 'GET' }, 0.42);
|
|
156
92
|
|
|
157
93
|
// Gauge
|
|
158
|
-
gauge
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
#### Instrumentation Helpers
|
|
164
|
-
|
|
165
|
-
```typescript
|
|
166
|
-
import { Timer, trackOperation } from '@manifest-cyber/observability-ts/metrics';
|
|
167
|
-
|
|
168
|
-
// Track operation duration
|
|
169
|
-
const result = await trackOperation(
|
|
170
|
-
histogram,
|
|
171
|
-
{ route: '/api/users', method: 'GET' },
|
|
172
|
-
async () => {
|
|
173
|
-
return await fetchUsers();
|
|
174
|
-
},
|
|
175
|
-
);
|
|
176
|
-
|
|
177
|
-
// Manual timer
|
|
178
|
-
const timer = new Timer();
|
|
179
|
-
await doWork();
|
|
180
|
-
histogram.observe({ operation: 'work' }, timer.elapsedSeconds());
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
#### Metrics Server
|
|
184
|
-
|
|
185
|
-
```typescript
|
|
186
|
-
import { startMetricsServer } from '@manifest-cyber/observability-ts/metrics';
|
|
187
|
-
|
|
188
|
-
// Start server on port 9090 (default)
|
|
189
|
-
await startMetricsServer({
|
|
190
|
-
serviceName: 'my-service',
|
|
191
|
-
port: 9090,
|
|
94
|
+
const gauge = createGauge({
|
|
95
|
+
name: 'active_connections',
|
|
96
|
+
help: 'Active connections',
|
|
192
97
|
});
|
|
193
|
-
|
|
194
|
-
// Access metrics at http://localhost:9090/metrics
|
|
98
|
+
gauge.set(42);
|
|
195
99
|
```
|
|
196
100
|
|
|
197
|
-
### Tracing
|
|
198
|
-
|
|
199
|
-
#### Initialize Tracing
|
|
101
|
+
### Tracing
|
|
200
102
|
|
|
201
103
|
```typescript
|
|
202
|
-
import { initTracing } from '@manifest-cyber/observability-ts/tracing';
|
|
104
|
+
import { initTracing, withSpan, createSpan } from '@manifest-cyber/observability-ts/tracing';
|
|
203
105
|
|
|
106
|
+
// Initialize
|
|
204
107
|
await initTracing({
|
|
205
|
-
serviceName:
|
|
108
|
+
serviceName: 'my-service',
|
|
206
109
|
exporter: {
|
|
207
110
|
type: 'otlp-grpc',
|
|
208
|
-
endpoint:
|
|
111
|
+
endpoint: 'http://localhost:4317',
|
|
209
112
|
},
|
|
210
113
|
sampling: {
|
|
211
114
|
type: 'parentBased',
|
|
@@ -214,132 +117,66 @@ await initTracing({
|
|
|
214
117
|
},
|
|
215
118
|
},
|
|
216
119
|
});
|
|
217
|
-
```
|
|
218
|
-
|
|
219
|
-
#### Create Spans
|
|
220
|
-
|
|
221
|
-
```typescript
|
|
222
|
-
import {
|
|
223
|
-
withSpan,
|
|
224
|
-
createSpan,
|
|
225
|
-
getCurrentSpan,
|
|
226
|
-
} from '@manifest-cyber/observability-ts/tracing';
|
|
227
120
|
|
|
228
121
|
// Automatic span lifecycle
|
|
229
|
-
|
|
122
|
+
await withSpan('database.query', async (span) => {
|
|
230
123
|
span.setAttribute('db.statement', 'SELECT * FROM users');
|
|
231
|
-
span.setAttribute('db.name', 'manifest');
|
|
232
124
|
return await db.query('SELECT * FROM users');
|
|
233
125
|
});
|
|
234
126
|
|
|
235
127
|
// Manual span management
|
|
236
|
-
const span = createSpan('manual.operation'
|
|
128
|
+
const span = createSpan('manual.operation');
|
|
237
129
|
try {
|
|
238
|
-
span.setAttribute('custom.attribute', 'value');
|
|
239
130
|
await doWork();
|
|
240
131
|
span.setStatus({ code: SpanStatusCode.OK });
|
|
241
|
-
} catch (error) {
|
|
242
|
-
span.recordException(error);
|
|
243
|
-
span.setStatus({ code: SpanStatusCode.ERROR, message: error.message });
|
|
244
132
|
} finally {
|
|
245
133
|
span.end();
|
|
246
134
|
}
|
|
247
|
-
|
|
248
|
-
// Get current span
|
|
249
|
-
const activeSpan = getCurrentSpan();
|
|
250
|
-
activeSpan?.setAttribute('user.id', userId);
|
|
251
135
|
```
|
|
252
136
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
##### HTTP Propagation
|
|
137
|
+
### Trace Propagation
|
|
256
138
|
|
|
257
139
|
```typescript
|
|
258
|
-
import {
|
|
259
|
-
injectTraceContext,
|
|
140
|
+
import {
|
|
141
|
+
injectTraceContext,
|
|
260
142
|
extractTraceContext,
|
|
143
|
+
createMessageTraceContext,
|
|
144
|
+
extractMessageTraceContext
|
|
261
145
|
} from '@manifest-cyber/observability-ts/tracing';
|
|
262
146
|
|
|
263
|
-
// HTTP Client
|
|
264
|
-
const headers
|
|
147
|
+
// HTTP Client
|
|
148
|
+
const headers = {};
|
|
265
149
|
injectTraceContext(headers);
|
|
266
|
-
|
|
267
150
|
await axios.get('https://api.example.com/users', { headers });
|
|
268
151
|
|
|
269
|
-
// HTTP Server
|
|
152
|
+
// HTTP Server
|
|
270
153
|
app.use((req, res, next) => {
|
|
271
154
|
extractTraceContext(req.headers);
|
|
272
155
|
next();
|
|
273
156
|
});
|
|
274
|
-
```
|
|
275
157
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
createMessageTraceContext,
|
|
281
|
-
extractMessageTraceContext,
|
|
282
|
-
} from '@manifest-cyber/observability-ts/tracing';
|
|
283
|
-
|
|
284
|
-
// SQS Producer - Add trace context to message
|
|
285
|
-
await withSpan('sqs.send', async (span) => {
|
|
286
|
-
await sqs.sendMessage({
|
|
287
|
-
QueueUrl: queueUrl,
|
|
288
|
-
MessageBody: JSON.stringify(data),
|
|
289
|
-
MessageAttributes: createMessageTraceContext(),
|
|
290
|
-
});
|
|
158
|
+
// SQS Producer
|
|
159
|
+
await sqs.sendMessage({
|
|
160
|
+
QueueUrl: queueUrl,
|
|
161
|
+
MessageBody: JSON.stringify(data),
|
|
162
|
+
MessageAttributes: createMessageTraceContext(),
|
|
291
163
|
});
|
|
292
164
|
|
|
293
|
-
// SQS Consumer
|
|
165
|
+
// SQS Consumer
|
|
294
166
|
extractMessageTraceContext(message.MessageAttributes);
|
|
295
|
-
await withSpan('sqs.process', async (span) => {
|
|
296
|
-
await processMessage(message);
|
|
297
|
-
});
|
|
298
167
|
```
|
|
299
168
|
|
|
300
|
-
|
|
169
|
+
## Environment Variables
|
|
301
170
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
171
|
+
| Variable | Description | Default |
|
|
172
|
+
|----------|-------------|---------|
|
|
173
|
+
| `SERVICE_NAME` | Service name | `'unknown-service'` |
|
|
174
|
+
| `MFST_METRICS_PORT` | Metrics server port | `9090` |
|
|
175
|
+
| `OTEL_EXPORTER_OTLP_ENDPOINT` | OTLP endpoint | `'http://localhost:4317'` |
|
|
176
|
+
| `OTEL_TRACING_ENABLED` | Enable/disable tracing | `true` |
|
|
177
|
+
| `ENV` | Environment (dev/staging/prod) | `'development'` |
|
|
307
178
|
|
|
308
|
-
|
|
309
|
-
const spanId = getCurrentSpanId();
|
|
310
|
-
|
|
311
|
-
console.log(`Processing request [trace_id=${traceId}, span_id=${spanId}]`);
|
|
312
|
-
```
|
|
313
|
-
|
|
314
|
-
---
|
|
315
|
-
|
|
316
|
-
## ๐๏ธ Architecture
|
|
317
|
-
|
|
318
|
-
### Package Structure
|
|
319
|
-
|
|
320
|
-
```
|
|
321
|
-
@manifest-cyber/observability-ts
|
|
322
|
-
โโโ /metrics - Prometheus metrics (tree-shakeable)
|
|
323
|
-
โโโ /tracing - OpenTelemetry tracing (tree-shakeable)
|
|
324
|
-
โโโ (main export) - Combined exports (convenience)
|
|
325
|
-
```
|
|
326
|
-
|
|
327
|
-
### Exports
|
|
328
|
-
|
|
329
|
-
```typescript
|
|
330
|
-
// Main export - Everything
|
|
331
|
-
import { createCounter, initTracing } from '@manifest-cyber/observability-ts';
|
|
332
|
-
|
|
333
|
-
// Subpath exports - Tree-shakeable
|
|
334
|
-
import { createCounter } from '@manifest-cyber/observability-ts/metrics';
|
|
335
|
-
import { initTracing } from '@manifest-cyber/observability-ts/tracing';
|
|
336
|
-
```
|
|
337
|
-
|
|
338
|
-
---
|
|
339
|
-
|
|
340
|
-
## ๐ Integration Examples
|
|
341
|
-
|
|
342
|
-
### Express API with Metrics + Tracing
|
|
179
|
+
## Example: Express API
|
|
343
180
|
|
|
344
181
|
```typescript
|
|
345
182
|
import express from 'express';
|
|
@@ -350,15 +187,11 @@ import {
|
|
|
350
187
|
initTracing,
|
|
351
188
|
withSpan,
|
|
352
189
|
extractTraceContext,
|
|
353
|
-
injectTraceContext,
|
|
354
|
-
getCurrentTraceId,
|
|
355
190
|
} from '@manifest-cyber/observability-ts';
|
|
356
191
|
|
|
357
|
-
// Initialize observability
|
|
358
192
|
await initTracing({ serviceName: 'api-service' });
|
|
359
193
|
await startMetricsServer({ serviceName: 'api-service' });
|
|
360
194
|
|
|
361
|
-
// Create metrics
|
|
362
195
|
const httpRequests = createCounter({
|
|
363
196
|
name: 'http_requests_total',
|
|
364
197
|
help: 'Total HTTP requests',
|
|
@@ -367,20 +200,14 @@ const httpRequests = createCounter({
|
|
|
367
200
|
|
|
368
201
|
const httpDuration = createHistogram({
|
|
369
202
|
name: 'http_request_duration_seconds',
|
|
370
|
-
help: 'HTTP request duration
|
|
203
|
+
help: 'HTTP request duration',
|
|
371
204
|
labelNames: ['method', 'route', 'status'],
|
|
372
205
|
});
|
|
373
206
|
|
|
374
207
|
const app = express();
|
|
375
208
|
|
|
376
|
-
// Middleware - Extract trace context
|
|
377
209
|
app.use((req, res, next) => {
|
|
378
210
|
extractTraceContext(req.headers);
|
|
379
|
-
next();
|
|
380
|
-
});
|
|
381
|
-
|
|
382
|
-
// Middleware - Automatic instrumentation
|
|
383
|
-
app.use((req, res, next) => {
|
|
384
211
|
const start = Date.now();
|
|
385
212
|
|
|
386
213
|
res.on('finish', () => {
|
|
@@ -390,7 +217,6 @@ app.use((req, res, next) => {
|
|
|
390
217
|
route: req.route?.path || req.path,
|
|
391
218
|
status: res.statusCode.toString(),
|
|
392
219
|
};
|
|
393
|
-
|
|
394
220
|
httpRequests.inc(labels);
|
|
395
221
|
httpDuration.observe(labels, duration);
|
|
396
222
|
});
|
|
@@ -398,14 +224,9 @@ app.use((req, res, next) => {
|
|
|
398
224
|
next();
|
|
399
225
|
});
|
|
400
226
|
|
|
401
|
-
// Route handler with tracing
|
|
402
227
|
app.get('/api/users/:id', async (req, res) => {
|
|
403
228
|
await withSpan('http.GET /api/users/:id', async (span) => {
|
|
404
|
-
span.setAttribute('http.method', 'GET');
|
|
405
|
-
span.setAttribute('http.route', '/api/users/:id');
|
|
406
|
-
span.setAttribute('http.target', req.path);
|
|
407
229
|
span.setAttribute('user.id', req.params.id);
|
|
408
|
-
|
|
409
230
|
const user = await fetchUser(req.params.id);
|
|
410
231
|
res.json(user);
|
|
411
232
|
});
|
|
@@ -414,207 +235,15 @@ app.get('/api/users/:id', async (req, res) => {
|
|
|
414
235
|
app.listen(3000);
|
|
415
236
|
```
|
|
416
237
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
```typescript
|
|
420
|
-
import {
|
|
421
|
-
initTracing,
|
|
422
|
-
withSpan,
|
|
423
|
-
extractMessageTraceContext,
|
|
424
|
-
} from '@manifest-cyber/observability-ts';
|
|
425
|
-
|
|
426
|
-
await initTracing({ serviceName: 'job-worker' });
|
|
427
|
-
|
|
428
|
-
// SQS Consumer
|
|
429
|
-
while (true) {
|
|
430
|
-
const messages = await sqs.receiveMessage({ QueueUrl: queueUrl });
|
|
431
|
-
|
|
432
|
-
for (const message of messages.Messages || []) {
|
|
433
|
-
// Extract trace context from message
|
|
434
|
-
extractMessageTraceContext(message.MessageAttributes);
|
|
435
|
-
|
|
436
|
-
await withSpan('sqs.process', async (span) => {
|
|
437
|
-
span.setAttribute('messaging.system', 'sqs');
|
|
438
|
-
span.setAttribute('messaging.operation', 'process');
|
|
439
|
-
span.setAttribute('messaging.message.id', message.MessageId);
|
|
440
|
-
|
|
441
|
-
const body = JSON.parse(message.Body);
|
|
442
|
-
await processJob(body);
|
|
443
|
-
|
|
444
|
-
await sqs.deleteMessage({
|
|
445
|
-
QueueUrl: queueUrl,
|
|
446
|
-
ReceiptHandle: message.ReceiptHandle,
|
|
447
|
-
});
|
|
448
|
-
});
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
```
|
|
452
|
-
|
|
453
|
-
### Integration with logger-ts
|
|
454
|
-
|
|
455
|
-
```typescript
|
|
456
|
-
import { OtelLogger } from '@manifest-cyber/logger-ts';
|
|
457
|
-
import { getCurrentTraceId, getCurrentSpanId } from '@manifest-cyber/observability-ts';
|
|
458
|
-
|
|
459
|
-
const logger = new OtelLogger({ serviceName: 'my-service' });
|
|
460
|
-
|
|
461
|
-
await withSpan('operation', async () => {
|
|
462
|
-
// Logger automatically picks up trace context
|
|
463
|
-
logger.info('Processing request', {
|
|
464
|
-
userId: '123',
|
|
465
|
-
// Trace and span IDs automatically included
|
|
466
|
-
});
|
|
467
|
-
|
|
468
|
-
// Or manually include them
|
|
469
|
-
logger.info('Manual trace correlation', {
|
|
470
|
-
trace_id: getCurrentTraceId(),
|
|
471
|
-
span_id: getCurrentSpanId(),
|
|
472
|
-
});
|
|
473
|
-
});
|
|
474
|
-
```
|
|
475
|
-
|
|
476
|
-
---
|
|
477
|
-
|
|
478
|
-
## ๐ Environment Variables
|
|
479
|
-
|
|
480
|
-
### Metrics
|
|
481
|
-
|
|
482
|
-
| Variable | Description | Default |
|
|
483
|
-
| ------------------- | ------------------------------- | ------------------- |
|
|
484
|
-
| `SERVICE_NAME` | Service name for metrics labels | `'unknown-service'` |
|
|
485
|
-
| `MFST_METRICS_PORT` | Port for metrics HTTP server | `9090` |
|
|
486
|
-
|
|
487
|
-
### Tracing
|
|
488
|
-
|
|
489
|
-
| Variable | Description | Default |
|
|
490
|
-
| ----------------------------- | ------------------------------ | ------------------------- |
|
|
491
|
-
| `SERVICE_NAME` | Service name for traces | `'unknown-service'` |
|
|
492
|
-
| `OTEL_EXPORTER_OTLP_ENDPOINT` | OTLP endpoint URL | `'http://localhost:4317'` |
|
|
493
|
-
| `OTEL_TRACING_ENABLED` | Enable/disable tracing | `true` |
|
|
494
|
-
| `ENV` | Environment (dev/staging/prod) | `'development'` |
|
|
495
|
-
|
|
496
|
-
---
|
|
497
|
-
|
|
498
|
-
## ๐ณ Deployment
|
|
499
|
-
|
|
500
|
-
### ECS (SaaS Deployment)
|
|
501
|
-
|
|
502
|
-
Services run with **Vector sidecar** that receives OTLP traces:
|
|
503
|
-
|
|
504
|
-
```typescript
|
|
505
|
-
await initTracing({
|
|
506
|
-
serviceName: process.env.SERVICE_NAME,
|
|
507
|
-
exporter: {
|
|
508
|
-
type: 'otlp-grpc',
|
|
509
|
-
endpoint: 'http://localhost:4317', // Vector sidecar
|
|
510
|
-
},
|
|
511
|
-
});
|
|
512
|
-
```
|
|
513
|
-
|
|
514
|
-
**Vector config** routes traces to VictoriaTraces:
|
|
515
|
-
|
|
516
|
-
```toml
|
|
517
|
-
[sources.otlp]
|
|
518
|
-
type = "opentelemetry"
|
|
519
|
-
grpc.address = "0.0.0.0:4317"
|
|
520
|
-
|
|
521
|
-
[sinks.victoria_traces]
|
|
522
|
-
type = "http"
|
|
523
|
-
inputs = ["otlp"]
|
|
524
|
-
uri = "http://victoria-traces:4318/opentelemetry/v1/traces"
|
|
525
|
-
```
|
|
526
|
-
|
|
527
|
-
### Kubernetes (On-Prem Deployment)
|
|
528
|
-
|
|
529
|
-
Services export to **OpenTelemetry Collector** DaemonSet:
|
|
530
|
-
|
|
531
|
-
```typescript
|
|
532
|
-
await initTracing({
|
|
533
|
-
serviceName: process.env.SERVICE_NAME,
|
|
534
|
-
exporter: {
|
|
535
|
-
type: 'otlp-grpc',
|
|
536
|
-
endpoint: 'http://otel-collector:4317',
|
|
537
|
-
},
|
|
538
|
-
});
|
|
539
|
-
```
|
|
540
|
-
|
|
541
|
-
**Collector config** forwards to VictoriaTraces:
|
|
542
|
-
|
|
543
|
-
```yaml
|
|
544
|
-
exporters:
|
|
545
|
-
otlp:
|
|
546
|
-
endpoint: http://victoria-traces:4317
|
|
547
|
-
|
|
548
|
-
service:
|
|
549
|
-
pipelines:
|
|
550
|
-
traces:
|
|
551
|
-
receivers: [otlp]
|
|
552
|
-
processors: [batch]
|
|
553
|
-
exporters: [otlp]
|
|
554
|
-
```
|
|
555
|
-
|
|
556
|
-
---
|
|
557
|
-
|
|
558
|
-
## ๐ฌ Sampling
|
|
559
|
-
|
|
560
|
-
Recommended sampling configuration by environment:
|
|
561
|
-
|
|
562
|
-
```typescript
|
|
563
|
-
const getSamplingConfig = () => {
|
|
564
|
-
const env = process.env.ENV || 'development';
|
|
565
|
-
|
|
566
|
-
if (env === 'production') {
|
|
567
|
-
return {
|
|
568
|
-
type: 'parentBased' as const,
|
|
569
|
-
parentBased: {
|
|
570
|
-
root: { type: 'traceIdRatio' as const, ratio: 0.1 }, // 10%
|
|
571
|
-
},
|
|
572
|
-
};
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
// 100% sampling in dev/staging
|
|
576
|
-
return {
|
|
577
|
-
type: 'alwaysOn' as const,
|
|
578
|
-
};
|
|
579
|
-
};
|
|
580
|
-
|
|
581
|
-
await initTracing({
|
|
582
|
-
serviceName: process.env.SERVICE_NAME,
|
|
583
|
-
sampling: getSamplingConfig(),
|
|
584
|
-
});
|
|
585
|
-
```
|
|
586
|
-
|
|
587
|
-
---
|
|
588
|
-
|
|
589
|
-
## ๐งช Testing
|
|
590
|
-
|
|
591
|
-
```bash
|
|
592
|
-
# Install dependencies
|
|
593
|
-
npm install
|
|
594
|
-
|
|
595
|
-
# Run tests
|
|
596
|
-
npm test
|
|
597
|
-
|
|
598
|
-
# Build
|
|
599
|
-
npm run build
|
|
600
|
-
|
|
601
|
-
# Type check
|
|
602
|
-
npm run type-check
|
|
603
|
-
```
|
|
604
|
-
|
|
605
|
-
---
|
|
606
|
-
|
|
607
|
-
## ๐ Migration from @manifest-cyber/metrics
|
|
608
|
-
|
|
609
|
-
See [MIGRATION_GUIDE.md](./MIGRATION_GUIDE.md) for detailed migration instructions.
|
|
610
|
-
|
|
611
|
-
**TL;DR**: Update package name and imports. All existing code is backward compatible!
|
|
238
|
+
## Migration from @manifest-cyber/metrics
|
|
612
239
|
|
|
613
240
|
```bash
|
|
614
241
|
npm uninstall @manifest-cyber/metrics
|
|
615
242
|
npm install @manifest-cyber/observability-ts
|
|
616
243
|
```
|
|
617
244
|
|
|
245
|
+
Update imports - **all existing code is backward compatible**:
|
|
246
|
+
|
|
618
247
|
```typescript
|
|
619
248
|
// Before
|
|
620
249
|
import { createCounter } from '@manifest-cyber/metrics';
|
|
@@ -623,36 +252,12 @@ import { createCounter } from '@manifest-cyber/metrics';
|
|
|
623
252
|
import { createCounter } from '@manifest-cyber/observability-ts';
|
|
624
253
|
```
|
|
625
254
|
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
## ๐ค Contributing
|
|
629
|
-
|
|
630
|
-
1. Fork the repository
|
|
631
|
-
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
|
|
632
|
-
3. Commit your changes (`git commit -m 'Add amazing feature'`)
|
|
633
|
-
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
634
|
-
5. Open a Pull Request
|
|
635
|
-
|
|
636
|
-
---
|
|
637
|
-
|
|
638
|
-
## ๐ License
|
|
639
|
-
|
|
640
|
-
MIT ยฉ [Manifest Cyber](https://github.com/manifest-cyber)
|
|
641
|
-
|
|
642
|
-
---
|
|
643
|
-
|
|
644
|
-
## ๐ Links
|
|
255
|
+
## Links
|
|
645
256
|
|
|
646
|
-
- **
|
|
647
|
-
- **
|
|
648
|
-
- **Issues**:
|
|
649
|
-
- **Documentation**:
|
|
650
|
-
- [Tracing Guide](./TRACING_GUIDE.md)
|
|
651
|
-
- [Implementation Plan](./TRACING_IMPLEMENTATION_PLAN.md)
|
|
652
|
-
- [Migration Guide](./MIGRATION_GUIDE.md)
|
|
257
|
+
- **NPM**: https://www.npmjs.com/package/@manifest-cyber/observability-ts
|
|
258
|
+
- **GitHub**: https://github.com/manifest-cyber/observability-ts
|
|
259
|
+
- **Issues**: https://github.com/manifest-cyber/observability-ts/issues
|
|
653
260
|
|
|
654
|
-
|
|
261
|
+
## License
|
|
655
262
|
|
|
656
|
-
|
|
657
|
-
**OpenTelemetry Version**: 1.28.0
|
|
658
|
-
**Last Updated**: November 11, 2025
|
|
263
|
+
MIT ยฉ [Manifest Cyber](https://github.com/manifest-cyber)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@manifest-cyber/observability-ts",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "Unified observability library for Manifest Cyber services - Metrics (Prometheus) and Tracing (OpenTelemetry)",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|