@semiont/observability 0.5.4 → 0.5.6
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/dist/index.d.ts +24 -20
- package/dist/node.d.ts +6 -4
- package/dist/process-logger.d.ts +6 -3
- package/dist/web.d.ts +5 -3
- package/package.json +14 -12
- package/dist/index.d.ts.map +0 -1
- package/dist/node.d.ts.map +0 -1
- package/dist/process-logger.d.ts.map +0 -1
- package/dist/web.d.ts.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { Span, Attributes, SpanKind } from '@opentelemetry/api';
|
|
2
|
+
export { Attributes, Span, SpanKind, SpanStatusCode } from '@opentelemetry/api';
|
|
3
|
+
|
|
1
4
|
/**
|
|
2
5
|
* @semiont/observability — public API.
|
|
3
6
|
*
|
|
@@ -21,13 +24,13 @@
|
|
|
21
24
|
* tracer is a no-op, so `withSpan` is essentially free until
|
|
22
25
|
* `initObservability*()` runs.
|
|
23
26
|
*/
|
|
24
|
-
|
|
27
|
+
|
|
25
28
|
/**
|
|
26
29
|
* Wrap an async block in a span. The span is started before `fn` runs and
|
|
27
30
|
* ended after it resolves or rejects; exceptions are recorded and the span
|
|
28
31
|
* status is set to ERROR. `kind` defaults to INTERNAL.
|
|
29
32
|
*/
|
|
30
|
-
|
|
33
|
+
declare function withSpan<T>(name: string, fn: (span: Span) => Promise<T> | T, options?: {
|
|
31
34
|
kind?: SpanKind;
|
|
32
35
|
attrs?: Attributes;
|
|
33
36
|
}): Promise<T>;
|
|
@@ -37,7 +40,7 @@ export declare function withSpan<T>(name: string, fn: (span: Span) => Promise<T>
|
|
|
37
40
|
* the payload to subscribers. Additive — payloads without `_trace` parse
|
|
38
41
|
* unchanged.
|
|
39
42
|
*/
|
|
40
|
-
|
|
43
|
+
interface TraceCarrier {
|
|
41
44
|
/** W3C `traceparent` header value (`00-<traceId>-<spanId>-<flags>`). */
|
|
42
45
|
traceparent: string;
|
|
43
46
|
/** W3C `tracestate` header value (vendor-specific extensions). */
|
|
@@ -47,24 +50,24 @@ export interface TraceCarrier {
|
|
|
47
50
|
* Read the active span's W3C traceparent (and tracestate). Returns
|
|
48
51
|
* `undefined` if no span is active.
|
|
49
52
|
*/
|
|
50
|
-
|
|
53
|
+
declare function getActiveTraceparent(): TraceCarrier | undefined;
|
|
51
54
|
/**
|
|
52
55
|
* Attach the active span's trace-context to a payload object as
|
|
53
56
|
* `_trace`. No-op when no span is active. Returns the same object
|
|
54
57
|
* reference for chaining.
|
|
55
58
|
*/
|
|
56
|
-
|
|
59
|
+
declare function injectTraceparent<T extends Record<string, unknown>>(payload: T): T;
|
|
57
60
|
/**
|
|
58
61
|
* Strip and return the `_trace` field from a payload. Mutates `payload`.
|
|
59
62
|
* The field is internal plumbing and should not be visible to subscribers.
|
|
60
63
|
*/
|
|
61
|
-
|
|
64
|
+
declare function extractTraceparent<T extends Record<string, unknown>>(payload: T): TraceCarrier | undefined;
|
|
62
65
|
/**
|
|
63
66
|
* Run `fn` with the given W3C traceparent set as the parent context.
|
|
64
67
|
* Any spans started inside `fn` will be children of the incoming trace.
|
|
65
68
|
* No-op if `carrier` is undefined.
|
|
66
69
|
*/
|
|
67
|
-
|
|
70
|
+
declare function withTraceparent<T>(carrier: TraceCarrier | undefined, fn: () => T): T;
|
|
68
71
|
/**
|
|
69
72
|
* Wrap a bus-event handler in an `actor.<name>:<channel>` consumer span.
|
|
70
73
|
* Used at every `eventBus.get(channel).subscribe(handler)` site inside
|
|
@@ -77,7 +80,7 @@ export declare function withTraceparent<T>(carrier: TraceCarrier | undefined, fn
|
|
|
77
80
|
* (Subject.next runs synchronously inside the dispatch span), or the
|
|
78
81
|
* `bus.emit:<channel>` span when an actor emits to itself.
|
|
79
82
|
*/
|
|
80
|
-
|
|
83
|
+
declare function withActorSpan<T>(actor: string, channel: string, fn: (span: Span) => Promise<T> | T, extraAttrs?: Attributes): Promise<T>;
|
|
81
84
|
/**
|
|
82
85
|
* Read the active span's `trace_id` / `span_id` for log-line correlation.
|
|
83
86
|
* Tier 3 of `.plans/OBSERVABILITY.md`. Each structured log line gets
|
|
@@ -87,12 +90,12 @@ export declare function withActorSpan<T>(actor: string, channel: string, fn: (sp
|
|
|
87
90
|
* Returns `undefined` if no span is active, or if the active span's
|
|
88
91
|
* context is invalid (uninitialized SDK, no-op tracer).
|
|
89
92
|
*/
|
|
90
|
-
|
|
93
|
+
declare function getLogTraceContext(): {
|
|
91
94
|
trace_id: string;
|
|
92
95
|
span_id: string;
|
|
93
96
|
} | undefined;
|
|
94
97
|
/** Snapshot of job-queue contents by status. Match `JobQueue.getStats()`. */
|
|
95
|
-
|
|
98
|
+
interface JobQueueSnapshot {
|
|
96
99
|
pending: number;
|
|
97
100
|
running: number;
|
|
98
101
|
complete: number;
|
|
@@ -100,15 +103,15 @@ export interface JobQueueSnapshot {
|
|
|
100
103
|
cancelled: number;
|
|
101
104
|
}
|
|
102
105
|
/** Increment the bus-emit counter. Called at every transport `emit` site. */
|
|
103
|
-
|
|
106
|
+
declare function recordBusEmit(channel: string, scope?: string): void;
|
|
104
107
|
/** Record an in-process actor handler's duration. */
|
|
105
|
-
|
|
108
|
+
declare function recordHandlerDuration(actor: string, channel: string, durationMs: number): void;
|
|
106
109
|
/** Record a worker job's outcome and duration. */
|
|
107
|
-
|
|
110
|
+
declare function recordJobOutcome(jobType: string, outcome: 'completed' | 'failed', durationMs: number): void;
|
|
108
111
|
/** Increment the SSE subscriber gauge — call on `/bus/subscribe` open. */
|
|
109
|
-
|
|
112
|
+
declare function recordSubscriberConnect(): void;
|
|
110
113
|
/** Decrement on disconnect. Pair with `recordSubscriberConnect`. */
|
|
111
|
-
|
|
114
|
+
declare function recordSubscriberDisconnect(): void;
|
|
112
115
|
/**
|
|
113
116
|
* Register a callback that returns the current job-queue snapshot.
|
|
114
117
|
* Polled at the SDK's metric-collection interval. The single gauge
|
|
@@ -116,19 +119,19 @@ export declare function recordSubscriberDisconnect(): void;
|
|
|
116
119
|
* with the `job.status` attribute. Idempotent — last registered
|
|
117
120
|
* provider wins.
|
|
118
121
|
*/
|
|
119
|
-
|
|
122
|
+
declare function registerJobQueueProvider(provider: () => Promise<JobQueueSnapshot> | JobQueueSnapshot): void;
|
|
120
123
|
/**
|
|
121
124
|
* Register a callback that returns the current vector-index size
|
|
122
125
|
* (point count). Async to allow remote queries (Qdrant). Polled at
|
|
123
126
|
* the metric-collection interval.
|
|
124
127
|
*/
|
|
125
|
-
|
|
128
|
+
declare function registerVectorIndexSizeProvider(provider: () => Promise<number> | number): void;
|
|
126
129
|
/**
|
|
127
130
|
* Record an inference call. Token counts are optional — providers that
|
|
128
131
|
* don't expose them (or fail before generating) record only call count
|
|
129
132
|
* and duration.
|
|
130
133
|
*/
|
|
131
|
-
|
|
134
|
+
declare function recordInferenceUsage(opts: {
|
|
132
135
|
provider: string;
|
|
133
136
|
model: string;
|
|
134
137
|
durationMs: number;
|
|
@@ -136,5 +139,6 @@ export declare function recordInferenceUsage(opts: {
|
|
|
136
139
|
inputTokens?: number;
|
|
137
140
|
outputTokens?: number;
|
|
138
141
|
}): void;
|
|
139
|
-
|
|
140
|
-
|
|
142
|
+
|
|
143
|
+
export { extractTraceparent, getActiveTraceparent, getLogTraceContext, injectTraceparent, recordBusEmit, recordHandlerDuration, recordInferenceUsage, recordJobOutcome, recordSubscriberConnect, recordSubscriberDisconnect, registerJobQueueProvider, registerVectorIndexSizeProvider, withActorSpan, withSpan, withTraceparent };
|
|
144
|
+
export type { JobQueueSnapshot, TraceCarrier };
|
package/dist/node.d.ts
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
* SDKs, forcing npm to nest duplicate copies of the stable packages and
|
|
25
25
|
* blowing up bundles for every consumer.
|
|
26
26
|
*/
|
|
27
|
-
|
|
27
|
+
interface NodeObservabilityConfig {
|
|
28
28
|
/** Service identity (e.g. `semiont-backend`). Overridden by `OTEL_SERVICE_NAME`. */
|
|
29
29
|
serviceName: string;
|
|
30
30
|
/** Service version. Defaults to `0.0.0` if omitted. */
|
|
@@ -39,7 +39,9 @@ export interface NodeObservabilityConfig {
|
|
|
39
39
|
* Metrics export at `OTEL_METRIC_EXPORT_INTERVAL` ms (default 30s) to
|
|
40
40
|
* the same `OTEL_EXPORTER_OTLP_ENDPOINT` as traces.
|
|
41
41
|
*/
|
|
42
|
-
|
|
42
|
+
declare function initObservabilityNode(config: NodeObservabilityConfig): boolean;
|
|
43
43
|
/** Force-flush + shutdown both SDKs. Test cleanup, not production. */
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
declare function shutdownObservabilityNode(): Promise<void>;
|
|
45
|
+
|
|
46
|
+
export { initObservabilityNode, shutdownObservabilityNode };
|
|
47
|
+
export type { NodeObservabilityConfig };
|
package/dist/process-logger.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { Logger } from '@semiont/core';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Process-level structured logger for Node entry points.
|
|
3
5
|
*
|
|
@@ -15,6 +17,7 @@
|
|
|
15
17
|
* only reasonably-shaped consumer of that helper, and putting them in
|
|
16
18
|
* the same package keeps the trace-id wiring in one place.
|
|
17
19
|
*/
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
|
|
21
|
+
declare function createProcessLogger(component: string): Logger;
|
|
22
|
+
|
|
23
|
+
export { createProcessLogger };
|
package/dist/web.d.ts
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* Without an `otlpEndpoint`, falls back to a console exporter (visible
|
|
11
11
|
* in DevTools).
|
|
12
12
|
*/
|
|
13
|
-
|
|
13
|
+
interface WebObservabilityConfig {
|
|
14
14
|
/** Service identity (e.g. `semiont-frontend`). */
|
|
15
15
|
serviceName: string;
|
|
16
16
|
/** Service version. */
|
|
@@ -32,5 +32,7 @@ export interface WebObservabilityConfig {
|
|
|
32
32
|
* Initialize OTel for the SPA. Idempotent. Returns `true` if the SDK
|
|
33
33
|
* started, `false` if disabled or already initialized.
|
|
34
34
|
*/
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
declare function initObservabilityWeb(config: WebObservabilityConfig): boolean;
|
|
36
|
+
|
|
37
|
+
export { initObservabilityWeb };
|
|
38
|
+
export type { WebObservabilityConfig };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@semiont/observability",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.6",
|
|
4
4
|
"description": "OpenTelemetry-based tracing for Semiont — Tier 2 of OBSERVABILITY.md. Process-init helpers (Node + Web), withSpan helper, W3C traceparent inject/extract for bus payloads. No-op when no exporter is configured.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
}
|
|
29
29
|
},
|
|
30
30
|
"engines": {
|
|
31
|
-
"node": ">=
|
|
31
|
+
"node": ">=24.0.0"
|
|
32
32
|
},
|
|
33
33
|
"files": [
|
|
34
34
|
"dist",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"scripts": {
|
|
47
47
|
"pretypecheck": "npm run build --workspace=@semiont/core --if-present",
|
|
48
48
|
"typecheck": "tsc --noEmit",
|
|
49
|
-
"build": "npm run typecheck && tsup && tsc -p tsconfig.build.json",
|
|
49
|
+
"build": "npm run typecheck && tsup && tsc -p tsconfig.build.json && rollup -c rollup.dts.config.mjs && rm -rf dist-types",
|
|
50
50
|
"watch": "tsup --watch",
|
|
51
51
|
"clean": "rm -rf dist *.tsbuildinfo",
|
|
52
52
|
"test": "vitest run",
|
|
@@ -55,22 +55,24 @@
|
|
|
55
55
|
"author": "Semiont Team",
|
|
56
56
|
"license": "Apache-2.0",
|
|
57
57
|
"devDependencies": {
|
|
58
|
+
"rollup": "^4.61.0",
|
|
59
|
+
"rollup-plugin-dts": "^6.4.1",
|
|
58
60
|
"tsup": "^8.5.1",
|
|
59
61
|
"typescript": "^6.0.2",
|
|
60
|
-
"vitest": "^4.1.
|
|
62
|
+
"vitest": "^4.1.8"
|
|
61
63
|
},
|
|
62
64
|
"dependencies": {
|
|
63
|
-
"@opentelemetry/api": "^1.9.
|
|
64
|
-
"@
|
|
65
|
-
"@opentelemetry/
|
|
66
|
-
"@opentelemetry/
|
|
67
|
-
"@opentelemetry/exporter-
|
|
68
|
-
"@opentelemetry/exporter-trace-otlp-http": "^0.215.0",
|
|
65
|
+
"@opentelemetry/api": "^1.9.1",
|
|
66
|
+
"@opentelemetry/context-async-hooks": "^2.7.1",
|
|
67
|
+
"@opentelemetry/core": "^2.7.1",
|
|
68
|
+
"@opentelemetry/exporter-metrics-otlp-http": "^0.218.0",
|
|
69
|
+
"@opentelemetry/exporter-trace-otlp-http": "^0.218.0",
|
|
69
70
|
"@opentelemetry/resources": "^2.7.0",
|
|
70
71
|
"@opentelemetry/sdk-metrics": "^2.7.0",
|
|
71
72
|
"@opentelemetry/sdk-trace-base": "^2.7.0",
|
|
72
|
-
"@opentelemetry/sdk-trace-web": "^2.7.
|
|
73
|
-
"@opentelemetry/semantic-conventions": "^1.
|
|
73
|
+
"@opentelemetry/sdk-trace-web": "^2.7.1",
|
|
74
|
+
"@opentelemetry/semantic-conventions": "^1.41.1",
|
|
75
|
+
"@semiont/core": "*",
|
|
74
76
|
"winston": "^3.17.0"
|
|
75
77
|
}
|
|
76
78
|
}
|
package/dist/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/node.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAuBH,MAAM,WAAW,uBAAuB;IACtC,oFAAoF;IACpF,WAAW,EAAE,MAAM,CAAC;IACpB,uDAAuD;IACvD,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAWD;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,uBAAuB,GAAG,OAAO,CAyE9E;AAED,sEAAsE;AACtE,wBAAsB,yBAAyB,IAAI,OAAO,CAAC,IAAI,CAAC,CAO/D"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"process-logger.d.ts","sourceRoot":"","sources":["../src/process-logger.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAY5C,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CA2B7D"}
|
package/dist/web.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"web.d.ts","sourceRoot":"","sources":["../src/web.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAcH,MAAM,WAAW,sBAAsB;IACrC,kDAAkD;IAClD,WAAW,EAAE,MAAM,CAAC;IACpB,uBAAuB;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,6CAA6C;IAC7C,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAID;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAwB5E"}
|