@manifest-cyber/observability-ts 0.2.0-prerelease.20251111235219
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 +658 -0
- package/dist/src/index.d.ts +59 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +109 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/metrics/builders.d.ts +235 -0
- package/dist/src/metrics/builders.d.ts.map +1 -0
- package/dist/src/metrics/builders.js +303 -0
- package/dist/src/metrics/builders.js.map +1 -0
- package/dist/src/metrics/index.d.ts +36 -0
- package/dist/src/metrics/index.d.ts.map +1 -0
- package/dist/src/metrics/index.js +52 -0
- package/dist/src/metrics/index.js.map +1 -0
- package/dist/src/metrics/instrumentation.d.ts +157 -0
- package/dist/src/metrics/instrumentation.d.ts.map +1 -0
- package/dist/src/metrics/instrumentation.js +216 -0
- package/dist/src/metrics/instrumentation.js.map +1 -0
- package/dist/src/metrics/registry.d.ts +36 -0
- package/dist/src/metrics/registry.d.ts.map +1 -0
- package/dist/src/metrics/registry.js +48 -0
- package/dist/src/metrics/registry.js.map +1 -0
- package/dist/src/metrics/server.d.ts +72 -0
- package/dist/src/metrics/server.d.ts.map +1 -0
- package/dist/src/metrics/server.js +112 -0
- package/dist/src/metrics/server.js.map +1 -0
- package/dist/src/tracing/context.d.ts +213 -0
- package/dist/src/tracing/context.d.ts.map +1 -0
- package/dist/src/tracing/context.js +295 -0
- package/dist/src/tracing/context.js.map +1 -0
- package/dist/src/tracing/index.d.ts +79 -0
- package/dist/src/tracing/index.d.ts.map +1 -0
- package/dist/src/tracing/index.js +110 -0
- package/dist/src/tracing/index.js.map +1 -0
- package/dist/src/tracing/setup.d.ts +51 -0
- package/dist/src/tracing/setup.d.ts.map +1 -0
- package/dist/src/tracing/setup.js +230 -0
- package/dist/src/tracing/setup.js.map +1 -0
- package/dist/src/tracing/spans.d.ts +190 -0
- package/dist/src/tracing/spans.d.ts.map +1 -0
- package/dist/src/tracing/spans.js +300 -0
- package/dist/src/tracing/spans.js.map +1 -0
- package/dist/src/tracing/types.d.ts +158 -0
- package/dist/src/tracing/types.d.ts.map +1 -0
- package/dist/src/tracing/types.js +6 -0
- package/dist/src/tracing/types.js.map +1 -0
- package/dist/src/types.d.ts +34 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +3 -0
- package/dist/src/types.js.map +1 -0
- package/dist/test/builders.spec.d.ts +2 -0
- package/dist/test/builders.spec.d.ts.map +1 -0
- package/dist/test/builders.spec.js +111 -0
- package/dist/test/builders.spec.js.map +1 -0
- package/package.json +105 -0
package/README.md
ADDED
|
@@ -0,0 +1,658 @@
|
|
|
1
|
+
# @manifest-cyber/observability-ts
|
|
2
|
+
|
|
3
|
+
> **Unified observability library** for Manifest Cyber's TypeScript services, providing both **Prometheus metrics** and **OpenTelemetry distributed tracing**.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@manifest-cyber/observability-ts)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## ๐ฆ Installation
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install @manifest-cyber/observability-ts
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
### Tracing Peer Dependencies (Optional)
|
|
17
|
+
|
|
18
|
+
To use tracing features, install OpenTelemetry dependencies:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install @opentelemetry/sdk-node @opentelemetry/exporter-trace-otlp-grpc
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## ๐ Quick Start
|
|
27
|
+
|
|
28
|
+
### Metrics Only
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
import { createCounter, startMetricsServer } from '@manifest-cyber/observability-ts';
|
|
32
|
+
|
|
33
|
+
// Create a counter
|
|
34
|
+
const requestsTotal = createCounter({
|
|
35
|
+
name: 'http_requests_total',
|
|
36
|
+
help: 'Total HTTP requests',
|
|
37
|
+
labelNames: ['method', 'status'],
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// Start metrics server
|
|
41
|
+
await startMetricsServer({ serviceName: 'my-service' });
|
|
42
|
+
|
|
43
|
+
// Increment counter
|
|
44
|
+
requestsTotal.inc({ method: 'GET', status: '200' });
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Metrics + Tracing
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
import {
|
|
51
|
+
createCounter,
|
|
52
|
+
startMetricsServer,
|
|
53
|
+
initTracing,
|
|
54
|
+
withSpan,
|
|
55
|
+
} from '@manifest-cyber/observability-ts';
|
|
56
|
+
|
|
57
|
+
// Initialize both
|
|
58
|
+
await initTracing({ serviceName: 'my-service' });
|
|
59
|
+
await startMetricsServer({ serviceName: 'my-service' });
|
|
60
|
+
|
|
61
|
+
// Use both together
|
|
62
|
+
await withSpan('process.request', async (span) => {
|
|
63
|
+
span.setAttribute('user.id', userId);
|
|
64
|
+
requestsTotal.inc({ method: 'GET', status: '200' });
|
|
65
|
+
return await processRequest();
|
|
66
|
+
});
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Tree-Shakeable Imports (Recommended)
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
// Import only what you need
|
|
73
|
+
import {
|
|
74
|
+
createCounter,
|
|
75
|
+
startMetricsServer,
|
|
76
|
+
} from '@manifest-cyber/observability-ts/metrics';
|
|
77
|
+
import { initTracing, withSpan } from '@manifest-cyber/observability-ts/tracing';
|
|
78
|
+
```
|
|
79
|
+
|
|
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
|
+
---
|
|
103
|
+
|
|
104
|
+
## ๐ Documentation
|
|
105
|
+
|
|
106
|
+
- **[TRACING_GUIDE.md](./TRACING_GUIDE.md)** - Comprehensive tracing guide with examples
|
|
107
|
+
- **[TRACING_IMPLEMENTATION_PLAN.md](./TRACING_IMPLEMENTATION_PLAN.md)** - Implementation roadmap and architecture
|
|
108
|
+
- **[MIGRATION_GUIDE.md](./MIGRATION_GUIDE.md)** - Migrating from @manifest-cyber/metrics
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## ๐ง API Reference
|
|
113
|
+
|
|
114
|
+
### Metrics API
|
|
115
|
+
|
|
116
|
+
#### Creating Metrics
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
import {
|
|
120
|
+
createCounter,
|
|
121
|
+
createHistogram,
|
|
122
|
+
createGauge,
|
|
123
|
+
} from '@manifest-cyber/observability-ts/metrics';
|
|
124
|
+
|
|
125
|
+
// Counter - Monotonically increasing value
|
|
126
|
+
const counter = createCounter({
|
|
127
|
+
name: 'operation_total',
|
|
128
|
+
help: 'Total operations',
|
|
129
|
+
labelNames: ['type', 'status'],
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// Histogram - Distribution of values
|
|
133
|
+
const histogram = createHistogram({
|
|
134
|
+
name: 'request_duration_seconds',
|
|
135
|
+
help: 'Request duration in seconds',
|
|
136
|
+
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
|
+
});
|
|
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
|
+
histogram.observe({ route: '/api/users', method: 'GET' }, 0.42);
|
|
156
|
+
|
|
157
|
+
// Gauge
|
|
158
|
+
gauge.inc(); // +1
|
|
159
|
+
gauge.dec(); // -1
|
|
160
|
+
gauge.set(42); // Set to specific value
|
|
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,
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
// Access metrics at http://localhost:9090/metrics
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Tracing API
|
|
198
|
+
|
|
199
|
+
#### Initialize Tracing
|
|
200
|
+
|
|
201
|
+
```typescript
|
|
202
|
+
import { initTracing } from '@manifest-cyber/observability-ts/tracing';
|
|
203
|
+
|
|
204
|
+
await initTracing({
|
|
205
|
+
serviceName: process.env.SERVICE_NAME || 'my-service',
|
|
206
|
+
exporter: {
|
|
207
|
+
type: 'otlp-grpc',
|
|
208
|
+
endpoint: process.env.OTEL_EXPORTER_OTLP_ENDPOINT || 'http://localhost:4317',
|
|
209
|
+
},
|
|
210
|
+
sampling: {
|
|
211
|
+
type: 'parentBased',
|
|
212
|
+
parentBased: {
|
|
213
|
+
root: { type: 'traceIdRatio', ratio: 0.1 }, // 10% sampling
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
});
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
#### Create Spans
|
|
220
|
+
|
|
221
|
+
```typescript
|
|
222
|
+
import {
|
|
223
|
+
withSpan,
|
|
224
|
+
createSpan,
|
|
225
|
+
getCurrentSpan,
|
|
226
|
+
} from '@manifest-cyber/observability-ts/tracing';
|
|
227
|
+
|
|
228
|
+
// Automatic span lifecycle
|
|
229
|
+
const result = await withSpan('database.query', async (span) => {
|
|
230
|
+
span.setAttribute('db.statement', 'SELECT * FROM users');
|
|
231
|
+
span.setAttribute('db.name', 'manifest');
|
|
232
|
+
return await db.query('SELECT * FROM users');
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
// Manual span management
|
|
236
|
+
const span = createSpan('manual.operation', { kind: SpanKind.INTERNAL });
|
|
237
|
+
try {
|
|
238
|
+
span.setAttribute('custom.attribute', 'value');
|
|
239
|
+
await doWork();
|
|
240
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
241
|
+
} catch (error) {
|
|
242
|
+
span.recordException(error);
|
|
243
|
+
span.setStatus({ code: SpanStatusCode.ERROR, message: error.message });
|
|
244
|
+
} finally {
|
|
245
|
+
span.end();
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Get current span
|
|
249
|
+
const activeSpan = getCurrentSpan();
|
|
250
|
+
activeSpan?.setAttribute('user.id', userId);
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
#### Trace Context Propagation
|
|
254
|
+
|
|
255
|
+
##### HTTP Propagation
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
import {
|
|
259
|
+
injectTraceContext,
|
|
260
|
+
extractTraceContext,
|
|
261
|
+
} from '@manifest-cyber/observability-ts/tracing';
|
|
262
|
+
|
|
263
|
+
// HTTP Client - Inject trace context
|
|
264
|
+
const headers: Record<string, string> = {};
|
|
265
|
+
injectTraceContext(headers);
|
|
266
|
+
|
|
267
|
+
await axios.get('https://api.example.com/users', { headers });
|
|
268
|
+
|
|
269
|
+
// HTTP Server - Extract trace context
|
|
270
|
+
app.use((req, res, next) => {
|
|
271
|
+
extractTraceContext(req.headers);
|
|
272
|
+
next();
|
|
273
|
+
});
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
##### Message Queue Propagation
|
|
277
|
+
|
|
278
|
+
```typescript
|
|
279
|
+
import {
|
|
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
|
+
});
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
// SQS Consumer - Extract trace context
|
|
294
|
+
extractMessageTraceContext(message.MessageAttributes);
|
|
295
|
+
await withSpan('sqs.process', async (span) => {
|
|
296
|
+
await processMessage(message);
|
|
297
|
+
});
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
#### Get Trace and Span IDs
|
|
301
|
+
|
|
302
|
+
```typescript
|
|
303
|
+
import {
|
|
304
|
+
getCurrentTraceId,
|
|
305
|
+
getCurrentSpanId,
|
|
306
|
+
} from '@manifest-cyber/observability-ts/tracing';
|
|
307
|
+
|
|
308
|
+
const traceId = getCurrentTraceId();
|
|
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
|
|
343
|
+
|
|
344
|
+
```typescript
|
|
345
|
+
import express from 'express';
|
|
346
|
+
import {
|
|
347
|
+
createCounter,
|
|
348
|
+
createHistogram,
|
|
349
|
+
startMetricsServer,
|
|
350
|
+
initTracing,
|
|
351
|
+
withSpan,
|
|
352
|
+
extractTraceContext,
|
|
353
|
+
injectTraceContext,
|
|
354
|
+
getCurrentTraceId,
|
|
355
|
+
} from '@manifest-cyber/observability-ts';
|
|
356
|
+
|
|
357
|
+
// Initialize observability
|
|
358
|
+
await initTracing({ serviceName: 'api-service' });
|
|
359
|
+
await startMetricsServer({ serviceName: 'api-service' });
|
|
360
|
+
|
|
361
|
+
// Create metrics
|
|
362
|
+
const httpRequests = createCounter({
|
|
363
|
+
name: 'http_requests_total',
|
|
364
|
+
help: 'Total HTTP requests',
|
|
365
|
+
labelNames: ['method', 'route', 'status'],
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
const httpDuration = createHistogram({
|
|
369
|
+
name: 'http_request_duration_seconds',
|
|
370
|
+
help: 'HTTP request duration in seconds',
|
|
371
|
+
labelNames: ['method', 'route', 'status'],
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
const app = express();
|
|
375
|
+
|
|
376
|
+
// Middleware - Extract trace context
|
|
377
|
+
app.use((req, res, next) => {
|
|
378
|
+
extractTraceContext(req.headers);
|
|
379
|
+
next();
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
// Middleware - Automatic instrumentation
|
|
383
|
+
app.use((req, res, next) => {
|
|
384
|
+
const start = Date.now();
|
|
385
|
+
|
|
386
|
+
res.on('finish', () => {
|
|
387
|
+
const duration = (Date.now() - start) / 1000;
|
|
388
|
+
const labels = {
|
|
389
|
+
method: req.method,
|
|
390
|
+
route: req.route?.path || req.path,
|
|
391
|
+
status: res.statusCode.toString(),
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
httpRequests.inc(labels);
|
|
395
|
+
httpDuration.observe(labels, duration);
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
next();
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
// Route handler with tracing
|
|
402
|
+
app.get('/api/users/:id', async (req, res) => {
|
|
403
|
+
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
|
+
span.setAttribute('user.id', req.params.id);
|
|
408
|
+
|
|
409
|
+
const user = await fetchUser(req.params.id);
|
|
410
|
+
res.json(user);
|
|
411
|
+
});
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
app.listen(3000);
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
### Job Worker with Message Queue Tracing
|
|
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!
|
|
612
|
+
|
|
613
|
+
```bash
|
|
614
|
+
npm uninstall @manifest-cyber/metrics
|
|
615
|
+
npm install @manifest-cyber/observability-ts
|
|
616
|
+
```
|
|
617
|
+
|
|
618
|
+
```typescript
|
|
619
|
+
// Before
|
|
620
|
+
import { createCounter } from '@manifest-cyber/metrics';
|
|
621
|
+
|
|
622
|
+
// After
|
|
623
|
+
import { createCounter } from '@manifest-cyber/observability-ts';
|
|
624
|
+
```
|
|
625
|
+
|
|
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
|
|
645
|
+
|
|
646
|
+
- **GitHub**: [manifest-cyber/observability-ts](https://github.com/manifest-cyber/observability-ts)
|
|
647
|
+
- **NPM**: [@manifest-cyber/observability-ts](https://www.npmjs.com/package/@manifest-cyber/observability-ts)
|
|
648
|
+
- **Issues**: [Report a bug](https://github.com/manifest-cyber/observability-ts/issues)
|
|
649
|
+
- **Documentation**:
|
|
650
|
+
- [Tracing Guide](./TRACING_GUIDE.md)
|
|
651
|
+
- [Implementation Plan](./TRACING_IMPLEMENTATION_PLAN.md)
|
|
652
|
+
- [Migration Guide](./MIGRATION_GUIDE.md)
|
|
653
|
+
|
|
654
|
+
---
|
|
655
|
+
|
|
656
|
+
**Package Version**: 0.2.0
|
|
657
|
+
**OpenTelemetry Version**: 1.28.0
|
|
658
|
+
**Last Updated**: November 11, 2025
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @manifest-cyber/observability-ts
|
|
3
|
+
*
|
|
4
|
+
* Unified observability library for Manifest Cyber services.
|
|
5
|
+
*
|
|
6
|
+
* This library provides:
|
|
7
|
+
* - **Metrics**: Prometheus metrics collection and exposition
|
|
8
|
+
* - **Tracing**: OpenTelemetry distributed tracing
|
|
9
|
+
*
|
|
10
|
+
* @example Metrics
|
|
11
|
+
* ```typescript
|
|
12
|
+
* import { createCounter, createHistogram, startMetricsServer } from '@manifest-cyber/observability-ts';
|
|
13
|
+
*
|
|
14
|
+
* const requestsTotal = createCounter({
|
|
15
|
+
* name: 'http_requests',
|
|
16
|
+
* help: 'Total HTTP requests',
|
|
17
|
+
* labelNames: ['method', 'status'],
|
|
18
|
+
* });
|
|
19
|
+
*
|
|
20
|
+
* startMetricsServer({ serviceName: 'my-service' });
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* @example Tracing
|
|
24
|
+
* ```typescript
|
|
25
|
+
* import { initTracing, withSpan } from '@manifest-cyber/observability-ts';
|
|
26
|
+
*
|
|
27
|
+
* await initTracing({
|
|
28
|
+
* serviceName: 'my-service',
|
|
29
|
+
* exporter: { endpoint: 'http://localhost:4317' }
|
|
30
|
+
* });
|
|
31
|
+
*
|
|
32
|
+
* const result = await withSpan('operation', async () => {
|
|
33
|
+
* return await doWork();
|
|
34
|
+
* });
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* @example Modular Imports (Tree-shakeable)
|
|
38
|
+
* ```typescript
|
|
39
|
+
* // Import only what you need
|
|
40
|
+
* import { createCounter } from '@manifest-cyber/observability-ts/metrics';
|
|
41
|
+
* import { initTracing } from '@manifest-cyber/observability-ts/tracing';
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export { getRegistry, resetRegistry } from './metrics/registry';
|
|
45
|
+
export { startMetricsServer } from './metrics/server';
|
|
46
|
+
export type { MetricsServerOptions } from './metrics/server';
|
|
47
|
+
export { createCounter, createHistogram, createGauge, BUCKETS, DURATION_BUCKETS, // Deprecated, use BUCKETS.DURATION
|
|
48
|
+
MetricNames, ENV_KEY_SERVICE_NAME, } from './metrics/builders';
|
|
49
|
+
export type { HistogramConfig } from './metrics/builders';
|
|
50
|
+
export { Timer, MetricsContext, instrumentAsync, trackOperation, } from './metrics/instrumentation';
|
|
51
|
+
export type { Counter, Histogram, Gauge, Registry } from 'prom-client';
|
|
52
|
+
export { initTracing, isTracingInitialized, getTracerProvider, shutdownTracing, } from './tracing/setup';
|
|
53
|
+
export { getTracer, createSpan, withSpan, withSpanResult, getCurrentSpan, getCurrentTraceId, getCurrentSpanId, addSpanEvent, setSpanAttributes, recordException, withActiveSpan, withActiveSpanAsync, } from './tracing/spans';
|
|
54
|
+
export { injectTraceContext, extractTraceContext, getTraceparent, parseTraceparent, createContextFromTraceparent, createMessageTraceContext, extractMessageTraceContext, withExtractedContext, withExtractedContextAsync, } from './tracing/context';
|
|
55
|
+
export type { Span, Tracer, Context, SpanAttributes } from '@opentelemetry/api';
|
|
56
|
+
export { SpanStatusCode, SpanKind } from '@opentelemetry/api';
|
|
57
|
+
export type { ServiceMetricsConfig, MetricLabels, DurationMetricOptions, Logger, } from './types';
|
|
58
|
+
export type { TracingConfig, ExporterConfig, SamplingConfig, SpanOptions, TracedResult, HttpSpanAttributes, DbSpanAttributes, MessagingSpanAttributes, } from './tracing/types';
|
|
59
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAOH,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGhE,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,YAAY,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAG7D,OAAO,EACL,aAAa,EACb,eAAe,EACf,WAAW,EACX,OAAO,EACP,gBAAgB,EAAE,mCAAmC;AACrD,WAAW,EACX,oBAAoB,GACrB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAG1D,OAAO,EACL,KAAK,EACL,cAAc,EACd,eAAe,EACf,cAAc,GACf,MAAM,2BAA2B,CAAC;AAGnC,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAOvE,OAAO,EACL,WAAW,EACX,oBAAoB,EACpB,iBAAiB,EACjB,eAAe,GAChB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EACL,SAAS,EACT,UAAU,EACV,QAAQ,EACR,cAAc,EACd,cAAc,EACd,iBAAiB,EACjB,gBAAgB,EAChB,YAAY,EACZ,iBAAiB,EACjB,eAAe,EACf,cAAc,EACd,mBAAmB,GACpB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,cAAc,EACd,gBAAgB,EAChB,4BAA4B,EAC5B,yBAAyB,EACzB,0BAA0B,EAC1B,oBAAoB,EACpB,yBAAyB,GAC1B,MAAM,mBAAmB,CAAC;AAG3B,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAChF,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAM9D,YAAY,EACV,oBAAoB,EACpB,YAAY,EACZ,qBAAqB,EACrB,MAAM,GACP,MAAM,SAAS,CAAC;AAEjB,YAAY,EACV,aAAa,EACb,cAAc,EACd,cAAc,EACd,WAAW,EACX,YAAY,EACZ,kBAAkB,EAClB,gBAAgB,EAChB,uBAAuB,GACxB,MAAM,iBAAiB,CAAC"}
|