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