vestig 0.11.4 → 0.13.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 +95 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +4 -0
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +9 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts +85 -0
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +209 -2
- package/dist/logger.js.map +1 -1
- package/dist/metrics/index.d.ts +2 -0
- package/dist/metrics/index.d.ts.map +1 -0
- package/dist/metrics/index.js +2 -0
- package/dist/metrics/index.js.map +1 -0
- package/dist/metrics/prometheus.d.ts +109 -0
- package/dist/metrics/prometheus.d.ts.map +1 -0
- package/dist/metrics/prometheus.js +162 -0
- package/dist/metrics/prometheus.js.map +1 -0
- package/dist/sampling/index.d.ts +2 -0
- package/dist/sampling/index.d.ts.map +1 -1
- package/dist/sampling/index.js +2 -0
- package/dist/sampling/index.js.map +1 -1
- package/dist/sampling/tail.d.ts +76 -0
- package/dist/sampling/tail.d.ts.map +1 -0
- package/dist/sampling/tail.js +138 -0
- package/dist/sampling/tail.js.map +1 -0
- package/dist/transports/batch.d.ts +2 -0
- package/dist/transports/batch.d.ts.map +1 -1
- package/dist/transports/batch.js +13 -3
- package/dist/transports/batch.js.map +1 -1
- package/dist/transports/file.d.ts +14 -1
- package/dist/transports/file.d.ts.map +1 -1
- package/dist/transports/file.js +59 -4
- package/dist/transports/file.js.map +1 -1
- package/dist/transports/http.d.ts +29 -1
- package/dist/transports/http.d.ts.map +1 -1
- package/dist/transports/http.js +63 -6
- package/dist/transports/http.js.map +1 -1
- package/dist/transports/sentry.d.ts +83 -0
- package/dist/transports/sentry.d.ts.map +1 -0
- package/dist/transports/sentry.js +283 -0
- package/dist/transports/sentry.js.map +1 -0
- package/dist/types.d.ts +149 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/buffer.d.ts +33 -1
- package/dist/utils/buffer.d.ts.map +1 -1
- package/dist/utils/buffer.js +40 -2
- package/dist/utils/buffer.js.map +1 -1
- package/dist/utils/dedupe.d.ts +80 -0
- package/dist/utils/dedupe.d.ts.map +1 -0
- package/dist/utils/dedupe.js +173 -0
- package/dist/utils/dedupe.js.map +1 -0
- package/dist/utils/sanitize.d.ts +23 -1
- package/dist/utils/sanitize.d.ts.map +1 -1
- package/dist/utils/sanitize.js +113 -8
- package/dist/utils/sanitize.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/wide-events/builder.d.ts +51 -0
- package/dist/wide-events/builder.d.ts.map +1 -0
- package/dist/wide-events/builder.js +177 -0
- package/dist/wide-events/builder.js.map +1 -0
- package/dist/wide-events/context.d.ts +57 -0
- package/dist/wide-events/context.d.ts.map +1 -0
- package/dist/wide-events/context.js +148 -0
- package/dist/wide-events/context.js.map +1 -0
- package/dist/wide-events/index.d.ts +6 -0
- package/dist/wide-events/index.d.ts.map +1 -0
- package/dist/wide-events/index.js +7 -0
- package/dist/wide-events/index.js.map +1 -0
- package/dist/wide-events/schemas/http.d.ts +179 -0
- package/dist/wide-events/schemas/http.d.ts.map +1 -0
- package/dist/wide-events/schemas/http.js +25 -0
- package/dist/wide-events/schemas/http.js.map +1 -0
- package/dist/wide-events/schemas/index.d.ts +5 -0
- package/dist/wide-events/schemas/index.d.ts.map +1 -0
- package/dist/wide-events/schemas/index.js +5 -0
- package/dist/wide-events/schemas/index.js.map +1 -0
- package/dist/wide-events/schemas/job.d.ts +130 -0
- package/dist/wide-events/schemas/job.d.ts.map +1 -0
- package/dist/wide-events/schemas/job.js +27 -0
- package/dist/wide-events/schemas/job.js.map +1 -0
- package/dist/wide-events/types.d.ts +216 -0
- package/dist/wide-events/types.d.ts.map +1 -0
- package/dist/wide-events/types.js +2 -0
- package/dist/wide-events/types.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -27,6 +27,7 @@ A modern, runtime-agnostic structured logging library with automatic PII sanitiz
|
|
|
27
27
|
| Runtime Agnostic | ✅ | ❌ | ❌ |
|
|
28
28
|
| Auto PII Sanitization | ✅ | ❌ | ❌ |
|
|
29
29
|
| GDPR/HIPAA/PCI-DSS Presets | ✅ | ❌ | ❌ |
|
|
30
|
+
| Wide Events / Tail Sampling | ✅ | ❌ | ❌ |
|
|
30
31
|
| Zero Config | ✅ | ✅ | ❌ |
|
|
31
32
|
| TypeScript First | ✅ | ✅ | ⚠️ |
|
|
32
33
|
| Edge Runtime Support | ✅ | ❌ | ❌ |
|
|
@@ -78,7 +79,7 @@ log.info('User login', {
|
|
|
78
79
|
Send logs to multiple destinations simultaneously:
|
|
79
80
|
|
|
80
81
|
```typescript
|
|
81
|
-
import { createLogger,
|
|
82
|
+
import { createLogger, HTTPTransport, DatadogTransport, SentryTransport } from 'vestig'
|
|
82
83
|
|
|
83
84
|
const log = createLogger()
|
|
84
85
|
|
|
@@ -97,10 +98,19 @@ log.addTransport(new DatadogTransport({
|
|
|
97
98
|
tags: ['env:production'],
|
|
98
99
|
}))
|
|
99
100
|
|
|
101
|
+
// Add Sentry for error tracking
|
|
102
|
+
log.addTransport(new SentryTransport({
|
|
103
|
+
name: 'sentry',
|
|
104
|
+
dsn: process.env.SENTRY_DSN,
|
|
105
|
+
environment: 'production',
|
|
106
|
+
release: 'my-app@1.0.0',
|
|
107
|
+
minLevel: 'warn', // Only send warn/error to Sentry
|
|
108
|
+
}))
|
|
109
|
+
|
|
100
110
|
// Initialize transports (starts flush timers)
|
|
101
111
|
await log.init()
|
|
102
112
|
|
|
103
|
-
// All logs go to console, HTTP endpoint, and
|
|
113
|
+
// All logs go to console, HTTP endpoint, Datadog, and Sentry
|
|
104
114
|
log.info('Server started', { port: 3000 })
|
|
105
115
|
```
|
|
106
116
|
|
|
@@ -112,6 +122,7 @@ log.info('Server started', { port: 3000 })
|
|
|
112
122
|
| `HTTPTransport` | Send to any HTTP endpoint | Custom log aggregation |
|
|
113
123
|
| `FileTransport` | Write to files with rotation | Server-side logging |
|
|
114
124
|
| `DatadogTransport` | Datadog Log Management | Production observability |
|
|
125
|
+
| `SentryTransport` | Sentry error tracking | Error monitoring, alerting |
|
|
115
126
|
|
|
116
127
|
### PII Sanitization with Presets
|
|
117
128
|
|
|
@@ -203,6 +214,58 @@ export async function GET(req: Request) {
|
|
|
203
214
|
}
|
|
204
215
|
```
|
|
205
216
|
|
|
217
|
+
### Wide Events (Canonical Log Lines)
|
|
218
|
+
|
|
219
|
+
Wide Events capture **all context about a complete operation in ONE structured event**. Instead of scattered logs, you get a single comprehensive record per request.
|
|
220
|
+
|
|
221
|
+
```typescript
|
|
222
|
+
import { createLogger, createWideEvent } from 'vestig'
|
|
223
|
+
|
|
224
|
+
const log = createLogger({
|
|
225
|
+
tailSampling: {
|
|
226
|
+
enabled: true,
|
|
227
|
+
alwaysKeepStatuses: ['error'], // 100% of errors
|
|
228
|
+
slowThresholdMs: 2000, // 100% of slow requests
|
|
229
|
+
successSampleRate: 0.1, // 10% of successful requests
|
|
230
|
+
vipUserIds: ['user-123'], // 100% for VIP users
|
|
231
|
+
}
|
|
232
|
+
})
|
|
233
|
+
|
|
234
|
+
// Create and enrich the wide event throughout the request
|
|
235
|
+
const event = createWideEvent({ type: 'http.request' })
|
|
236
|
+
|
|
237
|
+
// Add HTTP context
|
|
238
|
+
event.merge('http', {
|
|
239
|
+
method: 'POST',
|
|
240
|
+
path: '/api/checkout',
|
|
241
|
+
status_code: 200,
|
|
242
|
+
})
|
|
243
|
+
|
|
244
|
+
// Add user context
|
|
245
|
+
event.merge('user', {
|
|
246
|
+
id: 'user-456',
|
|
247
|
+
subscription: 'premium',
|
|
248
|
+
})
|
|
249
|
+
|
|
250
|
+
// Add performance metrics
|
|
251
|
+
event.merge('performance', {
|
|
252
|
+
db_query_ms: 45,
|
|
253
|
+
external_api_ms: 230,
|
|
254
|
+
})
|
|
255
|
+
|
|
256
|
+
// End and emit the event
|
|
257
|
+
const completedEvent = event.end({ status: 'success' })
|
|
258
|
+
log.emitWideEvent(completedEvent)
|
|
259
|
+
|
|
260
|
+
// Output: ONE event with 50+ fields, easily queryable
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
**Why Wide Events?**
|
|
264
|
+
- **Debug faster**: All context in one place, no log correlation needed
|
|
265
|
+
- **Reduce costs**: Tail sampling keeps 100% of errors, samples success
|
|
266
|
+
- **Better queries**: "Show me slow requests from premium users with payment errors"
|
|
267
|
+
- **No missing context**: You'll never again lose the request that caused an error
|
|
268
|
+
|
|
206
269
|
## Configuration
|
|
207
270
|
|
|
208
271
|
### Environment Variables
|
|
@@ -306,6 +369,36 @@ Generate correlation IDs (requestId, traceId, spanId).
|
|
|
306
369
|
|
|
307
370
|
Create a sanitizer from a preset name.
|
|
308
371
|
|
|
372
|
+
### `createWideEvent(config)`
|
|
373
|
+
|
|
374
|
+
Create a wide event builder for accumulating context throughout a request.
|
|
375
|
+
|
|
376
|
+
```typescript
|
|
377
|
+
const event = createWideEvent({ type: 'http.request' })
|
|
378
|
+
event.set('http', 'method', 'POST')
|
|
379
|
+
event.merge('user', { id: 'user-123', tier: 'premium' })
|
|
380
|
+
const completed = event.end({ status: 'success' })
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
### `log.emitWideEvent(event)`
|
|
384
|
+
|
|
385
|
+
Emit a completed wide event through the logger's transports. Applies tail sampling if configured.
|
|
386
|
+
|
|
387
|
+
### `createTailSampler(config)`
|
|
388
|
+
|
|
389
|
+
Create a tail sampler for wide events. Used internally by `emitWideEvent()` but can be used standalone.
|
|
390
|
+
|
|
391
|
+
```typescript
|
|
392
|
+
const sampler = createTailSampler({
|
|
393
|
+
alwaysKeepStatuses: ['error'],
|
|
394
|
+
slowThresholdMs: 2000,
|
|
395
|
+
successSampleRate: 0.1,
|
|
396
|
+
})
|
|
397
|
+
if (sampler.shouldSample(event).sampled) {
|
|
398
|
+
log.emitWideEvent(event)
|
|
399
|
+
}
|
|
400
|
+
```
|
|
401
|
+
|
|
309
402
|
## Contributing
|
|
310
403
|
|
|
311
404
|
We love contributions! Please read our [Contributing Guide](https://github.com/Arakiss/vestig/blob/main/CONTRIBUTING.md) to get started.
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAwB,YAAY,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAA;AAEvF;;GAEG;AACH,eAAO,MAAM,QAAQ;;;;;CAKX,CAAA;AA4CV;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,oBAAoB,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAwB,YAAY,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAA;AAEvF;;GAEG;AACH,eAAO,MAAM,QAAQ;;;;;CAKX,CAAA;AA4CV;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,oBAAoB,CAevD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,UAAU,CAAC,EAAE,YAAY,GAAG,oBAAoB,CAe3E"}
|
package/dist/config.js
CHANGED
|
@@ -61,6 +61,8 @@ export function getDefaultConfig() {
|
|
|
61
61
|
context: getEnvContext(),
|
|
62
62
|
namespace: '',
|
|
63
63
|
sampling: undefined,
|
|
64
|
+
dedupe: undefined,
|
|
65
|
+
tailSampling: undefined,
|
|
64
66
|
};
|
|
65
67
|
}
|
|
66
68
|
/**
|
|
@@ -77,6 +79,8 @@ export function mergeConfig(userConfig) {
|
|
|
77
79
|
context: { ...defaults.context, ...userConfig?.context },
|
|
78
80
|
namespace: userConfig?.namespace ?? defaults.namespace,
|
|
79
81
|
sampling: userConfig?.sampling ?? defaults.sampling,
|
|
82
|
+
dedupe: userConfig?.dedupe ?? defaults.dedupe,
|
|
83
|
+
tailSampling: userConfig?.tailSampling ?? defaults.tailSampling,
|
|
80
84
|
};
|
|
81
85
|
}
|
|
82
86
|
//# sourceMappingURL=config.js.map
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAGxC;;GAEG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG;IACvB,KAAK,EAAE,cAAc;IACrB,OAAO,EAAE,gBAAgB;IACzB,UAAU,EAAE,mBAAmB;IAC/B,QAAQ,EAAE,iBAAiB;CAClB,CAAA;AAEV;;GAEG;AACH,SAAS,MAAM,CAAC,GAAW;IAC1B,IAAI,OAAO,OAAO,KAAK,WAAW,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;QACnD,OAAO,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IACxB,CAAC;IACD,OAAO,SAAS,CAAA;AACjB,CAAC;AAED;;GAEG;AACH,SAAS,YAAY;IACpB,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,CAAA;IAClC,OAAO,OAAO,KAAK,YAAY,CAAA;AAChC,CAAC;AAED;;GAEG;AACH,SAAS,SAAS,CAAC,KAAyB,EAAE,QAAiB;IAC9D,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,QAAQ,CAAA;IACxC,OAAO,KAAK,CAAC,WAAW,EAAE,KAAK,MAAM,IAAI,KAAK,KAAK,GAAG,CAAA;AACvD,CAAC;AAED;;GAEG;AACH,SAAS,aAAa;IACrB,MAAM,OAAO,GAAe,EAAE,CAAA;IAC9B,IAAI,OAAO,OAAO,KAAK,WAAW,IAAI,CAAC,OAAO,CAAC,GAAG;QAAE,OAAO,OAAO,CAAA;IAElE,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACxD,IAAI,GAAG,CAAC,UAAU,CAAC,iBAAiB,CAAC,IAAI,KAAK,EAAE,CAAC;YAChD,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC,iBAAiB,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,CAAA;YACnE,OAAO,CAAC,UAAU,CAAC,GAAG,KAAK,CAAA;QAC5B,CAAC;IACF,CAAC;IACD,OAAO,OAAO,CAAA;AACf,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB;IAC/B,MAAM,MAAM,GAAG,YAAY,EAAE,CAAA;IAE7B,OAAO;QACN,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;QACtE,OAAO,EAAE,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC;QAClD,UAAU,EAAE,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAC1D,QAAQ,EAAE,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC;QACpD,cAAc,EAAE,EAAE;QAClB,OAAO,EAAE,aAAa,EAAE;QACxB,SAAS,EAAE,EAAE;QACb,QAAQ,EAAE,SAAS;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { VERSION } from './version';
|
|
2
|
-
export { createLogger, LoggerImpl } from './logger';
|
|
3
|
-
export type { Logger, LoggerConfig, ResolvedLoggerConfig, LogLevel, LogEntry, LogMetadata, LogContext, Transport, TransportConfig, BatchTransportConfig, HTTPTransportConfig, FileTransportConfig, DatadogTransportConfig, SerializedError, Runtime, FieldMatcher, SanitizePattern, SanitizeConfig, SanitizePreset, Span, SpanCallback, SpanEvent, SpanOptions, SpanStatus, SpanSyncCallback, Sampler, SamplerConfig, SamplingConfig, ProbabilitySamplerConfig, RateLimitSamplerConfig, NamespaceSamplerConfig, } from './types';
|
|
2
|
+
export { createLogger, createLoggerAsync, initLogger, LoggerImpl } from './logger';
|
|
3
|
+
export type { Logger, LoggerConfig, ResolvedLoggerConfig, LogLevel, LogEntry, LogMetadata, LogContext, Transport, TransportConfig, BatchTransportConfig, HTTPTransportConfig, FileTransportConfig, RotationInterval, DatadogTransportConfig, SentryTransportConfig, SerializedError, Runtime, FieldMatcher, SanitizePattern, SanitizeConfig, SanitizePreset, DedupeConfig, Span, SpanCallback, SpanEvent, SpanOptions, SpanStatus, SpanSyncCallback, Sampler, SamplerConfig, SamplingConfig, ProbabilitySamplerConfig, RateLimitSamplerConfig, NamespaceSamplerConfig, } from './types';
|
|
4
4
|
export { RUNTIME, CAPABILITIES, IS_NODE, IS_BUN, IS_DENO, IS_EDGE, IS_BROWSER, IS_WORKER, IS_SERVER, } from './runtime';
|
|
5
5
|
export type { RuntimeCapabilities } from './runtime';
|
|
6
6
|
export { LOG_LEVELS, shouldLog, parseLogLevel } from './levels';
|
|
@@ -11,14 +11,21 @@ export { serializeError, isError, getErrorMessage } from './utils/error';
|
|
|
11
11
|
export { Sanitizer, sanitize, createSanitizer, getPreset, mergeConfigs, COMMON_PATTERNS, PRESETS, } from './utils/sanitize';
|
|
12
12
|
export { CircularBuffer } from './utils/buffer';
|
|
13
13
|
export type { CircularBufferConfig } from './utils/buffer';
|
|
14
|
+
export { Deduplicator } from './utils/dedupe';
|
|
15
|
+
export type { DedupeResult } from './utils/dedupe';
|
|
14
16
|
export { ConsoleTransport } from './transports/console';
|
|
15
17
|
export type { ConsoleTransportConfig } from './transports/console';
|
|
16
18
|
export { BatchTransport } from './transports/batch';
|
|
17
19
|
export { HTTPTransport, HTTPTransportError } from './transports/http';
|
|
18
20
|
export { FileTransport } from './transports/file';
|
|
19
21
|
export { DatadogTransport, DatadogTransportError } from './transports/datadog';
|
|
22
|
+
export { SentryTransport, SentryTransportError } from './transports/sentry';
|
|
20
23
|
export { span, spanSync, startSpan, endSpan, getActiveSpan, withActiveSpan, SpanImpl, clearActiveSpans, getActiveSpanStackDepth, withSpanContext, withSpanContextAsync, } from './tracing';
|
|
21
24
|
export { createSampler, createSamplerFromConfig, createProbabilitySampler, createRateLimitSampler, createNamespaceSampler, createCompositeSampler, } from './sampling';
|
|
25
|
+
export { createWideEvent, WideEventBuilderImpl, getActiveWideEvent, withWideEvent, withWideEventAsync, } from './wide-events';
|
|
26
|
+
export type { WideEvent, WideEventBuilder, WideEventConfig, WideEventContext, WideEventEndOptions, WideEventFields, WideEventStatus, TailSamplingConfig, } from './wide-events';
|
|
27
|
+
export { MetricsCollector, globalMetrics, createMetricsCollector } from './metrics';
|
|
28
|
+
export type { LoggerMetrics } from './metrics';
|
|
22
29
|
/**
|
|
23
30
|
* Default logger instance with auto-configuration
|
|
24
31
|
*/
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAGnC,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Version
|
|
2
2
|
export { VERSION } from './version';
|
|
3
3
|
// Core exports
|
|
4
|
-
export { createLogger, LoggerImpl } from './logger';
|
|
4
|
+
export { createLogger, createLoggerAsync, initLogger, LoggerImpl } from './logger';
|
|
5
5
|
// Runtime detection
|
|
6
6
|
export { RUNTIME, CAPABILITIES, IS_NODE, IS_BUN, IS_DENO, IS_EDGE, IS_BROWSER, IS_WORKER, IS_SERVER, } from './runtime';
|
|
7
7
|
// Log levels
|
|
@@ -16,18 +16,24 @@ parseTracestate, createTracestate, getTracestateValue, setTracestateValue, delet
|
|
|
16
16
|
export { serializeError, isError, getErrorMessage } from './utils/error';
|
|
17
17
|
export { Sanitizer, sanitize, createSanitizer, getPreset, mergeConfigs, COMMON_PATTERNS, PRESETS, } from './utils/sanitize';
|
|
18
18
|
export { CircularBuffer } from './utils/buffer';
|
|
19
|
+
export { Deduplicator } from './utils/dedupe';
|
|
19
20
|
// Transports
|
|
20
21
|
export { ConsoleTransport } from './transports/console';
|
|
21
22
|
export { BatchTransport } from './transports/batch';
|
|
22
23
|
export { HTTPTransport, HTTPTransportError } from './transports/http';
|
|
23
24
|
export { FileTransport } from './transports/file';
|
|
24
25
|
export { DatadogTransport, DatadogTransportError } from './transports/datadog';
|
|
26
|
+
export { SentryTransport, SentryTransportError } from './transports/sentry';
|
|
25
27
|
// Tracing - standalone functions and utilities
|
|
26
28
|
export { span, spanSync, startSpan, endSpan, getActiveSpan, withActiveSpan, SpanImpl,
|
|
27
29
|
// Context utilities (for advanced use cases)
|
|
28
30
|
clearActiveSpans, getActiveSpanStackDepth, withSpanContext, withSpanContextAsync, } from './tracing';
|
|
29
31
|
// Sampling - factory functions for creating samplers
|
|
30
32
|
export { createSampler, createSamplerFromConfig, createProbabilitySampler, createRateLimitSampler, createNamespaceSampler, createCompositeSampler, } from './sampling';
|
|
33
|
+
// Wide Events - canonical log lines for comprehensive request context
|
|
34
|
+
export { createWideEvent, WideEventBuilderImpl, getActiveWideEvent, withWideEvent, withWideEventAsync, } from './wide-events';
|
|
35
|
+
// Metrics - Prometheus format export
|
|
36
|
+
export { MetricsCollector, globalMetrics, createMetricsCollector } from './metrics';
|
|
31
37
|
// Default logger instance (convenience)
|
|
32
38
|
import { createLogger } from './logger';
|
|
33
39
|
/**
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,UAAU;AACV,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAEnC,eAAe;AACf,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,UAAU;AACV,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAEnC,eAAe;AACf,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AA0ClF,oBAAoB;AACpB,OAAO,EACN,OAAO,EACP,YAAY,EACZ,OAAO,EACP,MAAM,EACN,OAAO,EACP,OAAO,EACP,UAAU,EACV,SAAS,EACT,SAAS,GACT,MAAM,WAAW,CAAA;AAGlB,aAAa;AACb,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAE/D,gBAAgB;AAChB,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAElE,qBAAqB;AACrB,OAAO,EACN,UAAU,EACV,WAAW,EACX,gBAAgB,EAChB,wBAAwB,EACxB,iBAAiB,EACjB,eAAe,EACf,cAAc,EACd,gBAAgB,EAChB,iBAAiB;AACjB,uCAAuC;AACvC,eAAe,EACf,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,GACnB,MAAM,WAAW,CAAA;AAGlB,YAAY;AACZ,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AACxE,OAAO,EACN,SAAS,EACT,QAAQ,EACR,eAAe,EACf,SAAS,EACT,YAAY,EACZ,eAAe,EACf,OAAO,GACP,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAE/C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAG7C,aAAa;AACb,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAEvD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACnD,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AACjD,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAA;AAC9E,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAE3E,+CAA+C;AAC/C,OAAO,EACN,IAAI,EACJ,QAAQ,EACR,SAAS,EACT,OAAO,EACP,aAAa,EACb,cAAc,EACd,QAAQ;AACR,6CAA6C;AAC7C,gBAAgB,EAChB,uBAAuB,EACvB,eAAe,EACf,oBAAoB,GACpB,MAAM,WAAW,CAAA;AAElB,qDAAqD;AACrD,OAAO,EACN,aAAa,EACb,uBAAuB,EACvB,wBAAwB,EACxB,sBAAsB,EACtB,sBAAsB,EACtB,sBAAsB,GACtB,MAAM,YAAY,CAAA;AAEnB,sEAAsE;AACtE,OAAO,EACN,eAAe,EACf,oBAAoB,EACpB,kBAAkB,EAClB,aAAa,EACb,kBAAkB,GAClB,MAAM,eAAe,CAAA;AAYtB,qCAAqC;AACrC,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAA;AAGnF,wCAAwC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAEvC;;GAEG;AACH,MAAM,CAAC,MAAM,GAAG,GAAG,YAAY,EAAE,CAAA"}
|
package/dist/logger.d.ts
CHANGED
|
@@ -10,6 +10,8 @@ export declare class LoggerImpl implements Logger {
|
|
|
10
10
|
private children;
|
|
11
11
|
private initialized;
|
|
12
12
|
private sampler;
|
|
13
|
+
private deduplicator;
|
|
14
|
+
private tailSampler;
|
|
13
15
|
constructor(config?: LoggerConfig);
|
|
14
16
|
/**
|
|
15
17
|
* Internal log method
|
|
@@ -33,6 +35,11 @@ export declare class LoggerImpl implements Logger {
|
|
|
33
35
|
* Create a child logger with a namespace
|
|
34
36
|
*/
|
|
35
37
|
child(namespace: string, config?: Partial<LoggerConfig>): Logger;
|
|
38
|
+
/**
|
|
39
|
+
* Internal method called by FinalizationRegistry to clean up stale entries
|
|
40
|
+
* @internal
|
|
41
|
+
*/
|
|
42
|
+
cleanupChild(namespace: string): void;
|
|
36
43
|
/**
|
|
37
44
|
* Set the minimum log level
|
|
38
45
|
*/
|
|
@@ -120,9 +127,87 @@ export declare class LoggerImpl implements Logger {
|
|
|
120
127
|
* ```
|
|
121
128
|
*/
|
|
122
129
|
spanSync<T>(name: string, fn: SpanSyncCallback<T>, options?: SpanOptions): T;
|
|
130
|
+
/**
|
|
131
|
+
* Emit a completed wide event through the logger's transports.
|
|
132
|
+
*
|
|
133
|
+
* Wide events are comprehensive, single-event records of complete
|
|
134
|
+
* operations (like HTTP requests or background jobs).
|
|
135
|
+
*
|
|
136
|
+
* If tail sampling is configured, the event may be dropped based on:
|
|
137
|
+
* - Status (errors are always kept)
|
|
138
|
+
* - Duration (slow requests are always kept)
|
|
139
|
+
* - VIP users/tiers (always kept)
|
|
140
|
+
* - Random sampling for success events
|
|
141
|
+
*
|
|
142
|
+
* @param event - The completed WideEvent to emit
|
|
143
|
+
*/
|
|
144
|
+
emitWideEvent(event: import('./wide-events/types').WideEvent): void;
|
|
145
|
+
/**
|
|
146
|
+
* Flatten wide event fields to dot-notation for LogEntry metadata.
|
|
147
|
+
*/
|
|
148
|
+
private flattenFields;
|
|
123
149
|
}
|
|
124
150
|
/**
|
|
125
151
|
* Create a new logger instance
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* ```typescript
|
|
155
|
+
* // Basic usage
|
|
156
|
+
* const logger = createLogger({ level: 'info' })
|
|
157
|
+
*
|
|
158
|
+
* // With namespace
|
|
159
|
+
* const dbLogger = createLogger({ namespace: 'db' })
|
|
160
|
+
*
|
|
161
|
+
* // For async initialization, see createLoggerAsync()
|
|
162
|
+
* ```
|
|
126
163
|
*/
|
|
127
164
|
export declare function createLogger(config?: LoggerConfig): Logger;
|
|
165
|
+
/**
|
|
166
|
+
* Create and initialize a logger instance asynchronously
|
|
167
|
+
*
|
|
168
|
+
* This function creates a logger and waits for all transports to initialize.
|
|
169
|
+
* Use this when you have transports that require async setup (file handles,
|
|
170
|
+
* database connections, HTTP clients with connection pooling, etc.).
|
|
171
|
+
*
|
|
172
|
+
* @param config - Logger configuration options
|
|
173
|
+
* @returns A promise that resolves to the initialized logger
|
|
174
|
+
*
|
|
175
|
+
* @example
|
|
176
|
+
* ```typescript
|
|
177
|
+
* // Initialize logger with async transports
|
|
178
|
+
* const logger = await createLoggerAsync({
|
|
179
|
+
* level: 'info',
|
|
180
|
+
* namespace: 'app'
|
|
181
|
+
* })
|
|
182
|
+
*
|
|
183
|
+
* // Add transports that need async init
|
|
184
|
+
* logger.addTransport(new FileTransport({ path: './logs/app.log' }))
|
|
185
|
+
* logger.addTransport(new HTTPTransport({ url: 'https://logs.example.com' }))
|
|
186
|
+
*
|
|
187
|
+
* // Or create with transports added first
|
|
188
|
+
* const logger = createLogger()
|
|
189
|
+
* logger.addTransport(new FileTransport({ path: './logs/app.log' }))
|
|
190
|
+
* const initializedLogger = await initLogger(logger)
|
|
191
|
+
* ```
|
|
192
|
+
*/
|
|
193
|
+
export declare function createLoggerAsync(config?: LoggerConfig): Promise<Logger>;
|
|
194
|
+
/**
|
|
195
|
+
* Initialize an existing logger and its transports
|
|
196
|
+
*
|
|
197
|
+
* This is useful when you want to add transports first, then initialize them all.
|
|
198
|
+
*
|
|
199
|
+
* @param logger - The logger instance to initialize
|
|
200
|
+
* @returns A promise that resolves to the same logger after initialization
|
|
201
|
+
*
|
|
202
|
+
* @example
|
|
203
|
+
* ```typescript
|
|
204
|
+
* const logger = createLogger({ namespace: 'api' })
|
|
205
|
+
* logger.addTransport(new FileTransport({ path: './api.log' }))
|
|
206
|
+
* logger.addTransport(new DatadogTransport({ apiKey: process.env.DD_API_KEY }))
|
|
207
|
+
*
|
|
208
|
+
* // Initialize all transports
|
|
209
|
+
* await initLogger(logger)
|
|
210
|
+
* ```
|
|
211
|
+
*/
|
|
212
|
+
export declare function initLogger(logger: Logger): Promise<Logger>;
|
|
128
213
|
//# sourceMappingURL=logger.d.ts.map
|
package/dist/logger.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAKA,OAAO,EAEN,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,gBAAgB,EAGrB,MAAM,WAAW,CAAA;AAElB,OAAO,KAAK,EAGX,QAAQ,EACR,WAAW,EACX,MAAM,EACN,YAAY,EAEZ,SAAS,EACT,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"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"}
|
package/dist/logger.js
CHANGED
|
@@ -2,9 +2,10 @@ import { mergeConfig } from './config';
|
|
|
2
2
|
import { getContext } from './context';
|
|
3
3
|
import { LOG_LEVELS, shouldLog } from './levels';
|
|
4
4
|
import { RUNTIME } from './runtime';
|
|
5
|
-
import { createSampler } from './sampling';
|
|
5
|
+
import { TailSampler, createSampler } from './sampling';
|
|
6
6
|
import { span as spanFn, spanSync as spanSyncFn, } from './tracing';
|
|
7
7
|
import { ConsoleTransport } from './transports/console';
|
|
8
|
+
import { Deduplicator } from './utils/dedupe';
|
|
8
9
|
import { isError, serializeError } from './utils/error';
|
|
9
10
|
import { sanitize } from './utils/sanitize';
|
|
10
11
|
/**
|
|
@@ -55,6 +56,16 @@ function formatArgs(args) {
|
|
|
55
56
|
}
|
|
56
57
|
return { message: String(first), metadata };
|
|
57
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* FinalizationRegistry for cleaning up stale WeakRef entries in children Map.
|
|
61
|
+
* When a child logger is garbage collected, this removes its entry from the parent's Map.
|
|
62
|
+
*/
|
|
63
|
+
const childLoggerRegistry = new FinalizationRegistry((heldValue) => {
|
|
64
|
+
const parent = heldValue.parent.deref();
|
|
65
|
+
if (parent) {
|
|
66
|
+
parent.cleanupChild(heldValue.namespace);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
58
69
|
/**
|
|
59
70
|
* Core logger implementation
|
|
60
71
|
*/
|
|
@@ -65,12 +76,22 @@ export class LoggerImpl {
|
|
|
65
76
|
children = new Map();
|
|
66
77
|
initialized = false;
|
|
67
78
|
sampler = null;
|
|
79
|
+
deduplicator = null;
|
|
80
|
+
tailSampler = null;
|
|
68
81
|
constructor(config) {
|
|
69
82
|
this.config = mergeConfig(config);
|
|
70
83
|
// Initialize sampler if configured
|
|
71
84
|
if (this.config.sampling) {
|
|
72
85
|
this.sampler = createSampler(this.config.sampling);
|
|
73
86
|
}
|
|
87
|
+
// Initialize deduplicator if configured
|
|
88
|
+
if (this.config.dedupe?.enabled) {
|
|
89
|
+
this.deduplicator = new Deduplicator(this.config.dedupe);
|
|
90
|
+
}
|
|
91
|
+
// Initialize tail sampler for wide events if configured
|
|
92
|
+
if (this.config.tailSampling?.enabled !== false && this.config.tailSampling) {
|
|
93
|
+
this.tailSampler = new TailSampler(this.config.tailSampling);
|
|
94
|
+
}
|
|
74
95
|
// Add default console transport
|
|
75
96
|
this.transports.push(new ConsoleTransport({
|
|
76
97
|
structured: this.config.structured,
|
|
@@ -89,8 +110,9 @@ export class LoggerImpl {
|
|
|
89
110
|
// Get context from async storage
|
|
90
111
|
const asyncContext = getContext();
|
|
91
112
|
// Sanitize metadata if enabled
|
|
113
|
+
// Note: sanitize() can return null/undefined for edge cases, so we fallback to empty object
|
|
92
114
|
const sanitizedMetadata = this.config.sanitize
|
|
93
|
-
? sanitize(metadata, this.config.sanitizeFields)
|
|
115
|
+
? (sanitize(metadata, this.config.sanitizeFields) ?? {})
|
|
94
116
|
: metadata;
|
|
95
117
|
// Build log entry
|
|
96
118
|
const entry = {
|
|
@@ -112,6 +134,34 @@ export class LoggerImpl {
|
|
|
112
134
|
if (this.sampler && !this.sampler.shouldSample(entry)) {
|
|
113
135
|
return;
|
|
114
136
|
}
|
|
137
|
+
// Apply deduplication if configured
|
|
138
|
+
if (this.deduplicator) {
|
|
139
|
+
const dedupeResult = this.deduplicator.shouldSuppress(message, level, this.config.namespace);
|
|
140
|
+
if (dedupeResult.suppressed) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
// If this is a flush after suppression, emit summary first
|
|
144
|
+
if (dedupeResult.isFlush && dedupeResult.suppressedCount) {
|
|
145
|
+
const summaryEntry = {
|
|
146
|
+
timestamp: new Date().toISOString(),
|
|
147
|
+
level,
|
|
148
|
+
message: `[dedupe] Previous message repeated ${dedupeResult.suppressedCount} time${dedupeResult.suppressedCount > 1 ? 's' : ''}`,
|
|
149
|
+
metadata: { originalMessage: message },
|
|
150
|
+
runtime: RUNTIME,
|
|
151
|
+
namespace: this.config.namespace || undefined,
|
|
152
|
+
};
|
|
153
|
+
// Send summary to transports
|
|
154
|
+
for (const transport of this.transports) {
|
|
155
|
+
if (transport.config.enabled === false)
|
|
156
|
+
continue;
|
|
157
|
+
if (transport.config.level && !shouldLog(level, transport.config.level))
|
|
158
|
+
continue;
|
|
159
|
+
if (transport.config.filter && !transport.config.filter(summaryEntry))
|
|
160
|
+
continue;
|
|
161
|
+
transport.log(summaryEntry);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
115
165
|
// Send to all enabled transports
|
|
116
166
|
for (const transport of this.transports) {
|
|
117
167
|
// Check if transport is enabled
|
|
@@ -180,9 +230,21 @@ export class LoggerImpl {
|
|
|
180
230
|
// Cache if no custom config (using WeakRef to allow GC)
|
|
181
231
|
if (!config) {
|
|
182
232
|
this.children.set(fullNamespace, new WeakRef(child));
|
|
233
|
+
// Register for automatic cleanup when child is garbage collected
|
|
234
|
+
childLoggerRegistry.register(child, {
|
|
235
|
+
parent: new WeakRef(this),
|
|
236
|
+
namespace: fullNamespace,
|
|
237
|
+
});
|
|
183
238
|
}
|
|
184
239
|
return child;
|
|
185
240
|
}
|
|
241
|
+
/**
|
|
242
|
+
* Internal method called by FinalizationRegistry to clean up stale entries
|
|
243
|
+
* @internal
|
|
244
|
+
*/
|
|
245
|
+
cleanupChild(namespace) {
|
|
246
|
+
this.children.delete(namespace);
|
|
247
|
+
}
|
|
186
248
|
/**
|
|
187
249
|
* Set the minimum log level
|
|
188
250
|
*/
|
|
@@ -270,6 +332,11 @@ export class LoggerImpl {
|
|
|
270
332
|
* Destroy all transports (call on shutdown)
|
|
271
333
|
*/
|
|
272
334
|
async destroy() {
|
|
335
|
+
// Clean up deduplicator
|
|
336
|
+
if (this.deduplicator) {
|
|
337
|
+
this.deduplicator.destroy();
|
|
338
|
+
this.deduplicator = null;
|
|
339
|
+
}
|
|
273
340
|
await Promise.all(this.transports.map((t) => t.destroy?.()));
|
|
274
341
|
this.transports = [];
|
|
275
342
|
this.initialized = false;
|
|
@@ -323,11 +390,151 @@ export class LoggerImpl {
|
|
|
323
390
|
const fullName = this.config.namespace ? `${this.config.namespace}:${name}` : name;
|
|
324
391
|
return spanSyncFn(fullName, fn, options);
|
|
325
392
|
}
|
|
393
|
+
/**
|
|
394
|
+
* Emit a completed wide event through the logger's transports.
|
|
395
|
+
*
|
|
396
|
+
* Wide events are comprehensive, single-event records of complete
|
|
397
|
+
* operations (like HTTP requests or background jobs).
|
|
398
|
+
*
|
|
399
|
+
* If tail sampling is configured, the event may be dropped based on:
|
|
400
|
+
* - Status (errors are always kept)
|
|
401
|
+
* - Duration (slow requests are always kept)
|
|
402
|
+
* - VIP users/tiers (always kept)
|
|
403
|
+
* - Random sampling for success events
|
|
404
|
+
*
|
|
405
|
+
* @param event - The completed WideEvent to emit
|
|
406
|
+
*/
|
|
407
|
+
emitWideEvent(event) {
|
|
408
|
+
// Check if logging is enabled
|
|
409
|
+
if (!this.config.enabled) {
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
// Apply tail sampling if configured
|
|
413
|
+
if (this.tailSampler) {
|
|
414
|
+
const result = this.tailSampler.shouldSample(event);
|
|
415
|
+
if (!result.sampled) {
|
|
416
|
+
// Event was dropped by tail sampling
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
// Convert WideEvent to LogEntry
|
|
421
|
+
const entry = {
|
|
422
|
+
timestamp: event.ended_at,
|
|
423
|
+
level: event.level,
|
|
424
|
+
message: `[wide-event] ${event.event_type}`,
|
|
425
|
+
metadata: {
|
|
426
|
+
event_type: event.event_type,
|
|
427
|
+
status: event.status,
|
|
428
|
+
started_at: event.started_at,
|
|
429
|
+
duration_ms: event.duration_ms,
|
|
430
|
+
...this.flattenFields(event.fields),
|
|
431
|
+
},
|
|
432
|
+
context: event.context,
|
|
433
|
+
runtime: event.runtime,
|
|
434
|
+
namespace: this.config.namespace || undefined,
|
|
435
|
+
error: event.error,
|
|
436
|
+
};
|
|
437
|
+
// Sanitize metadata if enabled
|
|
438
|
+
if (this.config.sanitize && entry.metadata) {
|
|
439
|
+
entry.metadata = sanitize(entry.metadata, this.config.sanitizeFields) ?? {};
|
|
440
|
+
}
|
|
441
|
+
// Send to all enabled transports (no regular sampling/dedupe for wide events)
|
|
442
|
+
for (const transport of this.transports) {
|
|
443
|
+
if (transport.config.enabled === false)
|
|
444
|
+
continue;
|
|
445
|
+
if (transport.config.level && !shouldLog(entry.level, transport.config.level))
|
|
446
|
+
continue;
|
|
447
|
+
if (transport.config.filter && !transport.config.filter(entry))
|
|
448
|
+
continue;
|
|
449
|
+
transport.log(entry);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* Flatten wide event fields to dot-notation for LogEntry metadata.
|
|
454
|
+
*/
|
|
455
|
+
flattenFields(fields) {
|
|
456
|
+
const result = {};
|
|
457
|
+
for (const [category, categoryFields] of Object.entries(fields)) {
|
|
458
|
+
for (const [key, value] of Object.entries(categoryFields)) {
|
|
459
|
+
result[`${category}.${key}`] = value;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
return result;
|
|
463
|
+
}
|
|
326
464
|
}
|
|
327
465
|
/**
|
|
328
466
|
* Create a new logger instance
|
|
467
|
+
*
|
|
468
|
+
* @example
|
|
469
|
+
* ```typescript
|
|
470
|
+
* // Basic usage
|
|
471
|
+
* const logger = createLogger({ level: 'info' })
|
|
472
|
+
*
|
|
473
|
+
* // With namespace
|
|
474
|
+
* const dbLogger = createLogger({ namespace: 'db' })
|
|
475
|
+
*
|
|
476
|
+
* // For async initialization, see createLoggerAsync()
|
|
477
|
+
* ```
|
|
329
478
|
*/
|
|
330
479
|
export function createLogger(config) {
|
|
331
480
|
return new LoggerImpl(config);
|
|
332
481
|
}
|
|
482
|
+
/**
|
|
483
|
+
* Create and initialize a logger instance asynchronously
|
|
484
|
+
*
|
|
485
|
+
* This function creates a logger and waits for all transports to initialize.
|
|
486
|
+
* Use this when you have transports that require async setup (file handles,
|
|
487
|
+
* database connections, HTTP clients with connection pooling, etc.).
|
|
488
|
+
*
|
|
489
|
+
* @param config - Logger configuration options
|
|
490
|
+
* @returns A promise that resolves to the initialized logger
|
|
491
|
+
*
|
|
492
|
+
* @example
|
|
493
|
+
* ```typescript
|
|
494
|
+
* // Initialize logger with async transports
|
|
495
|
+
* const logger = await createLoggerAsync({
|
|
496
|
+
* level: 'info',
|
|
497
|
+
* namespace: 'app'
|
|
498
|
+
* })
|
|
499
|
+
*
|
|
500
|
+
* // Add transports that need async init
|
|
501
|
+
* logger.addTransport(new FileTransport({ path: './logs/app.log' }))
|
|
502
|
+
* logger.addTransport(new HTTPTransport({ url: 'https://logs.example.com' }))
|
|
503
|
+
*
|
|
504
|
+
* // Or create with transports added first
|
|
505
|
+
* const logger = createLogger()
|
|
506
|
+
* logger.addTransport(new FileTransport({ path: './logs/app.log' }))
|
|
507
|
+
* const initializedLogger = await initLogger(logger)
|
|
508
|
+
* ```
|
|
509
|
+
*/
|
|
510
|
+
export async function createLoggerAsync(config) {
|
|
511
|
+
const logger = new LoggerImpl(config);
|
|
512
|
+
await logger.init();
|
|
513
|
+
return logger;
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
516
|
+
* Initialize an existing logger and its transports
|
|
517
|
+
*
|
|
518
|
+
* This is useful when you want to add transports first, then initialize them all.
|
|
519
|
+
*
|
|
520
|
+
* @param logger - The logger instance to initialize
|
|
521
|
+
* @returns A promise that resolves to the same logger after initialization
|
|
522
|
+
*
|
|
523
|
+
* @example
|
|
524
|
+
* ```typescript
|
|
525
|
+
* const logger = createLogger({ namespace: 'api' })
|
|
526
|
+
* logger.addTransport(new FileTransport({ path: './api.log' }))
|
|
527
|
+
* logger.addTransport(new DatadogTransport({ apiKey: process.env.DD_API_KEY }))
|
|
528
|
+
*
|
|
529
|
+
* // Initialize all transports
|
|
530
|
+
* await initLogger(logger)
|
|
531
|
+
* ```
|
|
532
|
+
*/
|
|
533
|
+
export async function initLogger(logger) {
|
|
534
|
+
// The Logger interface doesn't expose init(), so we cast to access it
|
|
535
|
+
// This is safe because createLogger always returns a LoggerImpl
|
|
536
|
+
const impl = logger;
|
|
537
|
+
await impl.init();
|
|
538
|
+
return logger;
|
|
539
|
+
}
|
|
333
540
|
//# sourceMappingURL=logger.js.map
|