logquill 0.3.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +392 -6
- package/dist/browser.d.ts +468 -0
- package/dist/browser.mjs +783 -0
- package/dist/browser.mjs.map +1 -0
- package/dist/index.cjs +756 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +561 -126
- package/dist/index.d.ts +561 -126
- package/dist/index.mjs +736 -9
- package/dist/index.mjs.map +1 -1
- package/dist/langchain.cjs +120 -0
- package/dist/langchain.cjs.map +1 -0
- package/dist/langchain.d.cts +128 -0
- package/dist/langchain.d.ts +128 -0
- package/dist/langchain.mjs +116 -0
- package/dist/langchain.mjs.map +1 -0
- package/dist/logger-CRdmCDfC.d.cts +299 -0
- package/dist/logger-CRdmCDfC.d.ts +299 -0
- package/dist/winston.cjs +108 -0
- package/dist/winston.cjs.map +1 -0
- package/dist/winston.d.cts +55 -0
- package/dist/winston.d.ts +55 -0
- package/dist/winston.mjs +101 -0
- package/dist/winston.mjs.map +1 -0
- package/package.json +57 -12
package/dist/index.cjs
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var async_hooks = require('async_hooks');
|
|
3
4
|
var crypto = require('crypto');
|
|
5
|
+
var module$1 = require('module');
|
|
4
6
|
var zlib = require('zlib');
|
|
5
7
|
var fs = require('fs');
|
|
6
8
|
var path = require('path');
|
|
7
9
|
|
|
10
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
8
11
|
// src/core/levels.ts
|
|
9
12
|
var Level = /* @__PURE__ */ ((Level2) => {
|
|
10
13
|
Level2[Level2["TRACE"] = 5] = "TRACE";
|
|
@@ -56,6 +59,7 @@ function createRecord(params) {
|
|
|
56
59
|
|
|
57
60
|
// src/core/formatter.ts
|
|
58
61
|
var JSONFormatter = class {
|
|
62
|
+
/** Returns `JSON.stringify(record)`. */
|
|
59
63
|
format(record) {
|
|
60
64
|
return JSON.stringify(record);
|
|
61
65
|
}
|
|
@@ -74,6 +78,7 @@ var FunctionPlugin = class {
|
|
|
74
78
|
|
|
75
79
|
// src/plugins/context-plugin.ts
|
|
76
80
|
var ContextPlugin = class {
|
|
81
|
+
/** Fixed key/value pairs merged into every record's `meta`. */
|
|
77
82
|
context;
|
|
78
83
|
constructor(context) {
|
|
79
84
|
this.context = context;
|
|
@@ -82,11 +87,297 @@ var ContextPlugin = class {
|
|
|
82
87
|
return { ...record, meta: { ...this.context, ...record.meta } };
|
|
83
88
|
}
|
|
84
89
|
};
|
|
90
|
+
var contextStore = new async_hooks.AsyncLocalStorage();
|
|
91
|
+
function currentContext() {
|
|
92
|
+
return contextStore.getStore() ?? {};
|
|
93
|
+
}
|
|
94
|
+
function bindContext(values, fn) {
|
|
95
|
+
return contextStore.run({ ...currentContext(), ...values }, fn);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// src/plugins/rate-limit-plugin.ts
|
|
99
|
+
function defaultKey(record) {
|
|
100
|
+
return `${record.logger}:${record.level}`;
|
|
101
|
+
}
|
|
102
|
+
var RateLimitPlugin = class {
|
|
103
|
+
/** Records allowed per key within a `perSeconds` window before further records for that key are dropped. */
|
|
104
|
+
maxRecords;
|
|
105
|
+
/** Length, in seconds, of each key's rolling window. */
|
|
106
|
+
perSeconds;
|
|
107
|
+
/** Distinct keys tracked at once before the least-recently-seen one is evicted. */
|
|
108
|
+
maxKeys;
|
|
109
|
+
keyFunc;
|
|
110
|
+
clock;
|
|
111
|
+
windows = /* @__PURE__ */ new Map();
|
|
112
|
+
constructor(maxRecords, perSeconds, options = {}) {
|
|
113
|
+
if (maxRecords < 1) {
|
|
114
|
+
throw new Error(`maxRecords must be at least 1, got ${String(maxRecords)}`);
|
|
115
|
+
}
|
|
116
|
+
if (perSeconds <= 0) {
|
|
117
|
+
throw new Error(`perSeconds must be positive, got ${String(perSeconds)}`);
|
|
118
|
+
}
|
|
119
|
+
this.maxRecords = maxRecords;
|
|
120
|
+
this.perSeconds = perSeconds;
|
|
121
|
+
this.keyFunc = options.keyFunc ?? defaultKey;
|
|
122
|
+
this.maxKeys = options.maxKeys ?? 1e3;
|
|
123
|
+
this.clock = options.clock ?? (() => performance.now() / 1e3);
|
|
124
|
+
}
|
|
125
|
+
beforeLog(record) {
|
|
126
|
+
const key = this.keyFunc(record);
|
|
127
|
+
const now = this.clock();
|
|
128
|
+
const window = this.windows.get(key);
|
|
129
|
+
if (window === void 0 || now - window.start >= this.perSeconds) {
|
|
130
|
+
this.windows.delete(key);
|
|
131
|
+
this.windows.set(key, { start: now, count: 1 });
|
|
132
|
+
while (this.windows.size > this.maxKeys) {
|
|
133
|
+
this.evictOldest();
|
|
134
|
+
}
|
|
135
|
+
return record;
|
|
136
|
+
}
|
|
137
|
+
this.windows.delete(key);
|
|
138
|
+
this.windows.set(key, window);
|
|
139
|
+
if (window.count >= this.maxRecords) {
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
window.count += 1;
|
|
143
|
+
return record;
|
|
144
|
+
}
|
|
145
|
+
evictOldest() {
|
|
146
|
+
const oldest = this.windows.keys().next();
|
|
147
|
+
if (!oldest.done) {
|
|
148
|
+
this.windows.delete(oldest.value);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
// src/bridges/level-dispatch.ts
|
|
154
|
+
function callAtLevel(log, level, message, meta) {
|
|
155
|
+
switch (level) {
|
|
156
|
+
case 5 /* TRACE */:
|
|
157
|
+
log.trace(message, meta);
|
|
158
|
+
return;
|
|
159
|
+
case 10 /* DEBUG */:
|
|
160
|
+
log.debug(message, meta);
|
|
161
|
+
return;
|
|
162
|
+
case 20 /* INFO */:
|
|
163
|
+
log.info(message, meta);
|
|
164
|
+
return;
|
|
165
|
+
case 30 /* WARN */:
|
|
166
|
+
log.warn(message, meta);
|
|
167
|
+
return;
|
|
168
|
+
case 40 /* ERROR */:
|
|
169
|
+
log.error(message, meta);
|
|
170
|
+
return;
|
|
171
|
+
case 50 /* FATAL */:
|
|
172
|
+
log.fatal(message, meta);
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// src/bridges/pino-destination.ts
|
|
178
|
+
var DEFAULT_PINO_LEVEL_MAP = {
|
|
179
|
+
10: 5 /* TRACE */,
|
|
180
|
+
20: 10 /* DEBUG */,
|
|
181
|
+
30: 20 /* INFO */,
|
|
182
|
+
40: 30 /* WARN */,
|
|
183
|
+
50: 40 /* ERROR */,
|
|
184
|
+
60: 50 /* FATAL */
|
|
185
|
+
};
|
|
186
|
+
var LogQuillPinoDestination = class {
|
|
187
|
+
/**
|
|
188
|
+
* Pino only recognizes a bare object passed as its sole argument
|
|
189
|
+
* (`pino(destination)`, without a separate options argument) as a
|
|
190
|
+
* destination stream, rather than an options object, if it looks
|
|
191
|
+
* stream-like — checking for `.writable`/`._writableState`, the same
|
|
192
|
+
* duck-typing `stream.Writable` itself satisfies. Without this, `pino()`
|
|
193
|
+
* would silently fall back to writing to `process.stdout` instead.
|
|
194
|
+
*/
|
|
195
|
+
writable = true;
|
|
196
|
+
target;
|
|
197
|
+
levelMap;
|
|
198
|
+
constructor(logquillLogger, options = {}) {
|
|
199
|
+
this.target = logquillLogger;
|
|
200
|
+
this.levelMap = options.levelMap ?? DEFAULT_PINO_LEVEL_MAP;
|
|
201
|
+
}
|
|
202
|
+
/** Node `Writable`-compatible write hook — splits `chunk` into NDJSON lines and dispatches each as a `Logger` call. */
|
|
203
|
+
write(chunk) {
|
|
204
|
+
for (const line of chunk.split("\n")) {
|
|
205
|
+
if (line.trim()) {
|
|
206
|
+
this.writeLine(line);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return true;
|
|
210
|
+
}
|
|
211
|
+
writeLine(line) {
|
|
212
|
+
let parsed;
|
|
213
|
+
try {
|
|
214
|
+
parsed = JSON.parse(line);
|
|
215
|
+
} catch {
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
if (typeof parsed !== "object" || parsed === null) {
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
const entry = parsed;
|
|
222
|
+
const pinoLevel = typeof entry.level === "number" ? entry.level : 30;
|
|
223
|
+
const message = typeof entry.msg === "string" ? entry.msg : "";
|
|
224
|
+
const meta = {};
|
|
225
|
+
for (const key of Object.keys(entry)) {
|
|
226
|
+
if (key !== "level" && key !== "msg") {
|
|
227
|
+
meta[key] = entry[key];
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
callAtLevel(this.target, this.levelMap[pinoLevel] ?? 20 /* INFO */, message, meta);
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
var RunPlugin = class {
|
|
234
|
+
/** Id stamped onto `meta.runId` for every record this instance processes. */
|
|
235
|
+
runId;
|
|
236
|
+
step = 0;
|
|
237
|
+
constructor(options = {}) {
|
|
238
|
+
this.runId = options.runId ?? crypto.randomUUID();
|
|
239
|
+
}
|
|
240
|
+
beforeLog(record) {
|
|
241
|
+
record.meta.runId ??= this.runId;
|
|
242
|
+
record.meta.step = this.step++;
|
|
243
|
+
return record;
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
var traceparentStore = new async_hooks.AsyncLocalStorage();
|
|
247
|
+
function setTraceparent(value) {
|
|
248
|
+
const previous = traceparentStore.getStore();
|
|
249
|
+
traceparentStore.enterWith(value);
|
|
250
|
+
return () => {
|
|
251
|
+
traceparentStore.enterWith(previous);
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
function getTraceparent() {
|
|
255
|
+
return traceparentStore.getStore();
|
|
256
|
+
}
|
|
257
|
+
function generateTraceId() {
|
|
258
|
+
return crypto.randomBytes(16).toString("hex");
|
|
259
|
+
}
|
|
260
|
+
var W3C_TRACEPARENT_RE = /^[0-9a-f]{2}-([0-9a-f]{32})-[0-9a-f]{16}-[0-9a-f]{2}$/;
|
|
261
|
+
var XRAY_ROOT_RE = /Root=1-([0-9a-f]{8})-([0-9a-f]{24})/;
|
|
262
|
+
var GCP_TRACE_RE = /^([0-9a-f]{32})\/\d+(;o=\d)?$/;
|
|
263
|
+
function parseTraceHeader(header) {
|
|
264
|
+
const trimmed = header.trim();
|
|
265
|
+
const w3c = W3C_TRACEPARENT_RE.exec(trimmed);
|
|
266
|
+
if (w3c?.[1]) {
|
|
267
|
+
return w3c[1];
|
|
268
|
+
}
|
|
269
|
+
const xray = XRAY_ROOT_RE.exec(trimmed);
|
|
270
|
+
if (xray?.[1] && xray[2]) {
|
|
271
|
+
return xray[1] + xray[2];
|
|
272
|
+
}
|
|
273
|
+
const gcp = GCP_TRACE_RE.exec(trimmed);
|
|
274
|
+
if (gcp?.[1]) {
|
|
275
|
+
return gcp[1];
|
|
276
|
+
}
|
|
277
|
+
return void 0;
|
|
278
|
+
}
|
|
279
|
+
function defaultResolveActiveOtelTraceId() {
|
|
280
|
+
try {
|
|
281
|
+
const require2 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
|
|
282
|
+
const otel = require2("@opentelemetry/api");
|
|
283
|
+
const span = otel.trace.getActiveSpan();
|
|
284
|
+
if (!span) {
|
|
285
|
+
return void 0;
|
|
286
|
+
}
|
|
287
|
+
const spanContext = span.spanContext();
|
|
288
|
+
if (!otel.trace.isSpanContextValid(spanContext)) {
|
|
289
|
+
return void 0;
|
|
290
|
+
}
|
|
291
|
+
return spanContext.traceId;
|
|
292
|
+
} catch {
|
|
293
|
+
return void 0;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
var TraceContextPlugin = class {
|
|
297
|
+
/** `meta` key the trace id is written to. */
|
|
298
|
+
traceKey;
|
|
299
|
+
explicitTraceparent;
|
|
300
|
+
resolveActiveOtelTraceId;
|
|
301
|
+
constructor(options = {}) {
|
|
302
|
+
this.traceKey = options.traceKey ?? "traceId";
|
|
303
|
+
this.explicitTraceparent = options.traceparent;
|
|
304
|
+
this.resolveActiveOtelTraceId = options.resolveActiveOtelTraceId ?? defaultResolveActiveOtelTraceId;
|
|
305
|
+
}
|
|
306
|
+
beforeLog(record) {
|
|
307
|
+
if (record.meta[this.traceKey] != null) {
|
|
308
|
+
return record;
|
|
309
|
+
}
|
|
310
|
+
record.meta[this.traceKey] = this.resolveTraceId();
|
|
311
|
+
return record;
|
|
312
|
+
}
|
|
313
|
+
resolveTraceId() {
|
|
314
|
+
const fromOtel = this.resolveActiveOtelTraceId();
|
|
315
|
+
if (fromOtel) {
|
|
316
|
+
return fromOtel;
|
|
317
|
+
}
|
|
318
|
+
const header = this.explicitTraceparent ?? getTraceparent();
|
|
319
|
+
if (header) {
|
|
320
|
+
const parsed = parseTraceHeader(header);
|
|
321
|
+
if (parsed) {
|
|
322
|
+
return parsed;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
return generateTraceId();
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
|
|
329
|
+
// src/plugins/otel-span-processor.ts
|
|
330
|
+
var OTEL_STATUS_CODE_ERROR = 2;
|
|
331
|
+
var OtelSpanProcessor = class {
|
|
332
|
+
log;
|
|
333
|
+
attributesKey;
|
|
334
|
+
constructor(log, options = {}) {
|
|
335
|
+
this.log = log;
|
|
336
|
+
this.attributesKey = options.attributesKey ?? "attributes";
|
|
337
|
+
}
|
|
338
|
+
/** Called by the tracer provider when a span starts — emits `.action()`. */
|
|
339
|
+
onStart(span) {
|
|
340
|
+
this.log.action(span.name, this.baseMeta(span));
|
|
341
|
+
}
|
|
342
|
+
/** Called by the tracer provider when a span ends — emits `.observation()`, or `.error()` if the span's status is an error. */
|
|
343
|
+
onEnd(span) {
|
|
344
|
+
const meta = {
|
|
345
|
+
...this.baseMeta(span),
|
|
346
|
+
durationMs: span.duration[0] * 1e3 + span.duration[1] / 1e6
|
|
347
|
+
};
|
|
348
|
+
if (span.status.code === OTEL_STATUS_CODE_ERROR) {
|
|
349
|
+
this.log.error(span.name, {
|
|
350
|
+
...meta,
|
|
351
|
+
error: span.status.message ?? "span ended with an error status"
|
|
352
|
+
});
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
this.log.observation(span.name, meta);
|
|
356
|
+
}
|
|
357
|
+
/** No internal buffering to flush — every span is forwarded to the `Logger` immediately. */
|
|
358
|
+
async forceFlush() {
|
|
359
|
+
}
|
|
360
|
+
/** No resources of its own to release; flush/close the wrapped `Logger` separately. */
|
|
361
|
+
async shutdown() {
|
|
362
|
+
}
|
|
363
|
+
baseMeta(span) {
|
|
364
|
+
const meta = { spanId: span.spanContext().spanId };
|
|
365
|
+
const parentSpanId = span.parentSpanContext?.spanId ?? span.parentSpanId;
|
|
366
|
+
if (parentSpanId) {
|
|
367
|
+
meta.parentSpanId = parentSpanId;
|
|
368
|
+
}
|
|
369
|
+
if (Object.keys(span.attributes).length > 0) {
|
|
370
|
+
meta[this.attributesKey] = span.attributes;
|
|
371
|
+
}
|
|
372
|
+
return meta;
|
|
373
|
+
}
|
|
374
|
+
};
|
|
85
375
|
|
|
86
376
|
// src/plugins/redact-plugin.ts
|
|
87
377
|
var DEFAULT_REDACTED_KEYS = ["password", "token", "secret", "api_key", "authorization"];
|
|
88
378
|
var RedactPlugin = class {
|
|
89
379
|
keys;
|
|
380
|
+
/** Placeholder a matched value is replaced with. */
|
|
90
381
|
replacement;
|
|
91
382
|
constructor(options = {}) {
|
|
92
383
|
this.keys = new Set((options.keys ?? DEFAULT_REDACTED_KEYS).map((key) => key.toLowerCase()));
|
|
@@ -110,7 +401,9 @@ var DEFAULT_PII_PATTERNS = {
|
|
|
110
401
|
};
|
|
111
402
|
var MAX_DEPTH = 50;
|
|
112
403
|
var PIIRedactPlugin = class {
|
|
404
|
+
/** Named patterns scanned for in every string `meta` value. */
|
|
113
405
|
patterns;
|
|
406
|
+
/** Placeholder a matched substring is replaced with. */
|
|
114
407
|
replacement;
|
|
115
408
|
constructor(options = {}) {
|
|
116
409
|
this.patterns = options.patterns ?? DEFAULT_PII_PATTERNS;
|
|
@@ -158,11 +451,17 @@ var PIIRedactPlugin = class {
|
|
|
158
451
|
|
|
159
452
|
// src/plugins/sampling-plugin.ts
|
|
160
453
|
var SamplingPlugin = class {
|
|
454
|
+
/** Fraction of non-elevated records kept, in `[0, 1]`. */
|
|
161
455
|
rate;
|
|
456
|
+
/** `meta` key holding the trace/run id used to group buffered records. */
|
|
162
457
|
traceKey;
|
|
458
|
+
/** A record at or above this level elevates its whole trace. */
|
|
163
459
|
elevateAt;
|
|
460
|
+
/** Transports buffered records are flushed straight to on elevation; `undefined` disables tail-based elevation. */
|
|
164
461
|
transports;
|
|
462
|
+
/** Total buffered records allowed across every trace before the oldest trace is evicted. */
|
|
165
463
|
maxBufferedRecords;
|
|
464
|
+
/** Distinct trace ids held at once before the oldest is evicted. */
|
|
166
465
|
maxTraces;
|
|
167
466
|
rng;
|
|
168
467
|
buffer = /* @__PURE__ */ new Map();
|
|
@@ -308,8 +607,11 @@ function defaultDedupeKey(record) {
|
|
|
308
607
|
return `${record.level}:${record.logger}:${record.message}`;
|
|
309
608
|
}
|
|
310
609
|
var AlertingPlugin = class {
|
|
610
|
+
/** A record at or above this level fires an alert. */
|
|
311
611
|
threshold;
|
|
612
|
+
/** How long a dedupe window stays open before a collapsed follow-up alert (if any) fires. */
|
|
312
613
|
dedupeWindowMs;
|
|
614
|
+
/** Distinct concurrent dedupe keys tracked at once; beyond this, new keys are dropped rather than tracked. */
|
|
313
615
|
maxTrackedKeys;
|
|
314
616
|
dedupeKeyFn;
|
|
315
617
|
windows = /* @__PURE__ */ new Map();
|
|
@@ -383,6 +685,7 @@ function formatMessage(record, occurrences) {
|
|
|
383
685
|
return `[${record.level}] ${record.logger}: ${record.message}${suffix}`;
|
|
384
686
|
}
|
|
385
687
|
var SlackAlertPlugin = class extends AlertingPlugin {
|
|
688
|
+
/** Slack "Incoming Webhook" URL every alert is posted to. */
|
|
386
689
|
webhookUrl;
|
|
387
690
|
sender;
|
|
388
691
|
constructor(webhookUrl, options = {}) {
|
|
@@ -412,6 +715,7 @@ async function fetchPagerDutySender(body) {
|
|
|
412
715
|
}
|
|
413
716
|
}
|
|
414
717
|
var PagerDutyAlertPlugin = class extends AlertingPlugin {
|
|
718
|
+
/** PagerDuty Events API v2 integration key every alert is sent under. */
|
|
415
719
|
routingKey;
|
|
416
720
|
sender;
|
|
417
721
|
constructor(routingKey, options = {}) {
|
|
@@ -441,9 +745,13 @@ var PagerDutyAlertPlugin = class extends AlertingPlugin {
|
|
|
441
745
|
|
|
442
746
|
// src/plugins/email-alert-plugin.ts
|
|
443
747
|
var EmailAlertPlugin = class extends AlertingPlugin {
|
|
748
|
+
/** SMTP server hostname. */
|
|
444
749
|
smtpHost;
|
|
750
|
+
/** SMTP server port. */
|
|
445
751
|
smtpPort;
|
|
752
|
+
/** Envelope `From` address for every alert. */
|
|
446
753
|
fromAddr;
|
|
754
|
+
/** Envelope `To` addresses for every alert. */
|
|
447
755
|
toAddrs;
|
|
448
756
|
username;
|
|
449
757
|
password;
|
|
@@ -509,10 +817,12 @@ var EmailAlertPlugin = class extends AlertingPlugin {
|
|
|
509
817
|
|
|
510
818
|
// src/transports/transport.ts
|
|
511
819
|
var Transport = class {
|
|
820
|
+
/** Turns a `LogRecord` into the string this transport actually writes. Defaults to `JSONFormatter`. */
|
|
512
821
|
formatter;
|
|
513
822
|
constructor(formatter = new JSONFormatter()) {
|
|
514
823
|
this.formatter = formatter;
|
|
515
824
|
}
|
|
825
|
+
/** Formats `record` via `this.formatter`. Called once per record before `write()`. */
|
|
516
826
|
format(record) {
|
|
517
827
|
return this.formatter.format(record);
|
|
518
828
|
}
|
|
@@ -520,9 +830,15 @@ var Transport = class {
|
|
|
520
830
|
close() {
|
|
521
831
|
}
|
|
522
832
|
};
|
|
833
|
+
function hasFlush(transport) {
|
|
834
|
+
return typeof transport.flush === "function";
|
|
835
|
+
}
|
|
523
836
|
var CollectingTransport = class extends Transport {
|
|
837
|
+
/** Every formatted string passed to `write()`, in call order. */
|
|
524
838
|
formatted = [];
|
|
839
|
+
/** Every raw `LogRecord` passed to `write()`, in call order. */
|
|
525
840
|
records = [];
|
|
841
|
+
/** Set once `close()` has been called. */
|
|
526
842
|
closed = false;
|
|
527
843
|
write(formatted, record) {
|
|
528
844
|
this.formatted.push(formatted);
|
|
@@ -535,7 +851,9 @@ var CollectingTransport = class extends Transport {
|
|
|
535
851
|
|
|
536
852
|
// src/transports/batching-transport.ts
|
|
537
853
|
var BatchingTransport = class extends Transport {
|
|
854
|
+
/** Buffer is flushed once it holds this many items. */
|
|
538
855
|
maxRecords;
|
|
856
|
+
/** Buffer is flushed once its estimated byte size reaches this many bytes. */
|
|
539
857
|
maxBytes;
|
|
540
858
|
buffer = [];
|
|
541
859
|
bufferBytes = 0;
|
|
@@ -552,6 +870,7 @@ var BatchingTransport = class extends Transport {
|
|
|
552
870
|
sizeOf(item) {
|
|
553
871
|
return JSON.stringify(item).length;
|
|
554
872
|
}
|
|
873
|
+
/** Buffers the record, flushing the batch once `maxRecords`/`maxBytes` is reached. */
|
|
555
874
|
write(formatted, record) {
|
|
556
875
|
const item = this.toItem(formatted, record);
|
|
557
876
|
this.buffer.push(item);
|
|
@@ -586,7 +905,9 @@ function metaString(meta, key) {
|
|
|
586
905
|
return typeof value === "string" ? value : null;
|
|
587
906
|
}
|
|
588
907
|
var BaseSQLTransport = class extends BatchingTransport {
|
|
908
|
+
/** Table records are inserted into. */
|
|
589
909
|
tableName;
|
|
910
|
+
/** Whether `createTableSQL()` runs before the first insert. Dev/test convenience only. */
|
|
590
911
|
ensureSchema;
|
|
591
912
|
schemaEnsured = false;
|
|
592
913
|
constructor(options = {}) {
|
|
@@ -1059,6 +1380,7 @@ var RedisTransport = class extends BatchingTransport {
|
|
|
1059
1380
|
|
|
1060
1381
|
// src/transports/queue/base-queue-transport.ts
|
|
1061
1382
|
var BaseQueueTransport = class extends BatchingTransport {
|
|
1383
|
+
/** Destination name on the backend — a Kafka topic, a RabbitMQ queue name, an SQS queue URL, or a GCP Pub/Sub topic. */
|
|
1062
1384
|
topic;
|
|
1063
1385
|
constructor(options) {
|
|
1064
1386
|
super(options);
|
|
@@ -1257,8 +1579,11 @@ var PubSubTransport = class extends BaseQueueTransport {
|
|
|
1257
1579
|
|
|
1258
1580
|
// src/transports/cloud/cloudwatch-transport.ts
|
|
1259
1581
|
var CloudWatchTransport = class extends BatchingTransport {
|
|
1582
|
+
/** CloudWatch Logs log group written into. */
|
|
1260
1583
|
logGroupName;
|
|
1584
|
+
/** CloudWatch Logs log stream, within `logGroupName`, written into. */
|
|
1261
1585
|
logStreamName;
|
|
1586
|
+
/** AWS region passed to the real SDK client; `undefined` when `client` is injected or the SDK's own credential-chain resolution is used. */
|
|
1262
1587
|
region;
|
|
1263
1588
|
injectedClient;
|
|
1264
1589
|
client;
|
|
@@ -1326,7 +1651,9 @@ function gcpSeverity(levelValue) {
|
|
|
1326
1651
|
}
|
|
1327
1652
|
}
|
|
1328
1653
|
var CloudLoggingTransport = class extends BatchingTransport {
|
|
1654
|
+
/** GCP log name (the last segment of the log resource path). */
|
|
1329
1655
|
logName;
|
|
1656
|
+
/** GCP project ID passed to the real SDK client; `undefined` when `client` is injected or Application Default Credentials' project is used. */
|
|
1330
1657
|
projectId;
|
|
1331
1658
|
injectedClient;
|
|
1332
1659
|
client;
|
|
@@ -1391,6 +1718,7 @@ function appInsightsSeverity(levelValue) {
|
|
|
1391
1718
|
}
|
|
1392
1719
|
}
|
|
1393
1720
|
var AppInsightsTransport = class extends BatchingTransport {
|
|
1721
|
+
/** Azure Application Insights connection string passed to the real SDK client; `undefined` when `client` is injected. */
|
|
1394
1722
|
connectionString;
|
|
1395
1723
|
injectedClient;
|
|
1396
1724
|
client;
|
|
@@ -1450,8 +1778,11 @@ async function fetchDatadogSender(url, apiKey, batch) {
|
|
|
1450
1778
|
}
|
|
1451
1779
|
}
|
|
1452
1780
|
var DatadogTransport = class extends BatchingTransport {
|
|
1781
|
+
/** Logs intake endpoint derived from `site`. */
|
|
1453
1782
|
url;
|
|
1783
|
+
/** Datadog API key sent in the `DD-API-KEY` header. */
|
|
1454
1784
|
apiKey;
|
|
1785
|
+
/** Datadog site (region) this transport sends to. */
|
|
1455
1786
|
site;
|
|
1456
1787
|
sender;
|
|
1457
1788
|
constructor(options) {
|
|
@@ -1479,7 +1810,9 @@ async function fetchElasticsearchSender(url, headers, body) {
|
|
|
1479
1810
|
}
|
|
1480
1811
|
}
|
|
1481
1812
|
var ElasticsearchTransport = class extends BatchingTransport {
|
|
1813
|
+
/** `_bulk` endpoint derived from the `node` option. */
|
|
1482
1814
|
url;
|
|
1815
|
+
/** Index written into. */
|
|
1483
1816
|
index;
|
|
1484
1817
|
apiKey;
|
|
1485
1818
|
sender;
|
|
@@ -1530,7 +1863,9 @@ function resumeTimestamp(retryAfter, now) {
|
|
|
1530
1863
|
return Number.isNaN(dateMs) ? now + 6e4 : dateMs;
|
|
1531
1864
|
}
|
|
1532
1865
|
var NewRelicTransport = class extends BatchingTransport {
|
|
1866
|
+
/** Ingest endpoint derived from `region`. */
|
|
1533
1867
|
url;
|
|
1868
|
+
/** New Relic account region this transport sends to. */
|
|
1534
1869
|
region;
|
|
1535
1870
|
licenseKey;
|
|
1536
1871
|
sender;
|
|
@@ -1597,6 +1932,7 @@ function defaultColorize() {
|
|
|
1597
1932
|
return env?.NO_COLOR === void 0;
|
|
1598
1933
|
}
|
|
1599
1934
|
var ConsoleTransport = class extends Transport {
|
|
1935
|
+
/** Whether each line is wrapped in an ANSI color escape for its level. */
|
|
1600
1936
|
colorize;
|
|
1601
1937
|
out;
|
|
1602
1938
|
constructor(options = {}) {
|
|
@@ -1604,6 +1940,7 @@ var ConsoleTransport = class extends Transport {
|
|
|
1604
1940
|
this.colorize = options.colorize ?? defaultColorize();
|
|
1605
1941
|
this.out = options.console ?? console;
|
|
1606
1942
|
}
|
|
1943
|
+
/** Writes `formatted` via `console.log`, or `console.error` for ERROR/FATAL records. */
|
|
1607
1944
|
write(formatted, record) {
|
|
1608
1945
|
const level = parseLevel(record.level);
|
|
1609
1946
|
const line = this.colorize ? this.applyColor(formatted, level) : formatted;
|
|
@@ -1617,9 +1954,62 @@ var ConsoleTransport = class extends Transport {
|
|
|
1617
1954
|
return `${COLORS[level]}${formatted}${RESET}`;
|
|
1618
1955
|
}
|
|
1619
1956
|
};
|
|
1957
|
+
|
|
1958
|
+
// src/transports/beacon-transport.ts
|
|
1959
|
+
function defaultBeaconSender(url, batch) {
|
|
1960
|
+
const body = batch.join("\n");
|
|
1961
|
+
const nav = typeof navigator === "undefined" ? void 0 : navigator;
|
|
1962
|
+
if (nav && typeof nav.sendBeacon === "function") {
|
|
1963
|
+
nav.sendBeacon(url, body);
|
|
1964
|
+
return;
|
|
1965
|
+
}
|
|
1966
|
+
void fetch(url, { method: "POST", body, keepalive: true }).catch((error) => {
|
|
1967
|
+
console.error("BeaconTransport: failed to send log batch", error);
|
|
1968
|
+
});
|
|
1969
|
+
}
|
|
1970
|
+
var BeaconTransport = class extends Transport {
|
|
1971
|
+
/** Endpoint each batch is sent to. */
|
|
1972
|
+
url;
|
|
1973
|
+
/** Buffer is flushed once it holds this many lines. */
|
|
1974
|
+
batchSize;
|
|
1975
|
+
sender;
|
|
1976
|
+
batch = [];
|
|
1977
|
+
constructor(url, options = {}) {
|
|
1978
|
+
super(options.formatter);
|
|
1979
|
+
this.url = url;
|
|
1980
|
+
this.batchSize = options.batchSize ?? 20;
|
|
1981
|
+
this.sender = options.sender ?? defaultBeaconSender;
|
|
1982
|
+
}
|
|
1983
|
+
/** Buffers the formatted line, flushing the batch once `batchSize` is reached. */
|
|
1984
|
+
write(formatted) {
|
|
1985
|
+
this.batch.push(formatted);
|
|
1986
|
+
if (this.batch.length >= this.batchSize) {
|
|
1987
|
+
this.flush();
|
|
1988
|
+
}
|
|
1989
|
+
}
|
|
1990
|
+
/** Send the current batch now, even if it hasn't reached `batchSize`. */
|
|
1991
|
+
flush() {
|
|
1992
|
+
if (this.batch.length === 0) {
|
|
1993
|
+
return;
|
|
1994
|
+
}
|
|
1995
|
+
const batch = this.batch;
|
|
1996
|
+
this.batch = [];
|
|
1997
|
+
try {
|
|
1998
|
+
this.sender(this.url, batch);
|
|
1999
|
+
} catch (error) {
|
|
2000
|
+
console.error("BeaconTransport: failed to send log batch", error);
|
|
2001
|
+
}
|
|
2002
|
+
}
|
|
2003
|
+
close() {
|
|
2004
|
+
this.flush();
|
|
2005
|
+
}
|
|
2006
|
+
};
|
|
1620
2007
|
var FileTransport = class extends Transport {
|
|
2008
|
+
/** Path of the file records are appended to. */
|
|
1621
2009
|
path;
|
|
2010
|
+
/** File is rotated once it reaches this many bytes. `0` disables rotation. */
|
|
1622
2011
|
maxBytes;
|
|
2012
|
+
/** How many rotated backups (`.1`, `.2`, ...) are kept. */
|
|
1623
2013
|
backupCount;
|
|
1624
2014
|
fd;
|
|
1625
2015
|
constructor(path$1, options = {}) {
|
|
@@ -1630,6 +2020,7 @@ var FileTransport = class extends Transport {
|
|
|
1630
2020
|
fs.mkdirSync(path.dirname(path$1), { recursive: true });
|
|
1631
2021
|
this.fd = fs.openSync(this.path, "a");
|
|
1632
2022
|
}
|
|
2023
|
+
/** Appends one formatted line to the file, rotating first if `maxBytes` has been exceeded. */
|
|
1633
2024
|
write(formatted) {
|
|
1634
2025
|
fs.writeSync(this.fd, formatted + "\n");
|
|
1635
2026
|
if (this.maxBytes > 0 && fs.fstatSync(this.fd).size >= this.maxBytes) {
|
|
@@ -1676,7 +2067,9 @@ async function fetchSender(url, batch) {
|
|
|
1676
2067
|
}
|
|
1677
2068
|
}
|
|
1678
2069
|
var HTTPTransport = class extends Transport {
|
|
2070
|
+
/** Endpoint each batch is POSTed to. */
|
|
1679
2071
|
url;
|
|
2072
|
+
/** Buffer is flushed once it holds this many lines. */
|
|
1680
2073
|
batchSize;
|
|
1681
2074
|
sender;
|
|
1682
2075
|
batch = [];
|
|
@@ -1686,6 +2079,7 @@ var HTTPTransport = class extends Transport {
|
|
|
1686
2079
|
this.batchSize = options.batchSize ?? 50;
|
|
1687
2080
|
this.sender = options.sender ?? fetchSender;
|
|
1688
2081
|
}
|
|
2082
|
+
/** Buffers the formatted line, flushing the batch once `batchSize` is reached. */
|
|
1689
2083
|
write(formatted) {
|
|
1690
2084
|
this.batch.push(formatted);
|
|
1691
2085
|
if (this.batch.length >= this.batchSize) {
|
|
@@ -1711,13 +2105,182 @@ var HTTPTransport = class extends Transport {
|
|
|
1711
2105
|
}
|
|
1712
2106
|
};
|
|
1713
2107
|
|
|
2108
|
+
// src/core/dispatch-queue.ts
|
|
2109
|
+
function isPromise(value) {
|
|
2110
|
+
return typeof value === "object" && typeof value.then === "function";
|
|
2111
|
+
}
|
|
2112
|
+
function defaultScheduler(run) {
|
|
2113
|
+
if (typeof setImmediate === "function") {
|
|
2114
|
+
setImmediate(run);
|
|
2115
|
+
} else {
|
|
2116
|
+
queueMicrotask(run);
|
|
2117
|
+
}
|
|
2118
|
+
}
|
|
2119
|
+
function defaultOnDrop(count, policy) {
|
|
2120
|
+
console.warn(
|
|
2121
|
+
`DispatchQueue: dropped ${String(count)} record(s) \u2014 queue exceeded its configured size under the "${policy}" backpressure policy`
|
|
2122
|
+
);
|
|
2123
|
+
}
|
|
2124
|
+
var DispatchQueue = class {
|
|
2125
|
+
/** Maximum number of pending tasks held at once, as configured via `DispatchQueueOptions`. */
|
|
2126
|
+
maxSize;
|
|
2127
|
+
/** Backpressure policy applied once `maxSize` is reached, as configured via `DispatchQueueOptions`. */
|
|
2128
|
+
policy;
|
|
2129
|
+
onDrop;
|
|
2130
|
+
warnIntervalMs;
|
|
2131
|
+
tasks = [];
|
|
2132
|
+
draining = false;
|
|
2133
|
+
scheduled = false;
|
|
2134
|
+
idleWaiters = [];
|
|
2135
|
+
droppedSinceWarning = 0;
|
|
2136
|
+
lastWarnAt = 0;
|
|
2137
|
+
constructor(options = {}) {
|
|
2138
|
+
this.maxSize = options.maxSize ?? 1e4;
|
|
2139
|
+
this.policy = options.policy ?? "dropOldest";
|
|
2140
|
+
this.onDrop = options.onDrop ?? defaultOnDrop;
|
|
2141
|
+
this.warnIntervalMs = options.warnIntervalMs ?? 5e3;
|
|
2142
|
+
}
|
|
2143
|
+
/** Number of tasks currently waiting to run. Bounded by `maxSize`. */
|
|
2144
|
+
get size() {
|
|
2145
|
+
return this.tasks.length;
|
|
2146
|
+
}
|
|
2147
|
+
/**
|
|
2148
|
+
* Queue `task` to run outside the current call stack, applying the
|
|
2149
|
+
* configured backpressure policy if the queue is already full. Under
|
|
2150
|
+
* `"block"`, `task` may run synchronously before this call returns.
|
|
2151
|
+
*/
|
|
2152
|
+
enqueue(task) {
|
|
2153
|
+
if (this.tasks.length < this.maxSize) {
|
|
2154
|
+
this.tasks.push(task);
|
|
2155
|
+
this.schedule();
|
|
2156
|
+
return;
|
|
2157
|
+
}
|
|
2158
|
+
switch (this.policy) {
|
|
2159
|
+
case "dropNewest":
|
|
2160
|
+
this.recordDrop();
|
|
2161
|
+
return;
|
|
2162
|
+
case "block":
|
|
2163
|
+
this.runInline(task);
|
|
2164
|
+
return;
|
|
2165
|
+
case "dropOldest":
|
|
2166
|
+
default:
|
|
2167
|
+
this.tasks.shift();
|
|
2168
|
+
this.recordDrop();
|
|
2169
|
+
this.tasks.push(task);
|
|
2170
|
+
this.schedule();
|
|
2171
|
+
return;
|
|
2172
|
+
}
|
|
2173
|
+
}
|
|
2174
|
+
/** Resolves once every task queued so far has run. Safe to call when idle. */
|
|
2175
|
+
async flush() {
|
|
2176
|
+
if (this.tasks.length === 0 && !this.draining) {
|
|
2177
|
+
return;
|
|
2178
|
+
}
|
|
2179
|
+
await new Promise((resolve) => {
|
|
2180
|
+
this.idleWaiters.push(resolve);
|
|
2181
|
+
this.schedule();
|
|
2182
|
+
});
|
|
2183
|
+
}
|
|
2184
|
+
recordDrop() {
|
|
2185
|
+
this.droppedSinceWarning += 1;
|
|
2186
|
+
const now = Date.now();
|
|
2187
|
+
if (now - this.lastWarnAt >= this.warnIntervalMs) {
|
|
2188
|
+
const count = this.droppedSinceWarning;
|
|
2189
|
+
this.droppedSinceWarning = 0;
|
|
2190
|
+
this.lastWarnAt = now;
|
|
2191
|
+
try {
|
|
2192
|
+
this.onDrop(count, this.policy);
|
|
2193
|
+
} catch {
|
|
2194
|
+
}
|
|
2195
|
+
}
|
|
2196
|
+
}
|
|
2197
|
+
runInline(task) {
|
|
2198
|
+
try {
|
|
2199
|
+
const result = task();
|
|
2200
|
+
if (isPromise(result)) {
|
|
2201
|
+
result.catch((error) => {
|
|
2202
|
+
console.error("DispatchQueue: a blocked task failed", error);
|
|
2203
|
+
});
|
|
2204
|
+
}
|
|
2205
|
+
} catch (error) {
|
|
2206
|
+
console.error("DispatchQueue: a blocked task failed", error);
|
|
2207
|
+
}
|
|
2208
|
+
}
|
|
2209
|
+
schedule() {
|
|
2210
|
+
if (this.scheduled) {
|
|
2211
|
+
return;
|
|
2212
|
+
}
|
|
2213
|
+
this.scheduled = true;
|
|
2214
|
+
defaultScheduler(() => {
|
|
2215
|
+
this.scheduled = false;
|
|
2216
|
+
void this.drainAll();
|
|
2217
|
+
});
|
|
2218
|
+
}
|
|
2219
|
+
async drainAll() {
|
|
2220
|
+
if (this.draining) {
|
|
2221
|
+
return;
|
|
2222
|
+
}
|
|
2223
|
+
this.draining = true;
|
|
2224
|
+
try {
|
|
2225
|
+
while (this.tasks.length > 0) {
|
|
2226
|
+
const task = this.tasks.shift();
|
|
2227
|
+
if (!task) {
|
|
2228
|
+
continue;
|
|
2229
|
+
}
|
|
2230
|
+
try {
|
|
2231
|
+
await task();
|
|
2232
|
+
} catch (error) {
|
|
2233
|
+
console.error("DispatchQueue: a queued task failed", error);
|
|
2234
|
+
}
|
|
2235
|
+
}
|
|
2236
|
+
} finally {
|
|
2237
|
+
this.draining = false;
|
|
2238
|
+
const waiters = this.idleWaiters;
|
|
2239
|
+
this.idleWaiters = [];
|
|
2240
|
+
for (const resolve of waiters) {
|
|
2241
|
+
resolve();
|
|
2242
|
+
}
|
|
2243
|
+
}
|
|
2244
|
+
}
|
|
2245
|
+
};
|
|
2246
|
+
var spanIdStore = new async_hooks.AsyncLocalStorage();
|
|
2247
|
+
function currentSpanId() {
|
|
2248
|
+
return spanIdStore.getStore();
|
|
2249
|
+
}
|
|
2250
|
+
function newSpanId() {
|
|
2251
|
+
return crypto.randomBytes(8).toString("hex");
|
|
2252
|
+
}
|
|
2253
|
+
function runInSpan(spanId, fn) {
|
|
2254
|
+
return spanIdStore.run(spanId, fn);
|
|
2255
|
+
}
|
|
2256
|
+
|
|
1714
2257
|
// src/core/logger.ts
|
|
2258
|
+
function formatSpanError(error) {
|
|
2259
|
+
if (error instanceof Error) {
|
|
2260
|
+
return `${error.name}: ${error.message}`;
|
|
2261
|
+
}
|
|
2262
|
+
return String(error);
|
|
2263
|
+
}
|
|
2264
|
+
function withStackFromErr(meta) {
|
|
2265
|
+
const err = meta.err;
|
|
2266
|
+
if (!(err instanceof Error)) {
|
|
2267
|
+
return meta;
|
|
2268
|
+
}
|
|
2269
|
+
const next = { ...meta };
|
|
2270
|
+
delete next.err;
|
|
2271
|
+
next.stack = err.stack ?? `${err.name}: ${err.message}`;
|
|
2272
|
+
return next;
|
|
2273
|
+
}
|
|
1715
2274
|
var Logger = class _Logger {
|
|
2275
|
+
/** This logger's name, as passed to the constructor (or derived via `.child()`). Appears on every record as `logger`. */
|
|
1716
2276
|
name;
|
|
2277
|
+
/** Every transport a written record is sent to. */
|
|
1717
2278
|
transports;
|
|
2279
|
+
/** Every plugin registered via `.use()`, in registration order. */
|
|
1718
2280
|
plugins;
|
|
1719
2281
|
currentLevel;
|
|
1720
2282
|
baseMeta;
|
|
2283
|
+
dispatchQueue;
|
|
1721
2284
|
constructor(name, options = {}) {
|
|
1722
2285
|
this.name = name;
|
|
1723
2286
|
this.currentLevel = parseLevel(options.level ?? 20 /* INFO */);
|
|
@@ -1727,10 +2290,13 @@ var Logger = class _Logger {
|
|
|
1727
2290
|
this.use(plugin);
|
|
1728
2291
|
}
|
|
1729
2292
|
this.baseMeta = options.meta ? { ...options.meta } : {};
|
|
2293
|
+
this.dispatchQueue = new DispatchQueue(options.queue);
|
|
1730
2294
|
}
|
|
2295
|
+
/** This logger's current minimum level — records below it are filtered before any plugin runs. */
|
|
1731
2296
|
get level() {
|
|
1732
2297
|
return this.currentLevel;
|
|
1733
2298
|
}
|
|
2299
|
+
/** Changes the minimum level records must meet to reach a transport. Accepts a `Level`, its numeric weight, or its name. */
|
|
1734
2300
|
setLevel(level) {
|
|
1735
2301
|
this.currentLevel = parseLevel(level);
|
|
1736
2302
|
}
|
|
@@ -1744,20 +2310,41 @@ var Logger = class _Logger {
|
|
|
1744
2310
|
this.plugins.push(typeof plugin === "function" ? new FunctionPlugin(plugin) : plugin);
|
|
1745
2311
|
return this;
|
|
1746
2312
|
}
|
|
1747
|
-
/**
|
|
1748
|
-
|
|
2313
|
+
/** Number of dispatched records not yet written to their transports. Bounded by the `queue` option. */
|
|
2314
|
+
get queueSize() {
|
|
2315
|
+
return this.dispatchQueue.size;
|
|
2316
|
+
}
|
|
2317
|
+
/**
|
|
2318
|
+
* Waits for every record dispatched so far to reach its transports'
|
|
2319
|
+
* `write()` (and any plugin `afterLog` hooks). Note this does *not* force
|
|
2320
|
+
* a batching transport (SQL, a queue, `HTTPTransport`, ...) to send a
|
|
2321
|
+
* batch still under its own `maxRecords`/`maxBytes` threshold early — it
|
|
2322
|
+
* only guarantees the record has been handed to that transport, the same
|
|
2323
|
+
* contract `write()` always had. Before a process may pause or exit
|
|
2324
|
+
* (a serverless freeze, a shutdown signal), prefer `withLambda`/
|
|
2325
|
+
* `installShutdownHandlers`, which additionally force every batching
|
|
2326
|
+
* transport to send its current buffer regardless of threshold.
|
|
2327
|
+
*/
|
|
2328
|
+
async flush() {
|
|
2329
|
+
await this.dispatchQueue.flush();
|
|
2330
|
+
}
|
|
2331
|
+
/** Flush every pending record, then close every attached transport. Call once, on shutdown. */
|
|
2332
|
+
async close() {
|
|
2333
|
+
await this.flush();
|
|
1749
2334
|
for (const transport of this.transports) {
|
|
1750
2335
|
transport.close();
|
|
1751
2336
|
}
|
|
1752
2337
|
}
|
|
1753
|
-
/** A logger scoped under this one, inheriting its level, transports, and
|
|
2338
|
+
/** A logger scoped under this one, inheriting its level, transports, plugins, and dispatch queue. */
|
|
1754
2339
|
child(name, meta = {}) {
|
|
1755
|
-
|
|
2340
|
+
const child = new _Logger(`${this.name}.${name}`, {
|
|
1756
2341
|
level: this.currentLevel,
|
|
1757
2342
|
transports: this.transports,
|
|
1758
2343
|
plugins: this.plugins,
|
|
1759
2344
|
meta: { ...this.baseMeta, ...meta }
|
|
1760
2345
|
});
|
|
2346
|
+
child.dispatchQueue = this.dispatchQueue;
|
|
2347
|
+
return child;
|
|
1761
2348
|
}
|
|
1762
2349
|
notifyError(plugin, error, record) {
|
|
1763
2350
|
try {
|
|
@@ -1773,8 +2360,12 @@ var Logger = class _Logger {
|
|
|
1773
2360
|
level,
|
|
1774
2361
|
logger: this.name,
|
|
1775
2362
|
message,
|
|
1776
|
-
meta: { ...this.baseMeta, ...meta }
|
|
2363
|
+
meta: { ...this.baseMeta, ...currentContext(), ...withStackFromErr(meta) }
|
|
1777
2364
|
});
|
|
2365
|
+
const parentSpanId = currentSpanId();
|
|
2366
|
+
if (parentSpanId !== void 0) {
|
|
2367
|
+
record.meta.parentSpanId ??= parentSpanId;
|
|
2368
|
+
}
|
|
1778
2369
|
for (const plugin of this.plugins) {
|
|
1779
2370
|
let result;
|
|
1780
2371
|
try {
|
|
@@ -1788,8 +2379,18 @@ var Logger = class _Logger {
|
|
|
1788
2379
|
}
|
|
1789
2380
|
record = result;
|
|
1790
2381
|
}
|
|
2382
|
+
this.dispatchQueue.enqueue(() => {
|
|
2383
|
+
this.writeAndNotify(record);
|
|
2384
|
+
});
|
|
2385
|
+
return record;
|
|
2386
|
+
}
|
|
2387
|
+
writeAndNotify(record) {
|
|
1791
2388
|
for (const transport of this.transports) {
|
|
1792
|
-
|
|
2389
|
+
try {
|
|
2390
|
+
transport.write(transport.format(record), record);
|
|
2391
|
+
} catch (error) {
|
|
2392
|
+
console.error(`${transport.constructor.name}: failed to write a log record`, error);
|
|
2393
|
+
}
|
|
1793
2394
|
}
|
|
1794
2395
|
for (const plugin of this.plugins) {
|
|
1795
2396
|
try {
|
|
@@ -1798,28 +2399,155 @@ var Logger = class _Logger {
|
|
|
1798
2399
|
this.notifyError(plugin, error, record);
|
|
1799
2400
|
}
|
|
1800
2401
|
}
|
|
1801
|
-
return record;
|
|
1802
2402
|
}
|
|
2403
|
+
/** Logs at `TRACE` — the lowest level, for fine-grained diagnostic detail. Returns the record, or `null` if filtered/dropped. */
|
|
1803
2404
|
trace(message, meta = {}) {
|
|
1804
2405
|
return this.dispatch(5 /* TRACE */, message, meta);
|
|
1805
2406
|
}
|
|
2407
|
+
/** Logs at `DEBUG`. Returns the record, or `null` if filtered/dropped. */
|
|
1806
2408
|
debug(message, meta = {}) {
|
|
1807
2409
|
return this.dispatch(10 /* DEBUG */, message, meta);
|
|
1808
2410
|
}
|
|
2411
|
+
/** Logs at `INFO`. Returns the record, or `null` if filtered/dropped. */
|
|
1809
2412
|
info(message, meta = {}) {
|
|
1810
2413
|
return this.dispatch(20 /* INFO */, message, meta);
|
|
1811
2414
|
}
|
|
2415
|
+
/** Logs at `WARN`. Returns the record, or `null` if filtered/dropped. */
|
|
1812
2416
|
warn(message, meta = {}) {
|
|
1813
2417
|
return this.dispatch(30 /* WARN */, message, meta);
|
|
1814
2418
|
}
|
|
2419
|
+
/** Logs at `ERROR`. Returns the record, or `null` if filtered/dropped. */
|
|
1815
2420
|
error(message, meta = {}) {
|
|
1816
2421
|
return this.dispatch(40 /* ERROR */, message, meta);
|
|
1817
2422
|
}
|
|
2423
|
+
/** Logs at `FATAL` — the highest level, for errors that precede an unrecoverable failure. Returns the record, or `null` if filtered/dropped. */
|
|
1818
2424
|
fatal(message, meta = {}) {
|
|
1819
2425
|
return this.dispatch(50 /* FATAL */, message, meta);
|
|
1820
2426
|
}
|
|
2427
|
+
/** `.info()` tagged `meta.kind = "thought"` — an agent's internal reasoning step, for harness/agentic tracing. */
|
|
2428
|
+
thought(message, meta = {}) {
|
|
2429
|
+
return this.dispatch(20 /* INFO */, message, { kind: "thought", ...meta });
|
|
2430
|
+
}
|
|
2431
|
+
/** `.info()` tagged `meta.kind = "action"` — an agent taking an action (a tool call, an LLM request), for harness/agentic tracing. */
|
|
2432
|
+
action(message, meta = {}) {
|
|
2433
|
+
return this.dispatch(20 /* INFO */, message, { kind: "action", ...meta });
|
|
2434
|
+
}
|
|
2435
|
+
/** `.info()` tagged `meta.kind = "observation"` — the result an agent observed from an action, for harness/agentic tracing. */
|
|
2436
|
+
observation(message, meta = {}) {
|
|
2437
|
+
return this.dispatch(20 /* INFO */, message, { kind: "observation", ...meta });
|
|
2438
|
+
}
|
|
2439
|
+
/** `.info()` tagged `meta.kind = "decision"` — an agent's concluding decision for a step or run, for harness/agentic tracing. */
|
|
2440
|
+
decision(message, meta = {}) {
|
|
2441
|
+
return this.dispatch(20 /* INFO */, message, { kind: "decision", ...meta });
|
|
2442
|
+
}
|
|
2443
|
+
/**
|
|
2444
|
+
* `await logger.span("callLlm", async () => {...})` — runs `fn`, and on
|
|
2445
|
+
* settling (success or throw) emits one record for the span itself
|
|
2446
|
+
* carrying `meta.spanId` and `meta.durationMs`. Every record logged
|
|
2447
|
+
* inside `fn` — through any method, and through any further `await` —
|
|
2448
|
+
* is automatically stamped with `meta.parentSpanId` pointing at this
|
|
2449
|
+
* span, so nested/sub-agent calls reconstruct their exact nesting when
|
|
2450
|
+
* sorted by `spanId`/`parentSpanId`.
|
|
2451
|
+
*
|
|
2452
|
+
* Still emits its record — at `ERROR`, with `meta.error` set — if `fn`
|
|
2453
|
+
* throws; the error itself propagates unchanged to the caller.
|
|
2454
|
+
*
|
|
2455
|
+
* `spanId`/`parentSpanId` normally auto-generate/auto-nest; pass them in
|
|
2456
|
+
* `options` to adopt an id handed in from elsewhere (e.g. a framework
|
|
2457
|
+
* adapter translating an id it already received).
|
|
2458
|
+
*/
|
|
2459
|
+
async span(name, fn, options = {}) {
|
|
2460
|
+
const { spanId: explicitSpanId, parentSpanId: explicitParentSpanId, ...meta } = options;
|
|
2461
|
+
const spanId = explicitSpanId ?? newSpanId();
|
|
2462
|
+
const start = performance.now();
|
|
2463
|
+
try {
|
|
2464
|
+
const result = await runInSpan(spanId, () => fn());
|
|
2465
|
+
this.finishSpan(name, spanId, explicitParentSpanId, performance.now() - start, meta);
|
|
2466
|
+
return result;
|
|
2467
|
+
} catch (error) {
|
|
2468
|
+
this.finishSpan(name, spanId, explicitParentSpanId, performance.now() - start, meta, error);
|
|
2469
|
+
throw error;
|
|
2470
|
+
}
|
|
2471
|
+
}
|
|
2472
|
+
finishSpan(name, spanId, explicitParentSpanId, durationMs, meta, error) {
|
|
2473
|
+
const fullMeta = {
|
|
2474
|
+
spanId,
|
|
2475
|
+
durationMs: Math.round(durationMs * 1e3) / 1e3,
|
|
2476
|
+
...meta
|
|
2477
|
+
};
|
|
2478
|
+
if (explicitParentSpanId !== void 0) {
|
|
2479
|
+
fullMeta.parentSpanId = explicitParentSpanId;
|
|
2480
|
+
}
|
|
2481
|
+
fullMeta.kind ??= "span";
|
|
2482
|
+
if (error !== void 0) {
|
|
2483
|
+
fullMeta.error = formatSpanError(error);
|
|
2484
|
+
}
|
|
2485
|
+
this.dispatch(error !== void 0 ? 40 /* ERROR */ : 20 /* INFO */, name, fullMeta);
|
|
2486
|
+
}
|
|
1821
2487
|
};
|
|
1822
2488
|
|
|
2489
|
+
// src/core/serverless.ts
|
|
2490
|
+
async function flushEverything(logger) {
|
|
2491
|
+
await logger.flush();
|
|
2492
|
+
for (const transport of logger.transports) {
|
|
2493
|
+
if (!hasFlush(transport)) {
|
|
2494
|
+
continue;
|
|
2495
|
+
}
|
|
2496
|
+
try {
|
|
2497
|
+
await transport.flush();
|
|
2498
|
+
} catch (error) {
|
|
2499
|
+
console.error(`${transport.constructor.name}: failed to flush`, error);
|
|
2500
|
+
}
|
|
2501
|
+
}
|
|
2502
|
+
}
|
|
2503
|
+
function withFlush(logger, fn) {
|
|
2504
|
+
return async (...args) => {
|
|
2505
|
+
try {
|
|
2506
|
+
return await fn(...args);
|
|
2507
|
+
} finally {
|
|
2508
|
+
await flushEverything(logger);
|
|
2509
|
+
}
|
|
2510
|
+
};
|
|
2511
|
+
}
|
|
2512
|
+
var withLambda = withFlush;
|
|
2513
|
+
var withCloudFunction = withFlush;
|
|
2514
|
+
var withAzureFunction = withFlush;
|
|
2515
|
+
|
|
2516
|
+
// src/core/shutdown.ts
|
|
2517
|
+
function installShutdownHandlers(logger, options = {}) {
|
|
2518
|
+
const signals = options.signals ?? ["SIGTERM", "SIGINT"];
|
|
2519
|
+
let closed = false;
|
|
2520
|
+
const shutdown = (exitAfter) => {
|
|
2521
|
+
if (closed) {
|
|
2522
|
+
return;
|
|
2523
|
+
}
|
|
2524
|
+
closed = true;
|
|
2525
|
+
logger.close().catch((error) => {
|
|
2526
|
+
console.error("installShutdownHandlers: logger.close() failed during shutdown", error);
|
|
2527
|
+
}).finally(() => {
|
|
2528
|
+
if (exitAfter) {
|
|
2529
|
+
process.exit(0);
|
|
2530
|
+
}
|
|
2531
|
+
});
|
|
2532
|
+
};
|
|
2533
|
+
const onBeforeExit = () => {
|
|
2534
|
+
shutdown(false);
|
|
2535
|
+
};
|
|
2536
|
+
const onSignal = () => {
|
|
2537
|
+
shutdown(true);
|
|
2538
|
+
};
|
|
2539
|
+
process.once("beforeExit", onBeforeExit);
|
|
2540
|
+
for (const signal of signals) {
|
|
2541
|
+
process.once(signal, onSignal);
|
|
2542
|
+
}
|
|
2543
|
+
return () => {
|
|
2544
|
+
process.removeListener("beforeExit", onBeforeExit);
|
|
2545
|
+
for (const signal of signals) {
|
|
2546
|
+
process.removeListener(signal, onSignal);
|
|
2547
|
+
}
|
|
2548
|
+
};
|
|
2549
|
+
}
|
|
2550
|
+
|
|
1823
2551
|
// src/index.ts
|
|
1824
2552
|
var VERSION = "0.3.0";
|
|
1825
2553
|
|
|
@@ -1828,14 +2556,17 @@ exports.AppInsightsTransport = AppInsightsTransport;
|
|
|
1828
2556
|
exports.BaseQueueTransport = BaseQueueTransport;
|
|
1829
2557
|
exports.BaseSQLTransport = BaseSQLTransport;
|
|
1830
2558
|
exports.BatchingTransport = BatchingTransport;
|
|
2559
|
+
exports.BeaconTransport = BeaconTransport;
|
|
1831
2560
|
exports.CloudLoggingTransport = CloudLoggingTransport;
|
|
1832
2561
|
exports.CloudWatchTransport = CloudWatchTransport;
|
|
1833
2562
|
exports.CollectingTransport = CollectingTransport;
|
|
1834
2563
|
exports.ConsoleTransport = ConsoleTransport;
|
|
1835
2564
|
exports.ContextPlugin = ContextPlugin;
|
|
1836
2565
|
exports.DEFAULT_PII_PATTERNS = DEFAULT_PII_PATTERNS;
|
|
2566
|
+
exports.DEFAULT_PINO_LEVEL_MAP = DEFAULT_PINO_LEVEL_MAP;
|
|
1837
2567
|
exports.DEFAULT_REDACTED_KEYS = DEFAULT_REDACTED_KEYS;
|
|
1838
2568
|
exports.DatadogTransport = DatadogTransport;
|
|
2569
|
+
exports.DispatchQueue = DispatchQueue;
|
|
1839
2570
|
exports.DynamoDBTransport = DynamoDBTransport;
|
|
1840
2571
|
exports.ElasticsearchTransport = ElasticsearchTransport;
|
|
1841
2572
|
exports.EmailAlertPlugin = EmailAlertPlugin;
|
|
@@ -1846,27 +2577,45 @@ exports.HTTPTransport = HTTPTransport;
|
|
|
1846
2577
|
exports.JSONFormatter = JSONFormatter;
|
|
1847
2578
|
exports.KafkaTransport = KafkaTransport;
|
|
1848
2579
|
exports.Level = Level;
|
|
2580
|
+
exports.LogQuillPinoDestination = LogQuillPinoDestination;
|
|
1849
2581
|
exports.Logger = Logger;
|
|
1850
2582
|
exports.MongoDBTransport = MongoDBTransport;
|
|
1851
2583
|
exports.MySQLTransport = MySQLTransport;
|
|
1852
2584
|
exports.NewRelicTransport = NewRelicTransport;
|
|
2585
|
+
exports.OtelSpanProcessor = OtelSpanProcessor;
|
|
1853
2586
|
exports.PIIRedactPlugin = PIIRedactPlugin;
|
|
1854
2587
|
exports.PagerDutyAlertPlugin = PagerDutyAlertPlugin;
|
|
1855
2588
|
exports.PostgresTransport = PostgresTransport;
|
|
1856
2589
|
exports.PubSubTransport = PubSubTransport;
|
|
1857
2590
|
exports.RabbitMQTransport = RabbitMQTransport;
|
|
2591
|
+
exports.RateLimitPlugin = RateLimitPlugin;
|
|
1858
2592
|
exports.RedactPlugin = RedactPlugin;
|
|
1859
2593
|
exports.RedisTransport = RedisTransport;
|
|
2594
|
+
exports.RunPlugin = RunPlugin;
|
|
1860
2595
|
exports.SQLiteTransport = SQLiteTransport;
|
|
1861
2596
|
exports.SQSTransport = SQSTransport;
|
|
1862
2597
|
exports.SamplingPlugin = SamplingPlugin;
|
|
1863
2598
|
exports.SlackAlertPlugin = SlackAlertPlugin;
|
|
1864
2599
|
exports.TamperEvidentPlugin = TamperEvidentPlugin;
|
|
2600
|
+
exports.TraceContextPlugin = TraceContextPlugin;
|
|
1865
2601
|
exports.Transport = Transport;
|
|
1866
2602
|
exports.VERSION = VERSION;
|
|
2603
|
+
exports.bindContext = bindContext;
|
|
1867
2604
|
exports.createRecord = createRecord;
|
|
2605
|
+
exports.currentContext = currentContext;
|
|
2606
|
+
exports.defaultResolveActiveOtelTraceId = defaultResolveActiveOtelTraceId;
|
|
2607
|
+
exports.generateTraceId = generateTraceId;
|
|
2608
|
+
exports.getTraceparent = getTraceparent;
|
|
2609
|
+
exports.hasFlush = hasFlush;
|
|
2610
|
+
exports.installShutdownHandlers = installShutdownHandlers;
|
|
1868
2611
|
exports.levelName = levelName;
|
|
1869
2612
|
exports.parseLevel = parseLevel;
|
|
2613
|
+
exports.parseTraceHeader = parseTraceHeader;
|
|
2614
|
+
exports.setTraceparent = setTraceparent;
|
|
1870
2615
|
exports.utcTimestamp = utcTimestamp;
|
|
2616
|
+
exports.withAzureFunction = withAzureFunction;
|
|
2617
|
+
exports.withCloudFunction = withCloudFunction;
|
|
2618
|
+
exports.withFlush = withFlush;
|
|
2619
|
+
exports.withLambda = withLambda;
|
|
1871
2620
|
//# sourceMappingURL=index.cjs.map
|
|
1872
2621
|
//# sourceMappingURL=index.cjs.map
|