@payloops/observability 0.0.1 → 0.0.5
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/package.json +12 -2
- package/.env.example +0 -4
- package/.github/workflows/ci.yml +0 -38
- package/.github/workflows/publish.yml +0 -40
- package/src/index.ts +0 -56
- package/src/lib/context.ts +0 -90
- package/src/lib/logger.ts +0 -77
- package/src/lib/metrics.ts +0 -146
- package/src/lib/otel.ts +0 -75
- package/tsconfig.json +0 -16
package/package.json
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@payloops/observability",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"type": "module",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/payloops/observability"
|
|
8
|
+
},
|
|
5
9
|
"main": "dist/index.js",
|
|
6
10
|
"types": "dist/index.d.ts",
|
|
11
|
+
"files": [
|
|
12
|
+
"dist"
|
|
13
|
+
],
|
|
7
14
|
"exports": {
|
|
8
15
|
".": {
|
|
9
16
|
"import": "./dist/index.js",
|
|
@@ -13,7 +20,10 @@
|
|
|
13
20
|
"scripts": {
|
|
14
21
|
"build": "tsup src/index.ts --format esm --dts",
|
|
15
22
|
"lint": "eslint src/",
|
|
16
|
-
"typecheck": "tsc --noEmit"
|
|
23
|
+
"typecheck": "tsc --noEmit",
|
|
24
|
+
"release": "npm run build && npm run typecheck && npm version patch && git push && git push --tags",
|
|
25
|
+
"release:minor": "npm run build && npm run typecheck && npm version minor && git push && git push --tags",
|
|
26
|
+
"release:major": "npm run build && npm run typecheck && npm version major && git push && git push --tags"
|
|
17
27
|
},
|
|
18
28
|
"dependencies": {
|
|
19
29
|
"@opentelemetry/api": "^1.9.0",
|
package/.env.example
DELETED
package/.github/workflows/ci.yml
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
name: CI
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches: [main]
|
|
6
|
-
pull_request:
|
|
7
|
-
branches: [main]
|
|
8
|
-
|
|
9
|
-
jobs:
|
|
10
|
-
build:
|
|
11
|
-
runs-on: ubuntu-latest
|
|
12
|
-
|
|
13
|
-
steps:
|
|
14
|
-
- uses: actions/checkout@v4
|
|
15
|
-
|
|
16
|
-
- uses: pnpm/action-setup@v4
|
|
17
|
-
with:
|
|
18
|
-
version: 9
|
|
19
|
-
|
|
20
|
-
- uses: actions/setup-node@v4
|
|
21
|
-
with:
|
|
22
|
-
node-version: '22'
|
|
23
|
-
cache: 'pnpm'
|
|
24
|
-
|
|
25
|
-
- name: Update npm to latest
|
|
26
|
-
run: npm install -g npm@latest
|
|
27
|
-
|
|
28
|
-
- name: Install dependencies
|
|
29
|
-
run: pnpm install
|
|
30
|
-
|
|
31
|
-
- name: Type check
|
|
32
|
-
run: pnpm typecheck
|
|
33
|
-
|
|
34
|
-
- name: Lint
|
|
35
|
-
run: pnpm lint
|
|
36
|
-
|
|
37
|
-
- name: Build
|
|
38
|
-
run: pnpm build
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
name: Publish to npm
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
release:
|
|
5
|
-
types: [created]
|
|
6
|
-
|
|
7
|
-
jobs:
|
|
8
|
-
publish:
|
|
9
|
-
runs-on: ubuntu-latest
|
|
10
|
-
|
|
11
|
-
permissions:
|
|
12
|
-
contents: read
|
|
13
|
-
id-token: write
|
|
14
|
-
|
|
15
|
-
steps:
|
|
16
|
-
- uses: actions/checkout@v4
|
|
17
|
-
|
|
18
|
-
- uses: pnpm/action-setup@v4
|
|
19
|
-
with:
|
|
20
|
-
version: 9
|
|
21
|
-
|
|
22
|
-
- uses: actions/setup-node@v4
|
|
23
|
-
with:
|
|
24
|
-
node-version: '22'
|
|
25
|
-
cache: 'pnpm'
|
|
26
|
-
registry-url: 'https://registry.npmjs.org'
|
|
27
|
-
|
|
28
|
-
- name: Update npm to latest
|
|
29
|
-
run: npm install -g npm@latest
|
|
30
|
-
|
|
31
|
-
- name: Install dependencies
|
|
32
|
-
run: pnpm install
|
|
33
|
-
|
|
34
|
-
- name: Build
|
|
35
|
-
run: pnpm build
|
|
36
|
-
|
|
37
|
-
- name: Publish to npm with provenance
|
|
38
|
-
run: npm publish --access public --provenance
|
|
39
|
-
env:
|
|
40
|
-
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
package/src/index.ts
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
// OpenTelemetry
|
|
2
|
-
export { initTelemetry, shutdownTelemetry, type TelemetryConfig } from './lib/otel';
|
|
3
|
-
|
|
4
|
-
// Logger
|
|
5
|
-
export { logger, createActivityLogger, createWorkflowLogger, createRequestLogger } from './lib/logger';
|
|
6
|
-
|
|
7
|
-
// Correlation Context
|
|
8
|
-
export {
|
|
9
|
-
getCorrelationContext,
|
|
10
|
-
withCorrelationContext,
|
|
11
|
-
withCorrelationContextAsync,
|
|
12
|
-
generateCorrelationId,
|
|
13
|
-
extractCorrelationId,
|
|
14
|
-
createPropagationHeaders,
|
|
15
|
-
createContextFromMemo,
|
|
16
|
-
CORRELATION_ID_HEADER,
|
|
17
|
-
REQUEST_ID_HEADER,
|
|
18
|
-
type CorrelationContext
|
|
19
|
-
} from './lib/context';
|
|
20
|
-
|
|
21
|
-
// Metrics
|
|
22
|
-
export {
|
|
23
|
-
// Payment metrics
|
|
24
|
-
paymentCounter,
|
|
25
|
-
paymentAmountHistogram,
|
|
26
|
-
paymentLatencyHistogram,
|
|
27
|
-
recordPaymentAttempt,
|
|
28
|
-
recordPaymentAmount,
|
|
29
|
-
recordPaymentLatency,
|
|
30
|
-
|
|
31
|
-
// Webhook metrics
|
|
32
|
-
webhookDeliveryCounter,
|
|
33
|
-
webhookLatencyHistogram,
|
|
34
|
-
recordWebhookDelivery,
|
|
35
|
-
recordWebhookLatency,
|
|
36
|
-
|
|
37
|
-
// HTTP metrics
|
|
38
|
-
httpRequestCounter,
|
|
39
|
-
httpRequestLatencyHistogram,
|
|
40
|
-
activeRequestsGauge,
|
|
41
|
-
recordHttpRequest,
|
|
42
|
-
|
|
43
|
-
// Database metrics
|
|
44
|
-
dbQueryHistogram,
|
|
45
|
-
dbConnectionGauge,
|
|
46
|
-
|
|
47
|
-
// Workflow metrics
|
|
48
|
-
workflowStartedCounter,
|
|
49
|
-
workflowCompletedCounter,
|
|
50
|
-
workflowFailedCounter,
|
|
51
|
-
activityLatencyHistogram,
|
|
52
|
-
recordWorkflowStarted,
|
|
53
|
-
recordWorkflowCompleted,
|
|
54
|
-
recordWorkflowFailed,
|
|
55
|
-
recordActivityLatency
|
|
56
|
-
} from './lib/metrics';
|
package/src/lib/context.ts
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { AsyncLocalStorage } from 'async_hooks';
|
|
2
|
-
import { nanoid } from 'nanoid';
|
|
3
|
-
import { context, propagation } from '@opentelemetry/api';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Correlation context for tracking requests across services
|
|
7
|
-
*/
|
|
8
|
-
export interface CorrelationContext {
|
|
9
|
-
correlationId: string;
|
|
10
|
-
merchantId?: string;
|
|
11
|
-
orderId?: string;
|
|
12
|
-
workflowId?: string;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const correlationStorage = new AsyncLocalStorage<CorrelationContext>();
|
|
16
|
-
|
|
17
|
-
// Standard headers for correlation
|
|
18
|
-
export const CORRELATION_ID_HEADER = 'X-Correlation-ID';
|
|
19
|
-
export const REQUEST_ID_HEADER = 'X-Request-ID';
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Get the current correlation context
|
|
23
|
-
*/
|
|
24
|
-
export function getCorrelationContext(): CorrelationContext | undefined {
|
|
25
|
-
return correlationStorage.getStore();
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Run a function with a correlation context
|
|
30
|
-
*/
|
|
31
|
-
export function withCorrelationContext<T>(ctx: CorrelationContext, fn: () => T): T {
|
|
32
|
-
return correlationStorage.run(ctx, fn);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Run an async function with a correlation context
|
|
37
|
-
*/
|
|
38
|
-
export async function withCorrelationContextAsync<T>(ctx: CorrelationContext, fn: () => Promise<T>): Promise<T> {
|
|
39
|
-
return correlationStorage.run(ctx, fn);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Generate a new correlation ID
|
|
44
|
-
*/
|
|
45
|
-
export function generateCorrelationId(): string {
|
|
46
|
-
return nanoid(21);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Extract correlation ID from headers (case-insensitive)
|
|
51
|
-
*/
|
|
52
|
-
export function extractCorrelationId(headers: Record<string, string | undefined>): string {
|
|
53
|
-
// Normalize header keys to lowercase for lookup
|
|
54
|
-
const normalizedHeaders: Record<string, string | undefined> = {};
|
|
55
|
-
for (const [key, value] of Object.entries(headers)) {
|
|
56
|
-
normalizedHeaders[key.toLowerCase()] = value;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
return (
|
|
60
|
-
normalizedHeaders[CORRELATION_ID_HEADER.toLowerCase()] ||
|
|
61
|
-
normalizedHeaders[REQUEST_ID_HEADER.toLowerCase()] ||
|
|
62
|
-
generateCorrelationId()
|
|
63
|
-
);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Create headers for propagating correlation context to downstream services
|
|
68
|
-
*/
|
|
69
|
-
export function createPropagationHeaders(correlationId: string): Record<string, string> {
|
|
70
|
-
const headers: Record<string, string> = {
|
|
71
|
-
[CORRELATION_ID_HEADER]: correlationId
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
// Inject OpenTelemetry trace context
|
|
75
|
-
propagation.inject(context.active(), headers);
|
|
76
|
-
|
|
77
|
-
return headers;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Create correlation context from Temporal workflow memo
|
|
82
|
-
*/
|
|
83
|
-
export function createContextFromMemo(memo: Record<string, unknown>): CorrelationContext {
|
|
84
|
-
return {
|
|
85
|
-
correlationId: (memo.correlationId as string) || generateCorrelationId(),
|
|
86
|
-
merchantId: memo.merchantId as string | undefined,
|
|
87
|
-
orderId: memo.orderId as string | undefined,
|
|
88
|
-
workflowId: memo.workflowId as string | undefined
|
|
89
|
-
};
|
|
90
|
-
}
|
package/src/lib/logger.ts
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import pino from 'pino';
|
|
2
|
-
import { trace } from '@opentelemetry/api';
|
|
3
|
-
import { getCorrelationContext } from './context';
|
|
4
|
-
|
|
5
|
-
const NODE_ENV = process.env.NODE_ENV || 'development';
|
|
6
|
-
const SERVICE_NAME = process.env.OTEL_SERVICE_NAME || 'loop';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Mixin that adds trace context to every log entry
|
|
10
|
-
*/
|
|
11
|
-
const traceMixin = () => {
|
|
12
|
-
const mixinData: Record<string, string | undefined> = {};
|
|
13
|
-
|
|
14
|
-
// Add OpenTelemetry trace context
|
|
15
|
-
const span = trace.getActiveSpan();
|
|
16
|
-
if (span) {
|
|
17
|
-
const spanContext = span.spanContext();
|
|
18
|
-
mixinData.trace_id = spanContext.traceId;
|
|
19
|
-
mixinData.span_id = spanContext.spanId;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// Add correlation context
|
|
23
|
-
const correlationCtx = getCorrelationContext();
|
|
24
|
-
if (correlationCtx) {
|
|
25
|
-
mixinData.correlation_id = correlationCtx.correlationId;
|
|
26
|
-
if (correlationCtx.merchantId) mixinData.merchant_id = correlationCtx.merchantId;
|
|
27
|
-
if (correlationCtx.orderId) mixinData.order_id = correlationCtx.orderId;
|
|
28
|
-
if (correlationCtx.workflowId) mixinData.workflow_id = correlationCtx.workflowId;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
return mixinData;
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Base logger with trace context mixin
|
|
36
|
-
*/
|
|
37
|
-
export const logger = pino({
|
|
38
|
-
level: NODE_ENV === 'production' ? 'info' : 'debug',
|
|
39
|
-
mixin: traceMixin,
|
|
40
|
-
base: {
|
|
41
|
-
service: SERVICE_NAME,
|
|
42
|
-
env: NODE_ENV
|
|
43
|
-
},
|
|
44
|
-
timestamp: pino.stdTimeFunctions.isoTime,
|
|
45
|
-
transport: NODE_ENV !== 'production' ? { target: 'pino-pretty', options: { colorize: true } } : undefined
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Create a child logger for a specific activity
|
|
50
|
-
*/
|
|
51
|
-
export function createActivityLogger(activityName: string, correlationId?: string) {
|
|
52
|
-
return logger.child({
|
|
53
|
-
activity: activityName,
|
|
54
|
-
correlationId
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Create a child logger for a specific workflow
|
|
60
|
-
*/
|
|
61
|
-
export function createWorkflowLogger(workflowId: string, correlationId?: string) {
|
|
62
|
-
return logger.child({
|
|
63
|
-
workflowId,
|
|
64
|
-
correlationId
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Create a child logger for HTTP requests
|
|
70
|
-
*/
|
|
71
|
-
export function createRequestLogger(requestId: string, method: string, path: string) {
|
|
72
|
-
return logger.child({
|
|
73
|
-
requestId,
|
|
74
|
-
method,
|
|
75
|
-
path
|
|
76
|
-
});
|
|
77
|
-
}
|
package/src/lib/metrics.ts
DELETED
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
import { metrics, ValueType } from '@opentelemetry/api';
|
|
2
|
-
|
|
3
|
-
// Create a meter for the application
|
|
4
|
-
const meter = metrics.getMeter('payloops');
|
|
5
|
-
|
|
6
|
-
// =============================================================================
|
|
7
|
-
// Payment Metrics
|
|
8
|
-
// =============================================================================
|
|
9
|
-
|
|
10
|
-
export const paymentCounter = meter.createCounter('payments_total', {
|
|
11
|
-
description: 'Total number of payment attempts',
|
|
12
|
-
valueType: ValueType.INT
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
export const paymentAmountHistogram = meter.createHistogram('payment_amount', {
|
|
16
|
-
description: 'Distribution of payment amounts',
|
|
17
|
-
unit: 'cents',
|
|
18
|
-
valueType: ValueType.INT
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
export const paymentLatencyHistogram = meter.createHistogram('payment_latency_ms', {
|
|
22
|
-
description: 'Payment processing latency',
|
|
23
|
-
unit: 'ms',
|
|
24
|
-
valueType: ValueType.DOUBLE
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
// =============================================================================
|
|
28
|
-
// Webhook Metrics
|
|
29
|
-
// =============================================================================
|
|
30
|
-
|
|
31
|
-
export const webhookDeliveryCounter = meter.createCounter('webhook_deliveries_total', {
|
|
32
|
-
description: 'Total webhook delivery attempts',
|
|
33
|
-
valueType: ValueType.INT
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
export const webhookLatencyHistogram = meter.createHistogram('webhook_latency_ms', {
|
|
37
|
-
description: 'Webhook delivery latency',
|
|
38
|
-
unit: 'ms',
|
|
39
|
-
valueType: ValueType.DOUBLE
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
// =============================================================================
|
|
43
|
-
// HTTP Metrics
|
|
44
|
-
// =============================================================================
|
|
45
|
-
|
|
46
|
-
export const httpRequestCounter = meter.createCounter('http_requests_total', {
|
|
47
|
-
description: 'Total HTTP requests',
|
|
48
|
-
valueType: ValueType.INT
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
export const httpRequestLatencyHistogram = meter.createHistogram('http_request_latency_ms', {
|
|
52
|
-
description: 'HTTP request latency',
|
|
53
|
-
unit: 'ms',
|
|
54
|
-
valueType: ValueType.DOUBLE
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
export const activeRequestsGauge = meter.createUpDownCounter('http_active_requests', {
|
|
58
|
-
description: 'Number of active HTTP requests',
|
|
59
|
-
valueType: ValueType.INT
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
// =============================================================================
|
|
63
|
-
// Database Metrics
|
|
64
|
-
// =============================================================================
|
|
65
|
-
|
|
66
|
-
export const dbQueryHistogram = meter.createHistogram('db_query_duration_ms', {
|
|
67
|
-
description: 'Database query duration',
|
|
68
|
-
unit: 'ms',
|
|
69
|
-
valueType: ValueType.DOUBLE
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
export const dbConnectionGauge = meter.createUpDownCounter('db_connections_active', {
|
|
73
|
-
description: 'Number of active database connections',
|
|
74
|
-
valueType: ValueType.INT
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
// =============================================================================
|
|
78
|
-
// Temporal Workflow Metrics
|
|
79
|
-
// =============================================================================
|
|
80
|
-
|
|
81
|
-
export const workflowStartedCounter = meter.createCounter('workflow_started_total', {
|
|
82
|
-
description: 'Total workflows started',
|
|
83
|
-
valueType: ValueType.INT
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
export const workflowCompletedCounter = meter.createCounter('workflow_completed_total', {
|
|
87
|
-
description: 'Total workflows completed',
|
|
88
|
-
valueType: ValueType.INT
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
export const workflowFailedCounter = meter.createCounter('workflow_failed_total', {
|
|
92
|
-
description: 'Total workflows failed',
|
|
93
|
-
valueType: ValueType.INT
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
export const activityLatencyHistogram = meter.createHistogram('activity_latency_ms', {
|
|
97
|
-
description: 'Activity execution latency',
|
|
98
|
-
unit: 'ms',
|
|
99
|
-
valueType: ValueType.DOUBLE
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
// =============================================================================
|
|
103
|
-
// Helper Functions
|
|
104
|
-
// =============================================================================
|
|
105
|
-
|
|
106
|
-
export function recordPaymentAttempt(processor: string, currency: string, status: 'success' | 'failed' | 'pending') {
|
|
107
|
-
paymentCounter.add(1, { processor, currency, status });
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
export function recordPaymentAmount(amount: number, processor: string, currency: string) {
|
|
111
|
-
paymentAmountHistogram.record(amount, { processor, currency });
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
export function recordPaymentLatency(durationMs: number, processor: string, status: 'success' | 'failed') {
|
|
115
|
-
paymentLatencyHistogram.record(durationMs, { processor, status });
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
export function recordWebhookDelivery(status: 'success' | 'failed', attempt: number) {
|
|
119
|
-
webhookDeliveryCounter.add(1, { status, attempt: String(attempt) });
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
export function recordWebhookLatency(durationMs: number, status: 'success' | 'failed') {
|
|
123
|
-
webhookLatencyHistogram.record(durationMs, { status });
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
export function recordHttpRequest(method: string, path: string, statusCode: number, durationMs: number) {
|
|
127
|
-
const statusClass = `${Math.floor(statusCode / 100)}xx`;
|
|
128
|
-
httpRequestCounter.add(1, { method, path, status_code: String(statusCode), status_class: statusClass });
|
|
129
|
-
httpRequestLatencyHistogram.record(durationMs, { method, path, status_class: statusClass });
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
export function recordWorkflowStarted(workflowType: string, taskQueue: string) {
|
|
133
|
-
workflowStartedCounter.add(1, { workflow_type: workflowType, task_queue: taskQueue });
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
export function recordWorkflowCompleted(workflowType: string, taskQueue: string, durationMs: number) {
|
|
137
|
-
workflowCompletedCounter.add(1, { workflow_type: workflowType, task_queue: taskQueue });
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
export function recordWorkflowFailed(workflowType: string, taskQueue: string, errorType: string) {
|
|
141
|
-
workflowFailedCounter.add(1, { workflow_type: workflowType, task_queue: taskQueue, error_type: errorType });
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
export function recordActivityLatency(activityType: string, durationMs: number, status: 'success' | 'failed') {
|
|
145
|
-
activityLatencyHistogram.record(durationMs, { activity_type: activityType, status });
|
|
146
|
-
}
|
package/src/lib/otel.ts
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import { NodeSDK } from '@opentelemetry/sdk-node';
|
|
2
|
-
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
|
|
3
|
-
import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http';
|
|
4
|
-
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
|
|
5
|
-
import { Resource } from '@opentelemetry/resources';
|
|
6
|
-
import { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } from '@opentelemetry/semantic-conventions';
|
|
7
|
-
import { PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics';
|
|
8
|
-
|
|
9
|
-
let sdk: NodeSDK | null = null;
|
|
10
|
-
|
|
11
|
-
export interface TelemetryConfig {
|
|
12
|
-
serviceName: string;
|
|
13
|
-
serviceVersion?: string;
|
|
14
|
-
otlpEndpoint?: string;
|
|
15
|
-
environment?: string;
|
|
16
|
-
enabledInstrumentations?: {
|
|
17
|
-
fs?: boolean;
|
|
18
|
-
http?: boolean;
|
|
19
|
-
pg?: boolean;
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export function initTelemetry(config: TelemetryConfig | string, serviceVersion = '0.0.1'): NodeSDK {
|
|
24
|
-
if (sdk) return sdk;
|
|
25
|
-
|
|
26
|
-
// Support both string (legacy) and config object
|
|
27
|
-
const cfg: TelemetryConfig =
|
|
28
|
-
typeof config === 'string' ? { serviceName: config, serviceVersion } : config;
|
|
29
|
-
|
|
30
|
-
const otlpEndpoint = cfg.otlpEndpoint || process.env.OTEL_EXPORTER_OTLP_ENDPOINT || 'http://localhost:4318';
|
|
31
|
-
const environment = cfg.environment || process.env.NODE_ENV || 'development';
|
|
32
|
-
|
|
33
|
-
sdk = new NodeSDK({
|
|
34
|
-
resource: new Resource({
|
|
35
|
-
[ATTR_SERVICE_NAME]: cfg.serviceName,
|
|
36
|
-
[ATTR_SERVICE_VERSION]: cfg.serviceVersion || '0.0.1',
|
|
37
|
-
'deployment.environment': environment
|
|
38
|
-
}),
|
|
39
|
-
|
|
40
|
-
traceExporter: new OTLPTraceExporter({
|
|
41
|
-
url: `${otlpEndpoint}/v1/traces`
|
|
42
|
-
}),
|
|
43
|
-
|
|
44
|
-
metricReader: new PeriodicExportingMetricReader({
|
|
45
|
-
exporter: new OTLPMetricExporter({
|
|
46
|
-
url: `${otlpEndpoint}/v1/metrics`
|
|
47
|
-
}),
|
|
48
|
-
exportIntervalMillis: 30000
|
|
49
|
-
}),
|
|
50
|
-
|
|
51
|
-
instrumentations: [
|
|
52
|
-
getNodeAutoInstrumentations({
|
|
53
|
-
'@opentelemetry/instrumentation-fs': { enabled: cfg.enabledInstrumentations?.fs ?? false },
|
|
54
|
-
'@opentelemetry/instrumentation-http': { enabled: cfg.enabledInstrumentations?.http ?? true },
|
|
55
|
-
'@opentelemetry/instrumentation-pg': { enabled: cfg.enabledInstrumentations?.pg ?? true }
|
|
56
|
-
})
|
|
57
|
-
]
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
sdk.start();
|
|
61
|
-
|
|
62
|
-
process.on('SIGTERM', () => {
|
|
63
|
-
sdk
|
|
64
|
-
?.shutdown()
|
|
65
|
-
.then(() => console.log('Telemetry shut down'))
|
|
66
|
-
.catch((err) => console.error('Telemetry shutdown error', err));
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
return sdk;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export function shutdownTelemetry(): Promise<void> {
|
|
73
|
-
if (!sdk) return Promise.resolve();
|
|
74
|
-
return sdk.shutdown();
|
|
75
|
-
}
|
package/tsconfig.json
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2022",
|
|
4
|
-
"module": "ESNext",
|
|
5
|
-
"moduleResolution": "bundler",
|
|
6
|
-
"lib": ["ES2022"],
|
|
7
|
-
"strict": true,
|
|
8
|
-
"esModuleInterop": true,
|
|
9
|
-
"skipLibCheck": true,
|
|
10
|
-
"declaration": true,
|
|
11
|
-
"outDir": "dist",
|
|
12
|
-
"rootDir": "src"
|
|
13
|
-
},
|
|
14
|
-
"include": ["src/**/*"],
|
|
15
|
-
"exclude": ["node_modules", "dist"]
|
|
16
|
-
}
|