@origintrail-official/dkg-node-ui 10.0.1 → 10.0.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/dist/chain-cursor-stores.d.ts +45 -0
- package/dist/chain-cursor-stores.d.ts.map +1 -0
- package/dist/chain-cursor-stores.js +107 -0
- package/dist/chain-cursor-stores.js.map +1 -0
- package/dist/chat-memory.d.ts +0 -17
- package/dist/chat-memory.d.ts.map +1 -1
- package/dist/chat-memory.js +6 -33
- package/dist/chat-memory.js.map +1 -1
- package/dist/db.d.ts +15 -0
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +40 -1
- package/dist/db.js.map +1 -1
- package/dist/index.d.ts +6 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -2
- package/dist/index.js.map +1 -1
- package/dist/notifications-scope.d.ts +19 -0
- package/dist/notifications-scope.d.ts.map +1 -1
- package/dist/notifications-scope.js +34 -2
- package/dist/notifications-scope.js.map +1 -1
- package/dist/otlp-log-worker.d.ts +127 -0
- package/dist/otlp-log-worker.d.ts.map +1 -0
- package/dist/otlp-log-worker.js +268 -0
- package/dist/otlp-log-worker.js.map +1 -0
- package/dist/telemetry-resource.d.ts +41 -0
- package/dist/telemetry-resource.d.ts.map +1 -0
- package/dist/telemetry-resource.js +31 -0
- package/dist/telemetry-resource.js.map +1 -0
- package/dist/telemetry.d.ts +75 -16
- package/dist/telemetry.d.ts.map +1 -1
- package/dist/telemetry.js +152 -29
- package/dist/telemetry.js.map +1 -1
- package/dist-ui/assets/{3d-force-graph-DII0C0lY.js → 3d-force-graph-DRDhpplH.js} +1 -1
- package/dist-ui/assets/AgentHub-DdUAxJoy.js +1 -0
- package/dist-ui/assets/AgentProfilePage-yI8fA4vv.js +1 -0
- package/dist-ui/assets/ApproveWalletsModal-9w2edv7e.js +57 -0
- package/dist-ui/assets/ConvictionDetailView-CcQMya-y.js +2 -0
- package/dist-ui/assets/Network-DpAKVzwi.js +1 -0
- package/dist-ui/assets/OnChainProvenanceCard-DMOm3jLz.js +1 -0
- package/dist-ui/assets/{Operations-BC6Cv6cR.js → Operations-DKJFp6hM.js} +3 -3
- package/dist-ui/assets/PublishingConviction-1CPHxNwp.js +2 -0
- package/dist-ui/assets/Settings-DaYMlGHD.js +1 -0
- package/dist-ui/assets/ccip-hCQYqfNz.js +1 -0
- package/dist-ui/assets/{index-D0Mz0SVt.js → index-Bh_8bMB0.js} +3 -3
- package/dist-ui/assets/{index-ByLJSVQ3.js → index-CVwCoJrM.js} +9 -9
- package/dist-ui/assets/index-D5UiTYlY.css +1 -0
- package/dist-ui/assets/index-DGpnb_b1.js +1661 -0
- package/dist-ui/assets/{jsonld-32FQRO67-B4_tUX65.js → jsonld-32FQRO67-C3B_LjZ-.js} +2 -2
- package/dist-ui/assets/{jsonld-D5RXTCJi.js → jsonld-CoPRWQuM.js} +1 -1
- package/dist-ui/assets/{renderer-3d-2EVDZII7-BTYEjwma.js → renderer-3d-2EVDZII7-Bx6o7Gge.js} +2 -2
- package/dist-ui/index.html +2 -2
- package/package.json +14 -3
- package/dist-ui/assets/AgentHub-D3eOrb3Z.js +0 -1
- package/dist-ui/assets/AgentProfilePage-jB-v9soG.js +0 -1
- package/dist-ui/assets/Network-d4igcZQ0.js +0 -1
- package/dist-ui/assets/OnChainProvenanceCard-BL6ou6s9.js +0 -1
- package/dist-ui/assets/Settings-DXSjvx2a.js +0 -1
- package/dist-ui/assets/index-B6UQm9N_.js +0 -1670
- package/dist-ui/assets/index-BgRu6zNc.css +0 -1
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OTLP/HTTP log exporter — ships structured log records to an OpenTelemetry
|
|
3
|
+
* collector (or any OTLP/HTTP logs endpoint) as a second, opt-in sink
|
|
4
|
+
* alongside the always-on local SQLite store.
|
|
5
|
+
*
|
|
6
|
+
* Why hand-rolled rather than @opentelemetry/sdk-logs: as of 2026 the OTel JS
|
|
7
|
+
* Logs SDK is still "Development" (Traces/Metrics are Stable). We emit the
|
|
8
|
+
* stable OTLP/HTTP JSON wire format (ExportLogsServiceRequest) directly and
|
|
9
|
+
* reuse the buffer/flush/backoff shape proven by the syslog LogPushWorker.
|
|
10
|
+
*
|
|
11
|
+
* Reliability contract (this must NEVER slow down or crash the node):
|
|
12
|
+
* - push() only appends to a bounded in-memory buffer (drop-oldest on
|
|
13
|
+
* overflow) and returns immediately; it never awaits the network.
|
|
14
|
+
* - flush() runs on a timer, is guarded against overlap, and swallows every
|
|
15
|
+
* error. On a retryable failure the batch is requeued and an exponential
|
|
16
|
+
* backoff (with jitter, honoring Retry-After) is applied. On a
|
|
17
|
+
* non-retryable failure the batch is dropped (logged once).
|
|
18
|
+
* - The flush timer is unref'd so it never keeps the process alive.
|
|
19
|
+
* - Transport is outbound HTTPS push only — no inbound scrape endpoint.
|
|
20
|
+
*/
|
|
21
|
+
import type { LogRecord } from '@origintrail-official/dkg-core';
|
|
22
|
+
export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
23
|
+
export interface OtlpLogWorkerOptions {
|
|
24
|
+
/** Full OTLP/HTTP logs URL, e.g. http://localhost:4318/v1/logs */
|
|
25
|
+
endpoint: string;
|
|
26
|
+
/** Bearer credential for the collector (sent as Authorization: Bearer …). */
|
|
27
|
+
token?: string;
|
|
28
|
+
/** Extra static headers to attach to every request. */
|
|
29
|
+
headers?: Record<string, string>;
|
|
30
|
+
/** Network identifier: 'testnet' | 'mainnet' | 'devnet'. */
|
|
31
|
+
network: string;
|
|
32
|
+
/** Node's libp2p peer ID. */
|
|
33
|
+
peerId: string;
|
|
34
|
+
nodeName?: string;
|
|
35
|
+
version?: string;
|
|
36
|
+
commit?: string;
|
|
37
|
+
/** 'core' | 'edge' */
|
|
38
|
+
role?: string;
|
|
39
|
+
/** Chain id string, e.g. 'base:8453' → resource attr dkg.chain (matches traces/metrics). */
|
|
40
|
+
chainId?: string;
|
|
41
|
+
/** OTel resource service.name. Default 'dkg-node'. */
|
|
42
|
+
serviceName?: string;
|
|
43
|
+
/**
|
|
44
|
+
* Per-node identifier. Becomes the OTel `service.instance.id`, which Loki
|
|
45
|
+
* promotes to the index label `service_instance_id` — this is what a Grafana
|
|
46
|
+
* "pick a node" dashboard variable selects on. Defaults to nodeName, then
|
|
47
|
+
* peerId. Hosted nodes should set a unique `name` in config.
|
|
48
|
+
*/
|
|
49
|
+
serviceInstanceId?: string;
|
|
50
|
+
/**
|
|
51
|
+
* Deployment environment (e.g. 'testnet' | 'mainnet'). Becomes the OTel
|
|
52
|
+
* `deployment.environment`, which Loki promotes to the label
|
|
53
|
+
* `deployment_environment`. Defaults to `network`.
|
|
54
|
+
*/
|
|
55
|
+
deploymentEnvironment?: string;
|
|
56
|
+
/** Minimum level forwarded remotely. Default 'info' (debug stays local). */
|
|
57
|
+
minLevel?: LogLevel;
|
|
58
|
+
/** Bounded in-memory buffer; drop-oldest on overflow. Default 500. */
|
|
59
|
+
bufferMaxEntries?: number;
|
|
60
|
+
flushIntervalMs?: number;
|
|
61
|
+
requestTimeoutMs?: number;
|
|
62
|
+
/** Initial retry backoff in ms (doubles up to maxBackoffMs). Default 1000. */
|
|
63
|
+
baseBackoffMs?: number;
|
|
64
|
+
/** Ceiling for retry backoff in ms. Default 60000. */
|
|
65
|
+
maxBackoffMs?: number;
|
|
66
|
+
/** Optional diagnostic sink (e.g. the daemon log). Never throws. */
|
|
67
|
+
onError?: (message: string) => void;
|
|
68
|
+
}
|
|
69
|
+
interface OtlpAttribute {
|
|
70
|
+
key: string;
|
|
71
|
+
value: {
|
|
72
|
+
stringValue: string;
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
export declare class OtlpLogWorker {
|
|
76
|
+
private buffer;
|
|
77
|
+
private timer;
|
|
78
|
+
private stopped;
|
|
79
|
+
private flushing;
|
|
80
|
+
private nextAttemptAt;
|
|
81
|
+
private backoffMs;
|
|
82
|
+
private droppedNonRetryable;
|
|
83
|
+
private loggedNonRetryable;
|
|
84
|
+
private readonly endpoint;
|
|
85
|
+
private readonly minRank;
|
|
86
|
+
private readonly maxBuffer;
|
|
87
|
+
private readonly flushIntervalMs;
|
|
88
|
+
private readonly requestTimeoutMs;
|
|
89
|
+
private readonly baseBackoffMs;
|
|
90
|
+
private readonly maxBackoffMs;
|
|
91
|
+
private readonly authHeaders;
|
|
92
|
+
private readonly resourceAttrs;
|
|
93
|
+
private readonly scopeVersion;
|
|
94
|
+
private readonly onError;
|
|
95
|
+
constructor(opts: OtlpLogWorkerOptions);
|
|
96
|
+
/** Append a record. Filters below minLevel; never awaits the network. */
|
|
97
|
+
push(record: LogRecord): void;
|
|
98
|
+
start(): void;
|
|
99
|
+
stop(): void;
|
|
100
|
+
/**
|
|
101
|
+
* Async teardown for the daemon shutdown / telemetry-disable path: stop the
|
|
102
|
+
* timer and AWAIT a final flush, so the caller can guarantee no batch is still
|
|
103
|
+
* being sent (or stranded in the buffer) once this resolves. stop() is the
|
|
104
|
+
* fire-and-forget variant for callers that can't await.
|
|
105
|
+
*/
|
|
106
|
+
shutdown(): Promise<void>;
|
|
107
|
+
/** Test/diagnostic hook. */
|
|
108
|
+
pending(): number;
|
|
109
|
+
private flush;
|
|
110
|
+
private requeue;
|
|
111
|
+
private scheduleBackoff;
|
|
112
|
+
private post;
|
|
113
|
+
private buildPayload;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* PURE OTLP/HTTP logs wire-format encoder (ExportLogsServiceRequest JSON).
|
|
117
|
+
* Extracted from `OtlpLogWorker` so the protocol/payload shape is independent
|
|
118
|
+
* from the worker's scheduling + retry/backoff mechanics (review: "OtlpLogWorker
|
|
119
|
+
* mixes too many concerns") — change the wire shape here without touching the
|
|
120
|
+
* buffer/timer logic, and vice-versa. No side effects, no `this`.
|
|
121
|
+
*/
|
|
122
|
+
export declare function encodeOtlpLogPayload(batch: ReadonlyArray<{
|
|
123
|
+
r: LogRecord;
|
|
124
|
+
tsMs: number;
|
|
125
|
+
}>, resourceAttrs: ReadonlyArray<OtlpAttribute>, scopeVersion?: string): string;
|
|
126
|
+
export {};
|
|
127
|
+
//# sourceMappingURL=otlp-log-worker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"otlp-log-worker.d.ts","sourceRoot":"","sources":["../src/otlp-log-worker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OTLP/HTTP log exporter — ships structured log records to an OpenTelemetry
|
|
3
|
+
* collector (or any OTLP/HTTP logs endpoint) as a second, opt-in sink
|
|
4
|
+
* alongside the always-on local SQLite store.
|
|
5
|
+
*
|
|
6
|
+
* Why hand-rolled rather than @opentelemetry/sdk-logs: as of 2026 the OTel JS
|
|
7
|
+
* Logs SDK is still "Development" (Traces/Metrics are Stable). We emit the
|
|
8
|
+
* stable OTLP/HTTP JSON wire format (ExportLogsServiceRequest) directly and
|
|
9
|
+
* reuse the buffer/flush/backoff shape proven by the syslog LogPushWorker.
|
|
10
|
+
*
|
|
11
|
+
* Reliability contract (this must NEVER slow down or crash the node):
|
|
12
|
+
* - push() only appends to a bounded in-memory buffer (drop-oldest on
|
|
13
|
+
* overflow) and returns immediately; it never awaits the network.
|
|
14
|
+
* - flush() runs on a timer, is guarded against overlap, and swallows every
|
|
15
|
+
* error. On a retryable failure the batch is requeued and an exponential
|
|
16
|
+
* backoff (with jitter, honoring Retry-After) is applied. On a
|
|
17
|
+
* non-retryable failure the batch is dropped (logged once).
|
|
18
|
+
* - The flush timer is unref'd so it never keeps the process alive.
|
|
19
|
+
* - Transport is outbound HTTPS push only — no inbound scrape endpoint.
|
|
20
|
+
*/
|
|
21
|
+
import { buildTelemetryResourceAttrs } from './telemetry-resource.js';
|
|
22
|
+
// OpenTelemetry severity numbers (logs data model).
|
|
23
|
+
const OTEL_SEVERITY = {
|
|
24
|
+
debug: { num: 5, text: 'DEBUG' },
|
|
25
|
+
info: { num: 9, text: 'INFO' },
|
|
26
|
+
warn: { num: 13, text: 'WARN' },
|
|
27
|
+
error: { num: 17, text: 'ERROR' },
|
|
28
|
+
};
|
|
29
|
+
const LEVEL_RANK = { debug: 0, info: 1, warn: 2, error: 3 };
|
|
30
|
+
const RETRYABLE_STATUS = new Set([408, 429, 500, 502, 503, 504]);
|
|
31
|
+
const DEFAULTS = {
|
|
32
|
+
flushIntervalMs: 2_000,
|
|
33
|
+
maxBuffer: 500,
|
|
34
|
+
maxBatch: 256,
|
|
35
|
+
requestTimeoutMs: 10_000,
|
|
36
|
+
baseBackoffMs: 1_000,
|
|
37
|
+
maxBackoffMs: 60_000,
|
|
38
|
+
serviceName: 'dkg-node',
|
|
39
|
+
minLevel: 'info',
|
|
40
|
+
};
|
|
41
|
+
function attr(key, value) {
|
|
42
|
+
if (value == null || value === '')
|
|
43
|
+
return null;
|
|
44
|
+
return { key, value: { stringValue: String(value) } };
|
|
45
|
+
}
|
|
46
|
+
export class OtlpLogWorker {
|
|
47
|
+
buffer = [];
|
|
48
|
+
timer = null;
|
|
49
|
+
stopped = false;
|
|
50
|
+
flushing = false;
|
|
51
|
+
nextAttemptAt = 0;
|
|
52
|
+
backoffMs = 0;
|
|
53
|
+
droppedNonRetryable = 0;
|
|
54
|
+
loggedNonRetryable = false;
|
|
55
|
+
endpoint;
|
|
56
|
+
minRank;
|
|
57
|
+
maxBuffer;
|
|
58
|
+
flushIntervalMs;
|
|
59
|
+
requestTimeoutMs;
|
|
60
|
+
baseBackoffMs;
|
|
61
|
+
maxBackoffMs;
|
|
62
|
+
authHeaders;
|
|
63
|
+
resourceAttrs;
|
|
64
|
+
scopeVersion;
|
|
65
|
+
onError;
|
|
66
|
+
constructor(opts) {
|
|
67
|
+
this.endpoint = opts.endpoint;
|
|
68
|
+
this.minRank = LEVEL_RANK[opts.minLevel ?? DEFAULTS.minLevel] ?? LEVEL_RANK.info;
|
|
69
|
+
this.maxBuffer = Math.max(1, opts.bufferMaxEntries ?? DEFAULTS.maxBuffer);
|
|
70
|
+
this.flushIntervalMs = opts.flushIntervalMs ?? DEFAULTS.flushIntervalMs;
|
|
71
|
+
this.requestTimeoutMs = opts.requestTimeoutMs ?? DEFAULTS.requestTimeoutMs;
|
|
72
|
+
this.baseBackoffMs = opts.baseBackoffMs ?? DEFAULTS.baseBackoffMs;
|
|
73
|
+
this.maxBackoffMs = opts.maxBackoffMs ?? DEFAULTS.maxBackoffMs;
|
|
74
|
+
this.scopeVersion = opts.version || undefined;
|
|
75
|
+
this.onError = opts.onError ?? (() => { });
|
|
76
|
+
this.authHeaders = { 'content-type': 'application/json', ...(opts.headers ?? {}) };
|
|
77
|
+
if (opts.token)
|
|
78
|
+
this.authHeaders['authorization'] = `Bearer ${opts.token}`;
|
|
79
|
+
// Built from the SHARED resource model so the log resource (and the Loki
|
|
80
|
+
// labels promoted from service.name / service.instance.id /
|
|
81
|
+
// deployment.environment / dkg.node.role) can never drift from the
|
|
82
|
+
// traces/metrics resource. See ./telemetry-resource.
|
|
83
|
+
this.resourceAttrs = Object.entries(buildTelemetryResourceAttrs({
|
|
84
|
+
serviceName: opts.serviceName ?? DEFAULTS.serviceName,
|
|
85
|
+
serviceVersion: opts.version,
|
|
86
|
+
serviceInstanceId: opts.serviceInstanceId,
|
|
87
|
+
deploymentEnvironment: opts.deploymentEnvironment,
|
|
88
|
+
network: opts.network,
|
|
89
|
+
peerId: opts.peerId,
|
|
90
|
+
nodeName: opts.nodeName,
|
|
91
|
+
nodeRole: opts.role,
|
|
92
|
+
commit: opts.commit,
|
|
93
|
+
chainId: opts.chainId,
|
|
94
|
+
})).map(([key, value]) => ({ key, value: { stringValue: value } }));
|
|
95
|
+
}
|
|
96
|
+
/** Append a record. Filters below minLevel; never awaits the network. */
|
|
97
|
+
push(record) {
|
|
98
|
+
if ((LEVEL_RANK[record.level] ?? LEVEL_RANK.info) < this.minRank)
|
|
99
|
+
return;
|
|
100
|
+
if (this.buffer.length >= this.maxBuffer)
|
|
101
|
+
this.buffer.shift();
|
|
102
|
+
this.buffer.push({ r: record, tsMs: Date.now() });
|
|
103
|
+
}
|
|
104
|
+
start() {
|
|
105
|
+
if (this.timer)
|
|
106
|
+
return;
|
|
107
|
+
this.stopped = false;
|
|
108
|
+
this.timer = setInterval(() => {
|
|
109
|
+
void this.flush();
|
|
110
|
+
}, this.flushIntervalMs);
|
|
111
|
+
this.timer.unref();
|
|
112
|
+
}
|
|
113
|
+
stop() {
|
|
114
|
+
this.stopped = true;
|
|
115
|
+
if (this.timer) {
|
|
116
|
+
clearInterval(this.timer);
|
|
117
|
+
this.timer = null;
|
|
118
|
+
}
|
|
119
|
+
// Best-effort final flush; failures are swallowed. Fire-and-forget — use
|
|
120
|
+
// shutdown() when you need to AWAIT the final flush (orderly teardown).
|
|
121
|
+
void this.flush(true);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Async teardown for the daemon shutdown / telemetry-disable path: stop the
|
|
125
|
+
* timer and AWAIT a final flush, so the caller can guarantee no batch is still
|
|
126
|
+
* being sent (or stranded in the buffer) once this resolves. stop() is the
|
|
127
|
+
* fire-and-forget variant for callers that can't await.
|
|
128
|
+
*/
|
|
129
|
+
async shutdown() {
|
|
130
|
+
this.stopped = true;
|
|
131
|
+
if (this.timer) {
|
|
132
|
+
clearInterval(this.timer);
|
|
133
|
+
this.timer = null;
|
|
134
|
+
}
|
|
135
|
+
await this.flush(true).catch(() => { });
|
|
136
|
+
}
|
|
137
|
+
/** Test/diagnostic hook. */
|
|
138
|
+
pending() {
|
|
139
|
+
return this.buffer.length;
|
|
140
|
+
}
|
|
141
|
+
async flush(force = false) {
|
|
142
|
+
if (this.flushing)
|
|
143
|
+
return;
|
|
144
|
+
if (this.stopped && !force)
|
|
145
|
+
return;
|
|
146
|
+
if (this.buffer.length === 0)
|
|
147
|
+
return;
|
|
148
|
+
if (!force && Date.now() < this.nextAttemptAt)
|
|
149
|
+
return;
|
|
150
|
+
this.flushing = true;
|
|
151
|
+
const batch = this.buffer.splice(0, DEFAULTS.maxBatch);
|
|
152
|
+
try {
|
|
153
|
+
const body = this.buildPayload(batch);
|
|
154
|
+
const res = await this.post(body);
|
|
155
|
+
if (res.ok) {
|
|
156
|
+
this.backoffMs = 0;
|
|
157
|
+
this.nextAttemptAt = 0;
|
|
158
|
+
}
|
|
159
|
+
else if (RETRYABLE_STATUS.has(res.status)) {
|
|
160
|
+
this.requeue(batch);
|
|
161
|
+
this.scheduleBackoff(res.retryAfterMs);
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
// Non-retryable (e.g. 400/401/403): dropping is correct — retrying
|
|
165
|
+
// a malformed/unauthorized request forever would just grow the buffer.
|
|
166
|
+
this.droppedNonRetryable += batch.length;
|
|
167
|
+
if (!this.loggedNonRetryable) {
|
|
168
|
+
this.loggedNonRetryable = true;
|
|
169
|
+
this.onError(`dropping logs — collector returned ${res.status} (non-retryable); check endpoint/token. ` +
|
|
170
|
+
`${this.droppedNonRetryable} record(s) dropped so far.`);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
catch (err) {
|
|
175
|
+
// Network/timeout error → treat as retryable.
|
|
176
|
+
this.requeue(batch);
|
|
177
|
+
this.scheduleBackoff();
|
|
178
|
+
void err;
|
|
179
|
+
}
|
|
180
|
+
finally {
|
|
181
|
+
this.flushing = false;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
requeue(batch) {
|
|
185
|
+
this.buffer.unshift(...batch);
|
|
186
|
+
while (this.buffer.length > this.maxBuffer)
|
|
187
|
+
this.buffer.shift();
|
|
188
|
+
}
|
|
189
|
+
scheduleBackoff(retryAfterMs) {
|
|
190
|
+
const next = this.backoffMs === 0 ? this.baseBackoffMs : Math.min(this.backoffMs * 2, this.maxBackoffMs);
|
|
191
|
+
this.backoffMs = next;
|
|
192
|
+
const jitter = next * 0.2 * Math.random();
|
|
193
|
+
const delay = retryAfterMs != null ? Math.max(retryAfterMs, next) : next + jitter;
|
|
194
|
+
this.nextAttemptAt = Date.now() + delay;
|
|
195
|
+
}
|
|
196
|
+
async post(body) {
|
|
197
|
+
const ac = new AbortController();
|
|
198
|
+
const timer = setTimeout(() => ac.abort(), this.requestTimeoutMs);
|
|
199
|
+
try {
|
|
200
|
+
const res = await fetch(this.endpoint, {
|
|
201
|
+
method: 'POST',
|
|
202
|
+
headers: this.authHeaders,
|
|
203
|
+
body,
|
|
204
|
+
signal: ac.signal,
|
|
205
|
+
});
|
|
206
|
+
// Drain the body so the socket can be reused / freed.
|
|
207
|
+
await res.arrayBuffer().catch(() => { });
|
|
208
|
+
let retryAfterMs;
|
|
209
|
+
const ra = res.headers.get('retry-after');
|
|
210
|
+
if (ra) {
|
|
211
|
+
const secs = Number(ra);
|
|
212
|
+
if (!Number.isNaN(secs))
|
|
213
|
+
retryAfterMs = secs * 1000;
|
|
214
|
+
}
|
|
215
|
+
return { ok: res.ok, status: res.status, retryAfterMs };
|
|
216
|
+
}
|
|
217
|
+
finally {
|
|
218
|
+
clearTimeout(timer);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
buildPayload(batch) {
|
|
222
|
+
return encodeOtlpLogPayload(batch, this.resourceAttrs, this.scopeVersion);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* PURE OTLP/HTTP logs wire-format encoder (ExportLogsServiceRequest JSON).
|
|
227
|
+
* Extracted from `OtlpLogWorker` so the protocol/payload shape is independent
|
|
228
|
+
* from the worker's scheduling + retry/backoff mechanics (review: "OtlpLogWorker
|
|
229
|
+
* mixes too many concerns") — change the wire shape here without touching the
|
|
230
|
+
* buffer/timer logic, and vice-versa. No side effects, no `this`.
|
|
231
|
+
*/
|
|
232
|
+
export function encodeOtlpLogPayload(batch, resourceAttrs, scopeVersion) {
|
|
233
|
+
const logRecords = batch.map(({ r, tsMs }) => {
|
|
234
|
+
const sev = OTEL_SEVERITY[r.level] ?? OTEL_SEVERITY.info;
|
|
235
|
+
const nano = String(tsMs * 1_000_000);
|
|
236
|
+
return {
|
|
237
|
+
timeUnixNano: nano,
|
|
238
|
+
observedTimeUnixNano: nano,
|
|
239
|
+
severityNumber: sev.num,
|
|
240
|
+
severityText: sev.text,
|
|
241
|
+
body: { stringValue: r.message },
|
|
242
|
+
// W3C trace correlation — OTLP top-level fields (hex), not attributes.
|
|
243
|
+
// Present only when the log was emitted inside a recording span.
|
|
244
|
+
...(r.traceId ? { traceId: r.traceId } : {}),
|
|
245
|
+
...(r.spanId ? { spanId: r.spanId } : {}),
|
|
246
|
+
attributes: [
|
|
247
|
+
attr('dkg.operation_id', r.operationId),
|
|
248
|
+
attr('dkg.operation_name', r.operationName),
|
|
249
|
+
attr('dkg.source_operation_id', r.sourceOperationId),
|
|
250
|
+
attr('dkg.module', r.module),
|
|
251
|
+
].filter((a) => a !== null),
|
|
252
|
+
};
|
|
253
|
+
});
|
|
254
|
+
return JSON.stringify({
|
|
255
|
+
resourceLogs: [
|
|
256
|
+
{
|
|
257
|
+
resource: { attributes: resourceAttrs },
|
|
258
|
+
scopeLogs: [
|
|
259
|
+
{
|
|
260
|
+
scope: { name: 'dkg-node', version: scopeVersion },
|
|
261
|
+
logRecords,
|
|
262
|
+
},
|
|
263
|
+
],
|
|
264
|
+
},
|
|
265
|
+
],
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
//# sourceMappingURL=otlp-log-worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"otlp-log-worker.js","sourceRoot":"","sources":["../src/otlp-log-worker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE one canonical node-identity → OTel resource-attribute mapping, shared by
|
|
3
|
+
* BOTH the hand-rolled log exporter (`OtlpLogWorker`) and the OTel SDK bootstrap
|
|
4
|
+
* (`telemetry.ts`). Keeping a single builder is the whole point: logs, traces,
|
|
5
|
+
* and metrics describe the same node, so a key/default must change in exactly
|
|
6
|
+
* one place or Loki labels, trace resources, and metric resources silently drift
|
|
7
|
+
* apart (review: "resource identity is duplicated between logs and traces/metrics").
|
|
8
|
+
*
|
|
9
|
+
* Pure (no OTel SDK, no Node built-ins) → safe to import from anywhere.
|
|
10
|
+
*/
|
|
11
|
+
export interface TelemetryResourceInput {
|
|
12
|
+
/** OTel service.name. Default 'dkg-node'. */
|
|
13
|
+
serviceName?: string;
|
|
14
|
+
/** OTel service.version (node build version). */
|
|
15
|
+
serviceVersion?: string;
|
|
16
|
+
/**
|
|
17
|
+
* Per-node id → service.instance.id (the Grafana node selector / Loki
|
|
18
|
+
* `service_instance_id` label). Falls back to nodeName then peerId so logs and
|
|
19
|
+
* traces/metrics resolve the SAME instance id even if a caller omits it.
|
|
20
|
+
*/
|
|
21
|
+
serviceInstanceId?: string;
|
|
22
|
+
/** Explicit deployment.environment; defaults to `network` when unset. */
|
|
23
|
+
deploymentEnvironment?: string;
|
|
24
|
+
/** testnet | mainnet | devnet → deployment.environment (default) + dkg.network. */
|
|
25
|
+
network?: string;
|
|
26
|
+
peerId?: string;
|
|
27
|
+
nodeName?: string;
|
|
28
|
+
/** 'core' | 'edge' → dkg.node.role */
|
|
29
|
+
nodeRole?: string;
|
|
30
|
+
commit?: string;
|
|
31
|
+
/** e.g. 'base:8453' → dkg.chain */
|
|
32
|
+
chainId?: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Build the resource attribute map. Standard OTel keys (service.*, deployment.*)
|
|
36
|
+
* plus the DKG identity keys (dkg.network, dkg.peer_id, dkg.node.name,
|
|
37
|
+
* dkg.node.role, dkg.chain, dkg.commit). Unset values are omitted so the
|
|
38
|
+
* resource never carries empty strings.
|
|
39
|
+
*/
|
|
40
|
+
export declare function buildTelemetryResourceAttrs(r?: TelemetryResourceInput): Record<string, string>;
|
|
41
|
+
//# sourceMappingURL=telemetry-resource.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telemetry-resource.d.ts","sourceRoot":"","sources":["../src/telemetry-resource.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,WAAW,sBAAsB;IACrC,6CAA6C;IAC7C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iDAAiD;IACjD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,yEAAyE;IACzE,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,mFAAmF;IACnF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sCAAsC;IACtC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mCAAmC;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,CAAC,CAAC,GAAE,sBAA2B,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAclG"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build the resource attribute map. Standard OTel keys (service.*, deployment.*)
|
|
3
|
+
* plus the DKG identity keys (dkg.network, dkg.peer_id, dkg.node.name,
|
|
4
|
+
* dkg.node.role, dkg.chain, dkg.commit). Unset values are omitted so the
|
|
5
|
+
* resource never carries empty strings.
|
|
6
|
+
*/
|
|
7
|
+
export function buildTelemetryResourceAttrs(r = {}) {
|
|
8
|
+
const attrs = { 'service.name': r.serviceName || 'dkg-node' };
|
|
9
|
+
if (r.serviceVersion)
|
|
10
|
+
attrs['service.version'] = r.serviceVersion;
|
|
11
|
+
const instanceId = r.serviceInstanceId || r.nodeName || r.peerId;
|
|
12
|
+
if (instanceId)
|
|
13
|
+
attrs['service.instance.id'] = instanceId;
|
|
14
|
+
const env = r.deploymentEnvironment || r.network;
|
|
15
|
+
if (env)
|
|
16
|
+
attrs['deployment.environment'] = env;
|
|
17
|
+
if (r.network)
|
|
18
|
+
attrs['dkg.network'] = r.network;
|
|
19
|
+
if (r.peerId)
|
|
20
|
+
attrs['dkg.peer_id'] = r.peerId;
|
|
21
|
+
if (r.nodeName)
|
|
22
|
+
attrs['dkg.node.name'] = r.nodeName;
|
|
23
|
+
if (r.nodeRole)
|
|
24
|
+
attrs['dkg.node.role'] = r.nodeRole;
|
|
25
|
+
if (r.commit)
|
|
26
|
+
attrs['dkg.commit'] = r.commit;
|
|
27
|
+
if (r.chainId)
|
|
28
|
+
attrs['dkg.chain'] = r.chainId;
|
|
29
|
+
return attrs;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=telemetry-resource.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telemetry-resource.js","sourceRoot":"","sources":["../src/telemetry-resource.ts"],"names":[],"mappings":"AAkCA;;;;;GAKG;AACH,MAAM,UAAU,2BAA2B,CAAC,IAA4B,EAAE;IACxE,MAAM,KAAK,GAA2B,EAAE,cAAc,EAAE,CAAC,CAAC,WAAW,IAAI,UAAU,EAAE,CAAC;IACtF,IAAI,CAAC,CAAC,cAAc;QAAE,KAAK,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,cAAc,CAAC;IAClE,MAAM,UAAU,GAAG,CAAC,CAAC,iBAAiB,IAAI,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,MAAM,CAAC;IACjE,IAAI,UAAU;QAAE,KAAK,CAAC,qBAAqB,CAAC,GAAG,UAAU,CAAC;IAC1D,MAAM,GAAG,GAAG,CAAC,CAAC,qBAAqB,IAAI,CAAC,CAAC,OAAO,CAAC;IACjD,IAAI,GAAG;QAAE,KAAK,CAAC,wBAAwB,CAAC,GAAG,GAAG,CAAC;IAC/C,IAAI,CAAC,CAAC,OAAO;QAAE,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC;IAChD,IAAI,CAAC,CAAC,MAAM;QAAE,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9C,IAAI,CAAC,CAAC,QAAQ;QAAE,KAAK,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC;IACpD,IAAI,CAAC,CAAC,QAAQ;QAAE,KAAK,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC;IACpD,IAAI,CAAC,CAAC,MAAM;QAAE,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;IAC7C,IAAI,CAAC,CAAC,OAAO;QAAE,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC;IAC9C,OAAO,KAAK,CAAC;AACf,CAAC"}
|
package/dist/telemetry.d.ts
CHANGED
|
@@ -1,12 +1,58 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* When enabled (via config), exports metrics and optionally traces to an OTLP endpoint.
|
|
4
|
-
* operationId is set as the trace/span attribute for correlation with the dashboard.
|
|
2
|
+
* OpenTelemetry SDK bootstrap for a DKG node (boot side, daemon-only consumer).
|
|
5
3
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
4
|
+
* Registers the global Tracer + Meter providers at daemon startup so that the
|
|
5
|
+
* call-site facade in `@origintrail-official/dkg-core` (getTracer/withSpan/
|
|
6
|
+
* getMetrics) — used across agent/publisher/chain/sync — produces real spans and
|
|
7
|
+
* metrics. When telemetry is disabled, or a signal has no endpoint, this
|
|
8
|
+
* registers NOTHING: the core facade then talks to the API's built-in no-op
|
|
9
|
+
* providers (zero cost, no outbound calls).
|
|
10
|
+
*
|
|
11
|
+
* Logs are NOT handled here — they stay on the hand-rolled `OtlpLogWorker`
|
|
12
|
+
* (bounded buffer + retry + at-source redaction); the OTel Logs SDK is still
|
|
13
|
+
* "Development". This module only wires traces + metrics, and shares ONE
|
|
14
|
+
* Resource with the log worker so all three signals describe the same node.
|
|
15
|
+
*
|
|
16
|
+
* BROWSER SAFETY: the heavy Node-only OTel SDK packages (sdk-trace-node,
|
|
17
|
+
* sdk-metrics, exporter-*-otlp-proto, resources) and `@origintrail-official/dkg-core`
|
|
18
|
+
* are loaded via DYNAMIC import inside `initTelemetry`/`shutdownTelemetry`, never
|
|
19
|
+
* statically. Only `@opentelemetry/api` (browser-safe, no Node built-ins) is a
|
|
20
|
+
* static import. That keeps this module — and the package root that re-exports
|
|
21
|
+
* it — free of server-only code in any static bundle graph: a browser bundler
|
|
22
|
+
* never pulls the Node SDK because it sits behind a runtime `import()` that the
|
|
23
|
+
* UI never triggers.
|
|
24
|
+
*/
|
|
25
|
+
import { type TelemetryResourceInput } from './telemetry-resource.js';
|
|
26
|
+
/**
|
|
27
|
+
* Stable resource identity, shared by logs + traces + metrics. Single canonical
|
|
28
|
+
* type — re-exported alias of `TelemetryResourceInput` (the shared resource
|
|
29
|
+
* model in ./telemetry-resource) so logs and traces/metrics can't drift.
|
|
30
|
+
*/
|
|
31
|
+
export type TelemetryResource = TelemetryResourceInput;
|
|
32
|
+
export interface OtlpSignalConfig {
|
|
33
|
+
endpoint?: string;
|
|
34
|
+
/** Bearer token → Authorization header. */
|
|
35
|
+
token?: string;
|
|
36
|
+
headers?: Record<string, string>;
|
|
37
|
+
/** Per-signal opt-out. A signal is on only when it has an endpoint AND this is not false. */
|
|
38
|
+
enabled?: boolean;
|
|
39
|
+
}
|
|
40
|
+
export interface TelemetryInitConfig {
|
|
41
|
+
/** Master gate. When false, nothing is registered. */
|
|
42
|
+
enabled?: boolean;
|
|
43
|
+
resource?: TelemetryResource;
|
|
44
|
+
traces?: OtlpSignalConfig & {
|
|
45
|
+
sampleRatio?: number;
|
|
46
|
+
};
|
|
47
|
+
metrics?: OtlpSignalConfig & {
|
|
48
|
+
exportIntervalMs?: number;
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* LEGACY config shape (pre-PR #1317 stub). Kept so old JS callers that pass
|
|
53
|
+
* `{ enabled, metricsEndpoint, serviceName }` keep working — `initTelemetry`
|
|
54
|
+
* normalizes it into `TelemetryInitConfig` (metricsEndpoint → metrics.endpoint).
|
|
55
|
+
* @deprecated Use `TelemetryInitConfig` (traces/metrics signal blocks).
|
|
10
56
|
*/
|
|
11
57
|
export interface TelemetryConfig {
|
|
12
58
|
enabled?: boolean;
|
|
@@ -16,20 +62,33 @@ export interface TelemetryConfig {
|
|
|
16
62
|
serviceName?: string;
|
|
17
63
|
}
|
|
18
64
|
/**
|
|
19
|
-
* Initialize
|
|
20
|
-
*
|
|
65
|
+
* Initialize traces + metrics. No-op when disabled or when a signal has no
|
|
66
|
+
* endpoint. Safe to call once at daemon boot. Idempotent (subsequent calls are
|
|
67
|
+
* ignored once configured). Async because the Node OTel SDK is dynamically
|
|
68
|
+
* imported (see the BROWSER SAFETY note above).
|
|
21
69
|
*/
|
|
22
|
-
export declare function initTelemetry(
|
|
70
|
+
export declare function initTelemetry(input: TelemetryInitConfig | TelemetryConfig): Promise<void>;
|
|
71
|
+
/** True once EITHER signal (traces or metrics) has registered a real provider. */
|
|
72
|
+
export declare function isTelemetryConfigured(): boolean;
|
|
23
73
|
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
74
|
+
* Flush + shut down providers. Used both at daemon teardown AND when telemetry
|
|
75
|
+
* is turned off via the runtime master gate, so it must FULLY reverse
|
|
76
|
+
* `initTelemetry`: stop the exporters, then clear the OTel API globals so a
|
|
77
|
+
* later `initTelemetry` (live re-enable) can register fresh providers — without
|
|
78
|
+
* the `disable()` calls, the API keeps the first (now shut-down) provider and a
|
|
79
|
+
* re-enable would silently no-op. Safe if never initialized; idempotent.
|
|
80
|
+
*/
|
|
81
|
+
export declare function shutdownTelemetry(): Promise<void>;
|
|
82
|
+
/**
|
|
83
|
+
* @deprecated No-op compatibility shim for the pre-PR #1317 telemetry API. Node
|
|
84
|
+
* metrics flow through the `@origintrail-official/dkg-core` facade
|
|
85
|
+
* (`getMetrics()`), not this call. Kept so old callers don't break at import.
|
|
26
86
|
*/
|
|
27
87
|
export declare function recordGauge(_name: string, _value: number): void;
|
|
28
88
|
/**
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
89
|
+
* @deprecated No-op compatibility shim for the pre-PR #1317 telemetry API. Spans
|
|
90
|
+
* are created via the core facade `withSpan()`/`getTracer()`. Kept so old
|
|
91
|
+
* callers don't break at import.
|
|
32
92
|
*/
|
|
33
93
|
export declare function setOperationSpan(_operationId: string, _operationName: string): void;
|
|
34
|
-
export declare function isTelemetryConfigured(): boolean;
|
|
35
94
|
//# sourceMappingURL=telemetry.d.ts.map
|
package/dist/telemetry.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"telemetry.d.ts","sourceRoot":"","sources":["../src/telemetry.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"telemetry.d.ts","sourceRoot":"","sources":["../src/telemetry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAGH,OAAO,EAA+B,KAAK,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAKnG;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GAAG,sBAAsB,CAAC;AAEvD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2CAA2C;IAC3C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,6FAA6F;IAC7F,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,sDAAsD;IACtD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B,MAAM,CAAC,EAAE,gBAAgB,GAAG;QAAE,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACrD,OAAO,CAAC,EAAE,gBAAgB,GAAG;QAAE,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC5D;AAED;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,6EAA6E;IAC7E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,2CAA2C;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AA+BD;;;;;GAKG;AACH,wBAAsB,aAAa,CAAC,KAAK,EAAE,mBAAmB,GAAG,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAwD/F;AAED,kFAAkF;AAClF,wBAAgB,qBAAqB,IAAI,OAAO,CAE/C;AAED;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAyBvD;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAE/D;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,YAAY,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,IAAI,CAEnF"}
|