@redthreadlabs/tracelog-client 2.1.0 → 2.1.1
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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@redthreadlabs/tracelog-client",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.1",
|
|
4
4
|
"description": "Lightweight logging client for tracelog — works in React Native and browsers",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"registry": "https://registry.npmjs.org/",
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
"dist"
|
|
13
13
|
],
|
|
14
14
|
"scripts": {
|
|
15
|
-
"
|
|
15
|
+
"clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\"",
|
|
16
|
+
"build": "npm run clean && tsc",
|
|
16
17
|
"prepublishOnly": "npm run build",
|
|
17
18
|
"pretest": "npm run build",
|
|
18
19
|
"test": "node --test"
|
package/dist/LogClient.d.ts
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import { EventBuilder } from './EventBuilder';
|
|
2
|
-
import { EndOptions, LogClientOptions, RecordOptions, StartOptions } from './types';
|
|
3
|
-
export declare class LogClient {
|
|
4
|
-
private _opts;
|
|
5
|
-
private _eventBuffer;
|
|
6
|
-
private _transactionBuffer;
|
|
7
|
-
private _spanBuffer;
|
|
8
|
-
private _activeSpans;
|
|
9
|
-
/** Per-launch id; the join key between records and this lifetime's origin. */
|
|
10
|
-
private readonly _lifetimeId;
|
|
11
|
-
/** JSON of the last origin sent, to detect changes (null ⇒ not yet sent). */
|
|
12
|
-
private _lastOriginJson;
|
|
13
|
-
private _flushHandle;
|
|
14
|
-
private _persistHandle;
|
|
15
|
-
private _disposed;
|
|
16
|
-
private _flushing;
|
|
17
|
-
constructor(opts: LogClientOptions);
|
|
18
|
-
/** This LogClient's lifetime id (one per launch / process run). */
|
|
19
|
-
get lifetimeId(): string;
|
|
20
|
-
event(type?: string): EventBuilder;
|
|
21
|
-
/** Start a root timed operation (a trace root). Recorded as a transaction. */
|
|
22
|
-
startTransaction(name: string, opts?: StartOptions): Transaction;
|
|
23
|
-
/** Start a sub-operation under a transaction or span. Recorded as a span. */
|
|
24
|
-
startSpan(name: string, parent: Transaction | Span, opts?: StartOptions): Span;
|
|
25
|
-
/** Internal: end a live transaction/span by id (called by the handles). */
|
|
26
|
-
_end(id: string, opts?: EndOptions): void;
|
|
27
|
-
/** Record a complete root operation timed elsewhere → a transaction. */
|
|
28
|
-
recordTransaction(name: string, durationMs: number, opts?: RecordOptions): void;
|
|
29
|
-
/** Record a complete sub-operation timed elsewhere → a span under `parent`. */
|
|
30
|
-
recordSpan(name: string, durationMs: number, parent: Transaction | Span, opts?: RecordOptions): void;
|
|
31
|
-
private _belowThreshold;
|
|
32
|
-
private _buildOneShot;
|
|
33
|
-
flush(): Promise<void>;
|
|
34
|
-
dispose(): void;
|
|
35
|
-
private _enqueueEvent;
|
|
36
|
-
private _enqueueTransaction;
|
|
37
|
-
private _enqueueSpan;
|
|
38
|
-
private _afterEnqueue;
|
|
39
|
-
/** The origin to attach to this flush, or undefined if unchanged since last sent. */
|
|
40
|
-
private _takeOriginIfChanged;
|
|
41
|
-
private _sendInChunks;
|
|
42
|
-
private _sendChunkWithRetry;
|
|
43
|
-
private _sendChunk;
|
|
44
|
-
private _schedulePersist;
|
|
45
|
-
private _persistNow;
|
|
46
|
-
private _loadPersistedLogs;
|
|
47
|
-
}
|
|
48
|
-
/** A live root operation. Recorded as a `transaction` when ended. */
|
|
49
|
-
export declare class Transaction {
|
|
50
|
-
private readonly _client;
|
|
51
|
-
readonly id: string;
|
|
52
|
-
readonly traceId: string;
|
|
53
|
-
readonly type: string;
|
|
54
|
-
constructor(_client: LogClient, id: string, traceId: string, type: string);
|
|
55
|
-
/** A transaction is its own trace root. */
|
|
56
|
-
get transactionId(): string;
|
|
57
|
-
startSpan(name: string, opts?: StartOptions): Span;
|
|
58
|
-
end(opts?: EndOptions): void;
|
|
59
|
-
}
|
|
60
|
-
/** A live sub-operation. Recorded as a `span` when ended. */
|
|
61
|
-
export declare class Span {
|
|
62
|
-
private readonly _client;
|
|
63
|
-
readonly id: string;
|
|
64
|
-
readonly traceId: string;
|
|
65
|
-
readonly transactionId: string;
|
|
66
|
-
readonly parentId: string;
|
|
67
|
-
readonly type: string;
|
|
68
|
-
constructor(_client: LogClient, id: string, traceId: string, transactionId: string, parentId: string, type: string);
|
|
69
|
-
startSpan(name: string, opts?: StartOptions): Span;
|
|
70
|
-
end(opts?: EndOptions): void;
|
|
71
|
-
}
|
package/dist/LogClient.js
DELETED
|
@@ -1,399 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Span = exports.Transaction = exports.LogClient = void 0;
|
|
4
|
-
const EventBuilder_1 = require("./EventBuilder");
|
|
5
|
-
const util_1 = require("./util");
|
|
6
|
-
// Level ordering for the optional getMinLevel gate. An event is dropped when
|
|
7
|
-
// its level ranks below the host-supplied minimum.
|
|
8
|
-
const LEVEL_RANK = { debug: 0, info: 1, warn: 2, error: 3 };
|
|
9
|
-
const DEFAULT_TYPE = 'app';
|
|
10
|
-
// Defaults (all overridable via LogClientOptions)
|
|
11
|
-
const DEFAULT_FLUSH_CADENCE_MS = 5000;
|
|
12
|
-
const DEFAULT_MAX_BUFFER_SIZE = 100;
|
|
13
|
-
const DEFAULT_MAX_CHUNK_SIZE = 50;
|
|
14
|
-
const DEFAULT_MAX_CHUNK_BYTES = 512 * 1024;
|
|
15
|
-
const INTER_CHUNK_DELAY_MS = 200;
|
|
16
|
-
const MAX_RETRIES = 3;
|
|
17
|
-
const BASE_RETRY_DELAY_MS = 1000;
|
|
18
|
-
const PERSIST_DEBOUNCE_MS = 100;
|
|
19
|
-
class LogClient {
|
|
20
|
-
constructor(opts) {
|
|
21
|
-
this._eventBuffer = [];
|
|
22
|
-
this._transactionBuffer = [];
|
|
23
|
-
this._spanBuffer = [];
|
|
24
|
-
this._activeSpans = new Map();
|
|
25
|
-
/** Per-launch id; the join key between records and this lifetime's origin. */
|
|
26
|
-
this._lifetimeId = randomHex(16);
|
|
27
|
-
/** JSON of the last origin sent, to detect changes (null ⇒ not yet sent). */
|
|
28
|
-
this._lastOriginJson = null;
|
|
29
|
-
this._flushHandle = null;
|
|
30
|
-
this._persistHandle = null;
|
|
31
|
-
this._disposed = false;
|
|
32
|
-
this._flushing = false;
|
|
33
|
-
this._opts = opts;
|
|
34
|
-
this._loadPersistedLogs();
|
|
35
|
-
this._flushHandle = setInterval(() => this.flush(), opts.flushCadenceMs ?? DEFAULT_FLUSH_CADENCE_MS);
|
|
36
|
-
}
|
|
37
|
-
/** This LogClient's lifetime id (one per launch / process run). */
|
|
38
|
-
get lifetimeId() {
|
|
39
|
-
return this._lifetimeId;
|
|
40
|
-
}
|
|
41
|
-
// ---- Fluent event builder ----
|
|
42
|
-
event(type = 'client-log') {
|
|
43
|
-
return new EventBuilder_1.EventBuilder((evt) => this._enqueueEvent(evt), type);
|
|
44
|
-
}
|
|
45
|
-
// ---- Live traces: transactions & spans ----
|
|
46
|
-
/** Start a root timed operation (a trace root). Recorded as a transaction. */
|
|
47
|
-
startTransaction(name, opts) {
|
|
48
|
-
const id = randomHex(16);
|
|
49
|
-
const trace_id = randomHex(32);
|
|
50
|
-
const type = opts?.type ?? DEFAULT_TYPE;
|
|
51
|
-
this._activeSpans.set(id, {
|
|
52
|
-
kind: 'transaction', id, trace_id, name, type,
|
|
53
|
-
startTime: now(), tzOffset: (0, util_1.tzOffsetMinutes)(), children: [],
|
|
54
|
-
});
|
|
55
|
-
return new Transaction(this, id, trace_id, type);
|
|
56
|
-
}
|
|
57
|
-
/** Start a sub-operation under a transaction or span. Recorded as a span. */
|
|
58
|
-
startSpan(name, parent, opts) {
|
|
59
|
-
const id = randomHex(16);
|
|
60
|
-
const type = opts?.type ?? DEFAULT_TYPE;
|
|
61
|
-
this._activeSpans.set(id, {
|
|
62
|
-
kind: 'span', id,
|
|
63
|
-
trace_id: parent.traceId,
|
|
64
|
-
transaction_id: parent.transactionId,
|
|
65
|
-
parent_id: parent.id,
|
|
66
|
-
name, type,
|
|
67
|
-
startTime: now(), tzOffset: (0, util_1.tzOffsetMinutes)(), children: [],
|
|
68
|
-
});
|
|
69
|
-
this._activeSpans.get(parent.id)?.children.push(id);
|
|
70
|
-
return new Span(this, id, parent.traceId, parent.transactionId, parent.id, type);
|
|
71
|
-
}
|
|
72
|
-
/** Internal: end a live transaction/span by id (called by the handles). */
|
|
73
|
-
_end(id, opts) {
|
|
74
|
-
const active = this._activeSpans.get(id);
|
|
75
|
-
if (!active)
|
|
76
|
-
return;
|
|
77
|
-
// Auto-close any children not yet ended, so a forgotten child can't leak.
|
|
78
|
-
for (const childId of active.children) {
|
|
79
|
-
if (this._activeSpans.has(childId))
|
|
80
|
-
this._end(childId);
|
|
81
|
-
}
|
|
82
|
-
const duration = Math.max(0, now() - active.startTime);
|
|
83
|
-
const base = {
|
|
84
|
-
id: active.id,
|
|
85
|
-
trace_id: active.trace_id,
|
|
86
|
-
name: active.name,
|
|
87
|
-
type: active.type,
|
|
88
|
-
timestamp: Math.round(active.startTime * 1000), // ms → µs
|
|
89
|
-
duration: Math.round(duration),
|
|
90
|
-
outcome: opts?.outcome ?? 'success',
|
|
91
|
-
tz_offset: active.tzOffset,
|
|
92
|
-
...(opts?.labels && Object.keys(opts.labels).length > 0 ? { context: { labels: opts.labels } } : {}),
|
|
93
|
-
};
|
|
94
|
-
this._activeSpans.delete(id);
|
|
95
|
-
if (active.kind === 'transaction') {
|
|
96
|
-
this._enqueueTransaction(base);
|
|
97
|
-
}
|
|
98
|
-
else {
|
|
99
|
-
this._enqueueSpan({ ...base, transaction_id: active.transaction_id, parent_id: active.parent_id });
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
// ---- One-shot (pre-measured) traces ----
|
|
103
|
-
/** Record a complete root operation timed elsewhere → a transaction. */
|
|
104
|
-
recordTransaction(name, durationMs, opts) {
|
|
105
|
-
if (this._disposed || this._belowThreshold(durationMs, opts))
|
|
106
|
-
return;
|
|
107
|
-
const id = randomHex(16);
|
|
108
|
-
this._enqueueTransaction(this._buildOneShot(id, randomHex(32), name, durationMs, opts));
|
|
109
|
-
}
|
|
110
|
-
/** Record a complete sub-operation timed elsewhere → a span under `parent`. */
|
|
111
|
-
recordSpan(name, durationMs, parent, opts) {
|
|
112
|
-
if (this._disposed || this._belowThreshold(durationMs, opts))
|
|
113
|
-
return;
|
|
114
|
-
const id = randomHex(16);
|
|
115
|
-
const rec = this._buildOneShot(id, parent.traceId, name, durationMs, opts);
|
|
116
|
-
rec.transaction_id = parent.transactionId;
|
|
117
|
-
rec.parent_id = parent.id;
|
|
118
|
-
this._enqueueSpan(rec);
|
|
119
|
-
}
|
|
120
|
-
_belowThreshold(durationMs, opts) {
|
|
121
|
-
return opts?.minDurationMs !== undefined && durationMs < opts.minDurationMs;
|
|
122
|
-
}
|
|
123
|
-
_buildOneShot(id, trace_id, name, durationMs, opts) {
|
|
124
|
-
const d = isFinite(durationMs) && durationMs > 0 ? durationMs : 0;
|
|
125
|
-
const rec = {
|
|
126
|
-
id, trace_id, name,
|
|
127
|
-
type: opts?.type ?? DEFAULT_TYPE,
|
|
128
|
-
// No live start, so back-compute it from the measured duration.
|
|
129
|
-
timestamp: Math.round((now() - d) * 1000), // ms → µs
|
|
130
|
-
duration: Math.round(d),
|
|
131
|
-
outcome: opts?.outcome ?? 'success',
|
|
132
|
-
tz_offset: (0, util_1.tzOffsetMinutes)(),
|
|
133
|
-
};
|
|
134
|
-
if (opts?.labels && Object.keys(opts.labels).length > 0)
|
|
135
|
-
rec.context = { labels: opts.labels };
|
|
136
|
-
return rec;
|
|
137
|
-
}
|
|
138
|
-
// ---- Transport ----
|
|
139
|
-
async flush() {
|
|
140
|
-
if (this._disposed || this._flushing)
|
|
141
|
-
return;
|
|
142
|
-
if (this._eventBuffer.length === 0 && this._transactionBuffer.length === 0 && this._spanBuffer.length === 0)
|
|
143
|
-
return;
|
|
144
|
-
this._flushing = true;
|
|
145
|
-
try {
|
|
146
|
-
const events = this._eventBuffer.splice(0);
|
|
147
|
-
const transactions = this._transactionBuffer.splice(0);
|
|
148
|
-
const spans = this._spanBuffer.splice(0);
|
|
149
|
-
const origin = this._takeOriginIfChanged();
|
|
150
|
-
await this._sendInChunks(events, transactions, spans, origin);
|
|
151
|
-
}
|
|
152
|
-
finally {
|
|
153
|
-
this._flushing = false;
|
|
154
|
-
this._schedulePersist();
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
dispose() {
|
|
158
|
-
if (this._disposed)
|
|
159
|
-
return;
|
|
160
|
-
this._disposed = true;
|
|
161
|
-
if (this._flushHandle) {
|
|
162
|
-
clearInterval(this._flushHandle);
|
|
163
|
-
this._flushHandle = null;
|
|
164
|
-
}
|
|
165
|
-
if (this._persistHandle) {
|
|
166
|
-
clearTimeout(this._persistHandle);
|
|
167
|
-
this._persistHandle = null;
|
|
168
|
-
}
|
|
169
|
-
this._persistNow();
|
|
170
|
-
}
|
|
171
|
-
// ---- Internal: buffering ----
|
|
172
|
-
_enqueueEvent(event) {
|
|
173
|
-
if (this._disposed)
|
|
174
|
-
return;
|
|
175
|
-
// Level gate: drop events below the host-supplied minimum before buffering.
|
|
176
|
-
const minLevel = this._opts.getMinLevel?.();
|
|
177
|
-
if (minLevel && LEVEL_RANK[event.level] < LEVEL_RANK[minLevel])
|
|
178
|
-
return;
|
|
179
|
-
if (event.locale === undefined) {
|
|
180
|
-
const locale = this._opts.getLocale?.();
|
|
181
|
-
if (locale)
|
|
182
|
-
event.locale = locale;
|
|
183
|
-
}
|
|
184
|
-
this._eventBuffer.push(event);
|
|
185
|
-
this._afterEnqueue();
|
|
186
|
-
}
|
|
187
|
-
_enqueueTransaction(rec) {
|
|
188
|
-
if (this._disposed)
|
|
189
|
-
return;
|
|
190
|
-
this._transactionBuffer.push(rec);
|
|
191
|
-
this._afterEnqueue();
|
|
192
|
-
}
|
|
193
|
-
_enqueueSpan(rec) {
|
|
194
|
-
if (this._disposed)
|
|
195
|
-
return;
|
|
196
|
-
this._spanBuffer.push(rec);
|
|
197
|
-
this._afterEnqueue();
|
|
198
|
-
}
|
|
199
|
-
_afterEnqueue() {
|
|
200
|
-
this._schedulePersist();
|
|
201
|
-
const total = this._eventBuffer.length + this._transactionBuffer.length + this._spanBuffer.length;
|
|
202
|
-
if (total >= (this._opts.maxBufferSize ?? DEFAULT_MAX_BUFFER_SIZE))
|
|
203
|
-
this.flush();
|
|
204
|
-
}
|
|
205
|
-
/** The origin to attach to this flush, or undefined if unchanged since last sent. */
|
|
206
|
-
_takeOriginIfChanged() {
|
|
207
|
-
let origin;
|
|
208
|
-
try {
|
|
209
|
-
origin = this._opts.getOrigin();
|
|
210
|
-
}
|
|
211
|
-
catch {
|
|
212
|
-
return undefined;
|
|
213
|
-
}
|
|
214
|
-
const oj = JSON.stringify(origin);
|
|
215
|
-
if (oj === this._lastOriginJson)
|
|
216
|
-
return undefined;
|
|
217
|
-
this._lastOriginJson = oj;
|
|
218
|
-
return { ...origin, lifetime_id: this._lifetimeId };
|
|
219
|
-
}
|
|
220
|
-
// ---- Internal: chunked sending ----
|
|
221
|
-
async _sendInChunks(events, transactions, spans, origin) {
|
|
222
|
-
const maxChunkSize = this._opts.maxChunkSize ?? DEFAULT_MAX_CHUNK_SIZE;
|
|
223
|
-
const maxChunkBytes = this._opts.maxChunkBytes ?? DEFAULT_MAX_CHUNK_BYTES;
|
|
224
|
-
const work = [
|
|
225
|
-
...events.map((rec) => ({ k: 'e', rec })),
|
|
226
|
-
...transactions.map((rec) => ({ k: 't', rec })),
|
|
227
|
-
...spans.map((rec) => ({ k: 's', rec })),
|
|
228
|
-
];
|
|
229
|
-
let i = 0;
|
|
230
|
-
let isFirst = true;
|
|
231
|
-
while (i < work.length || (isFirst && origin)) {
|
|
232
|
-
if (!isFirst)
|
|
233
|
-
await delay(INTER_CHUNK_DELAY_MS);
|
|
234
|
-
const ce = [];
|
|
235
|
-
const ct = [];
|
|
236
|
-
const cs = [];
|
|
237
|
-
let bytes = 200; // base overhead for the batch envelope
|
|
238
|
-
while (i < work.length && (ce.length + ct.length + cs.length) < maxChunkSize) {
|
|
239
|
-
const item = work[i];
|
|
240
|
-
const itemBytes = estimateJsonSize(item.rec);
|
|
241
|
-
if (bytes + itemBytes > maxChunkBytes && (ce.length + ct.length + cs.length) > 0)
|
|
242
|
-
break;
|
|
243
|
-
if (item.k === 'e')
|
|
244
|
-
ce.push(item.rec);
|
|
245
|
-
else if (item.k === 't')
|
|
246
|
-
ct.push(item.rec);
|
|
247
|
-
else
|
|
248
|
-
cs.push(item.rec);
|
|
249
|
-
bytes += itemBytes;
|
|
250
|
-
i++;
|
|
251
|
-
}
|
|
252
|
-
const chunkOrigin = isFirst ? origin : undefined;
|
|
253
|
-
isFirst = false;
|
|
254
|
-
if (ce.length === 0 && ct.length === 0 && cs.length === 0 && !chunkOrigin)
|
|
255
|
-
break;
|
|
256
|
-
await this._sendChunkWithRetry(ce, ct, cs, chunkOrigin);
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
async _sendChunkWithRetry(events, transactions, spans, origin) {
|
|
260
|
-
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
261
|
-
try {
|
|
262
|
-
await this._sendChunk(events, transactions, spans, origin);
|
|
263
|
-
return;
|
|
264
|
-
}
|
|
265
|
-
catch {
|
|
266
|
-
if (attempt < MAX_RETRIES) {
|
|
267
|
-
await delay(BASE_RETRY_DELAY_MS * Math.pow(2, attempt));
|
|
268
|
-
}
|
|
269
|
-
else {
|
|
270
|
-
// Max retries exceeded — put records back for persistence/retry, and
|
|
271
|
-
// re-arm the origin so it ships again on the next successful flush.
|
|
272
|
-
this._eventBuffer.push(...events);
|
|
273
|
-
this._transactionBuffer.push(...transactions);
|
|
274
|
-
this._spanBuffer.push(...spans);
|
|
275
|
-
if (origin)
|
|
276
|
-
this._lastOriginJson = null;
|
|
277
|
-
this._schedulePersist();
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
async _sendChunk(events, transactions, spans, origin) {
|
|
283
|
-
const batch = { events, transactions, spans };
|
|
284
|
-
batch.lifetime_id = this._lifetimeId;
|
|
285
|
-
const userId = this._opts.getUserId?.();
|
|
286
|
-
const deviceId = this._opts.getDeviceId?.();
|
|
287
|
-
if (userId)
|
|
288
|
-
batch.user_id = userId;
|
|
289
|
-
if (deviceId)
|
|
290
|
-
batch.device_id = deviceId;
|
|
291
|
-
if (origin)
|
|
292
|
-
batch.origin = origin;
|
|
293
|
-
const headers = await Promise.resolve(this._opts.getAuthHeaders());
|
|
294
|
-
const response = await fetch(this._opts.endpoint, {
|
|
295
|
-
method: 'POST',
|
|
296
|
-
headers: { 'Content-Type': 'application/json', ...headers },
|
|
297
|
-
body: JSON.stringify(batch),
|
|
298
|
-
});
|
|
299
|
-
if (!response.ok)
|
|
300
|
-
throw new Error(`Server returned ${response.status}`);
|
|
301
|
-
}
|
|
302
|
-
// ---- Internal: persistence ----
|
|
303
|
-
_schedulePersist() {
|
|
304
|
-
if (this._persistHandle || !this._opts.persistLogs)
|
|
305
|
-
return;
|
|
306
|
-
this._persistHandle = setTimeout(() => {
|
|
307
|
-
this._persistHandle = null;
|
|
308
|
-
this._persistNow();
|
|
309
|
-
}, PERSIST_DEBOUNCE_MS);
|
|
310
|
-
}
|
|
311
|
-
_persistNow() {
|
|
312
|
-
if (!this._opts.persistLogs)
|
|
313
|
-
return;
|
|
314
|
-
if (this._eventBuffer.length === 0 && this._transactionBuffer.length === 0 && this._spanBuffer.length === 0) {
|
|
315
|
-
this._opts.persistLogs('').catch(() => { });
|
|
316
|
-
return;
|
|
317
|
-
}
|
|
318
|
-
const data = JSON.stringify({
|
|
319
|
-
events: this._eventBuffer,
|
|
320
|
-
transactions: this._transactionBuffer,
|
|
321
|
-
spans: this._spanBuffer,
|
|
322
|
-
});
|
|
323
|
-
this._opts.persistLogs(data).catch(() => { });
|
|
324
|
-
}
|
|
325
|
-
async _loadPersistedLogs() {
|
|
326
|
-
if (!this._opts.loadPersistedLogs)
|
|
327
|
-
return;
|
|
328
|
-
try {
|
|
329
|
-
const data = await this._opts.loadPersistedLogs();
|
|
330
|
-
if (!data)
|
|
331
|
-
return;
|
|
332
|
-
const parsed = JSON.parse(data);
|
|
333
|
-
if (Array.isArray(parsed.events))
|
|
334
|
-
this._eventBuffer.push(...parsed.events);
|
|
335
|
-
if (Array.isArray(parsed.transactions))
|
|
336
|
-
this._transactionBuffer.push(...parsed.transactions);
|
|
337
|
-
if (Array.isArray(parsed.spans))
|
|
338
|
-
this._spanBuffer.push(...parsed.spans);
|
|
339
|
-
this._opts.persistLogs?.('').catch(() => { });
|
|
340
|
-
}
|
|
341
|
-
catch {
|
|
342
|
-
// Ignore parse errors from corrupted persisted data
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
exports.LogClient = LogClient;
|
|
347
|
-
// ---- Trace handles ----
|
|
348
|
-
/** A live root operation. Recorded as a `transaction` when ended. */
|
|
349
|
-
class Transaction {
|
|
350
|
-
constructor(_client, id, traceId, type) {
|
|
351
|
-
this._client = _client;
|
|
352
|
-
this.id = id;
|
|
353
|
-
this.traceId = traceId;
|
|
354
|
-
this.type = type;
|
|
355
|
-
}
|
|
356
|
-
/** A transaction is its own trace root. */
|
|
357
|
-
get transactionId() { return this.id; }
|
|
358
|
-
startSpan(name, opts) { return this._client.startSpan(name, this, opts); }
|
|
359
|
-
end(opts) { this._client._end(this.id, opts); }
|
|
360
|
-
}
|
|
361
|
-
exports.Transaction = Transaction;
|
|
362
|
-
/** A live sub-operation. Recorded as a `span` when ended. */
|
|
363
|
-
class Span {
|
|
364
|
-
constructor(_client, id, traceId, transactionId, parentId, type) {
|
|
365
|
-
this._client = _client;
|
|
366
|
-
this.id = id;
|
|
367
|
-
this.traceId = traceId;
|
|
368
|
-
this.transactionId = transactionId;
|
|
369
|
-
this.parentId = parentId;
|
|
370
|
-
this.type = type;
|
|
371
|
-
}
|
|
372
|
-
startSpan(name, opts) { return this._client.startSpan(name, this, opts); }
|
|
373
|
-
end(opts) { this._client._end(this.id, opts); }
|
|
374
|
-
}
|
|
375
|
-
exports.Span = Span;
|
|
376
|
-
// ---- Helpers ----
|
|
377
|
-
function randomHex(length) {
|
|
378
|
-
const chars = '0123456789abcdef';
|
|
379
|
-
let result = '';
|
|
380
|
-
for (let i = 0; i < length; i++) {
|
|
381
|
-
result += chars[Math.floor(Math.random() * 16)];
|
|
382
|
-
}
|
|
383
|
-
return result;
|
|
384
|
-
}
|
|
385
|
-
function now() {
|
|
386
|
-
if (typeof performance !== 'undefined' && performance.now) {
|
|
387
|
-
if (!now._offset) {
|
|
388
|
-
now._offset = Date.now() - performance.now();
|
|
389
|
-
}
|
|
390
|
-
return now._offset + performance.now();
|
|
391
|
-
}
|
|
392
|
-
return Date.now();
|
|
393
|
-
}
|
|
394
|
-
function delay(ms) {
|
|
395
|
-
return new Promise(resolve => setTimeout(resolve, ms));
|
|
396
|
-
}
|
|
397
|
-
function estimateJsonSize(obj) {
|
|
398
|
-
return JSON.stringify(obj).length;
|
|
399
|
-
}
|
|
File without changes
|
|
File without changes
|