@safaricom-mxl/log 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1040 -0
- package/dist/_http-DmaJ426Z.mjs +76 -0
- package/dist/_http-DmaJ426Z.mjs.map +1 -0
- package/dist/_severity-D_IU9-90.mjs +17 -0
- package/dist/_severity-D_IU9-90.mjs.map +1 -0
- package/dist/adapters/axiom.d.mts +64 -0
- package/dist/adapters/axiom.d.mts.map +1 -0
- package/dist/adapters/axiom.mjs +100 -0
- package/dist/adapters/axiom.mjs.map +1 -0
- package/dist/adapters/better-stack.d.mts +63 -0
- package/dist/adapters/better-stack.d.mts.map +1 -0
- package/dist/adapters/better-stack.mjs +98 -0
- package/dist/adapters/better-stack.mjs.map +1 -0
- package/dist/adapters/otlp.d.mts +85 -0
- package/dist/adapters/otlp.d.mts.map +1 -0
- package/dist/adapters/otlp.mjs +196 -0
- package/dist/adapters/otlp.mjs.map +1 -0
- package/dist/adapters/posthog.d.mts +107 -0
- package/dist/adapters/posthog.d.mts.map +1 -0
- package/dist/adapters/posthog.mjs +166 -0
- package/dist/adapters/posthog.mjs.map +1 -0
- package/dist/adapters/sentry.d.mts +80 -0
- package/dist/adapters/sentry.d.mts.map +1 -0
- package/dist/adapters/sentry.mjs +221 -0
- package/dist/adapters/sentry.mjs.map +1 -0
- package/dist/browser.d.mts +63 -0
- package/dist/browser.d.mts.map +1 -0
- package/dist/browser.mjs +95 -0
- package/dist/browser.mjs.map +1 -0
- package/dist/enrichers.d.mts +74 -0
- package/dist/enrichers.d.mts.map +1 -0
- package/dist/enrichers.mjs +172 -0
- package/dist/enrichers.mjs.map +1 -0
- package/dist/error.d.mts +65 -0
- package/dist/error.d.mts.map +1 -0
- package/dist/error.mjs +112 -0
- package/dist/error.mjs.map +1 -0
- package/dist/index.d.mts +6 -0
- package/dist/index.mjs +6 -0
- package/dist/logger.d.mts +46 -0
- package/dist/logger.d.mts.map +1 -0
- package/dist/logger.mjs +287 -0
- package/dist/logger.mjs.map +1 -0
- package/dist/next/client.d.mts +55 -0
- package/dist/next/client.d.mts.map +1 -0
- package/dist/next/client.mjs +44 -0
- package/dist/next/client.mjs.map +1 -0
- package/dist/next/index.d.mts +169 -0
- package/dist/next/index.d.mts.map +1 -0
- package/dist/next/index.mjs +280 -0
- package/dist/next/index.mjs.map +1 -0
- package/dist/nitro/errorHandler.d.mts +15 -0
- package/dist/nitro/errorHandler.d.mts.map +1 -0
- package/dist/nitro/errorHandler.mjs +41 -0
- package/dist/nitro/errorHandler.mjs.map +1 -0
- package/dist/nitro/module.d.mts +11 -0
- package/dist/nitro/module.d.mts.map +1 -0
- package/dist/nitro/module.mjs +23 -0
- package/dist/nitro/module.mjs.map +1 -0
- package/dist/nitro/plugin.d.mts +7 -0
- package/dist/nitro/plugin.d.mts.map +1 -0
- package/dist/nitro/plugin.mjs +145 -0
- package/dist/nitro/plugin.mjs.map +1 -0
- package/dist/nitro/v3/errorHandler.d.mts +24 -0
- package/dist/nitro/v3/errorHandler.d.mts.map +1 -0
- package/dist/nitro/v3/errorHandler.mjs +36 -0
- package/dist/nitro/v3/errorHandler.mjs.map +1 -0
- package/dist/nitro/v3/index.d.mts +5 -0
- package/dist/nitro/v3/index.mjs +5 -0
- package/dist/nitro/v3/middleware.d.mts +25 -0
- package/dist/nitro/v3/middleware.d.mts.map +1 -0
- package/dist/nitro/v3/middleware.mjs +45 -0
- package/dist/nitro/v3/middleware.mjs.map +1 -0
- package/dist/nitro/v3/module.d.mts +10 -0
- package/dist/nitro/v3/module.d.mts.map +1 -0
- package/dist/nitro/v3/module.mjs +22 -0
- package/dist/nitro/v3/module.mjs.map +1 -0
- package/dist/nitro/v3/plugin.d.mts +14 -0
- package/dist/nitro/v3/plugin.d.mts.map +1 -0
- package/dist/nitro/v3/plugin.mjs +162 -0
- package/dist/nitro/v3/plugin.mjs.map +1 -0
- package/dist/nitro/v3/useLogger.d.mts +24 -0
- package/dist/nitro/v3/useLogger.d.mts.map +1 -0
- package/dist/nitro/v3/useLogger.mjs +27 -0
- package/dist/nitro/v3/useLogger.mjs.map +1 -0
- package/dist/nitro-CrFBjY1Y.d.mts +42 -0
- package/dist/nitro-CrFBjY1Y.d.mts.map +1 -0
- package/dist/nitro-Dsv6dSzv.mjs +39 -0
- package/dist/nitro-Dsv6dSzv.mjs.map +1 -0
- package/dist/nuxt/module.d.mts +164 -0
- package/dist/nuxt/module.d.mts.map +1 -0
- package/dist/nuxt/module.mjs +84 -0
- package/dist/nuxt/module.mjs.map +1 -0
- package/dist/pipeline.d.mts +46 -0
- package/dist/pipeline.d.mts.map +1 -0
- package/dist/pipeline.mjs +122 -0
- package/dist/pipeline.mjs.map +1 -0
- package/dist/routes-BNbrnm14.mjs +39 -0
- package/dist/routes-BNbrnm14.mjs.map +1 -0
- package/dist/runtime/client/log.d.mts +15 -0
- package/dist/runtime/client/log.d.mts.map +1 -0
- package/dist/runtime/client/log.mjs +92 -0
- package/dist/runtime/client/log.mjs.map +1 -0
- package/dist/runtime/client/plugin.d.mts +5 -0
- package/dist/runtime/client/plugin.d.mts.map +1 -0
- package/dist/runtime/client/plugin.mjs +17 -0
- package/dist/runtime/client/plugin.mjs.map +1 -0
- package/dist/runtime/server/routes/_mxllog/ingest.post.d.mts +7 -0
- package/dist/runtime/server/routes/_mxllog/ingest.post.d.mts.map +1 -0
- package/dist/runtime/server/routes/_mxllog/ingest.post.mjs +123 -0
- package/dist/runtime/server/routes/_mxllog/ingest.post.mjs.map +1 -0
- package/dist/runtime/server/useLogger.d.mts +39 -0
- package/dist/runtime/server/useLogger.d.mts.map +1 -0
- package/dist/runtime/server/useLogger.mjs +43 -0
- package/dist/runtime/server/useLogger.mjs.map +1 -0
- package/dist/runtime/utils/parseError.d.mts +7 -0
- package/dist/runtime/utils/parseError.d.mts.map +1 -0
- package/dist/runtime/utils/parseError.mjs +29 -0
- package/dist/runtime/utils/parseError.mjs.map +1 -0
- package/dist/types.d.mts +496 -0
- package/dist/types.d.mts.map +1 -0
- package/dist/types.mjs +1 -0
- package/dist/utils.d.mts +34 -0
- package/dist/utils.d.mts.map +1 -0
- package/dist/utils.mjs +78 -0
- package/dist/utils.mjs.map +1 -0
- package/dist/workers.d.mts +46 -0
- package/dist/workers.d.mts.map +1 -0
- package/dist/workers.mjs +81 -0
- package/dist/workers.mjs.map +1 -0
- package/package.json +195 -0
package/dist/types.d.mts
ADDED
|
@@ -0,0 +1,496 @@
|
|
|
1
|
+
//#region src/types.d.ts
|
|
2
|
+
declare module 'nitropack/types' {
|
|
3
|
+
interface NitroRuntimeHooks {
|
|
4
|
+
/**
|
|
5
|
+
* Tail sampling hook - called before emitting a log.
|
|
6
|
+
* Set `ctx.shouldKeep = true` to force-keep the log regardless of head sampling.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* nitroApp.hooks.hook('@safaricom-mxl/log:emit:keep', (ctx) => {
|
|
11
|
+
* if (ctx.context.user?.premium) {
|
|
12
|
+
* ctx.shouldKeep = true
|
|
13
|
+
* }
|
|
14
|
+
* })
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
'@safaricom-mxl/log:emit:keep': (ctx: TailSamplingContext) => void | Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* Enrichment hook - called after emit, before drain.
|
|
20
|
+
* Use this to enrich the event with derived context (e.g. geo, user agent).
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```ts
|
|
24
|
+
* nitroApp.hooks.hook('@safaricom-mxl/log:enrich', (ctx) => {
|
|
25
|
+
* ctx.event.deploymentId = process.env.DEPLOYMENT_ID
|
|
26
|
+
* })
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
'@safaricom-mxl/log:enrich': (ctx: EnrichContext) => void | Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Drain hook - called after emitting a log (fire-and-forget).
|
|
32
|
+
* Use this to send logs to external services like Axiom, Loki, or custom endpoints.
|
|
33
|
+
* Errors are logged but never block the request.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* nitroApp.hooks.hook('@safaricom-mxl/log:drain', async (ctx) => {
|
|
38
|
+
* await fetch('https://api.axiom.co/v1/datasets/logs/ingest', {
|
|
39
|
+
* method: 'POST',
|
|
40
|
+
* headers: { Authorization: `Bearer ${process.env.AXIOM_TOKEN}` },
|
|
41
|
+
* body: JSON.stringify([ctx.event])
|
|
42
|
+
* })
|
|
43
|
+
* })
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
'@safaricom-mxl/log:drain': (ctx: DrainContext) => void | Promise<void>;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
declare module 'nitro/types' {
|
|
50
|
+
interface NitroRuntimeHooks {
|
|
51
|
+
'@safaricom-mxl/log:emit:keep': (ctx: TailSamplingContext) => void | Promise<void>;
|
|
52
|
+
'@safaricom-mxl/log:enrich': (ctx: EnrichContext) => void | Promise<void>;
|
|
53
|
+
'@safaricom-mxl/log:drain': (ctx: DrainContext) => void | Promise<void>;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Transport configuration for sending client logs to the server
|
|
58
|
+
*/
|
|
59
|
+
interface TransportConfig {
|
|
60
|
+
/**
|
|
61
|
+
* Enable sending logs to the server API
|
|
62
|
+
* @default false
|
|
63
|
+
*/
|
|
64
|
+
enabled?: boolean;
|
|
65
|
+
/**
|
|
66
|
+
* API endpoint for log ingestion
|
|
67
|
+
* @default '/api/_mxllog/ingest'
|
|
68
|
+
*/
|
|
69
|
+
endpoint?: string;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Payload sent from client to server for log ingestion
|
|
73
|
+
*/
|
|
74
|
+
interface IngestPayload {
|
|
75
|
+
timestamp: string;
|
|
76
|
+
level: 'info' | 'error' | 'warn' | 'debug';
|
|
77
|
+
[key: string]: unknown;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Sampling rates per log level (0-100 percentage)
|
|
81
|
+
*/
|
|
82
|
+
interface SamplingRates {
|
|
83
|
+
/** Percentage of info logs to keep (0-100). Default: 100 */
|
|
84
|
+
info?: number;
|
|
85
|
+
/** Percentage of warn logs to keep (0-100). Default: 100 */
|
|
86
|
+
warn?: number;
|
|
87
|
+
/** Percentage of debug logs to keep (0-100). Default: 100 */
|
|
88
|
+
debug?: number;
|
|
89
|
+
/** Percentage of error logs to keep (0-100). Default: 100 */
|
|
90
|
+
error?: number;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Tail sampling condition for forcing log retention based on request outcome.
|
|
94
|
+
* All conditions use >= comparison (e.g., status: 400 means status >= 400).
|
|
95
|
+
*/
|
|
96
|
+
interface TailSamplingCondition {
|
|
97
|
+
/** Keep if HTTP status >= this value (e.g., 400 for all errors) */
|
|
98
|
+
status?: number;
|
|
99
|
+
/** Keep if request duration >= this value in milliseconds */
|
|
100
|
+
duration?: number;
|
|
101
|
+
/** Keep if path matches this glob pattern (e.g., '/api/critical/**') */
|
|
102
|
+
path?: string;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Context passed to tail sampling evaluation and hooks.
|
|
106
|
+
* Contains request outcome information for sampling decisions.
|
|
107
|
+
*/
|
|
108
|
+
interface TailSamplingContext {
|
|
109
|
+
/** HTTP response status code */
|
|
110
|
+
status?: number;
|
|
111
|
+
/** Request duration in milliseconds (raw number) */
|
|
112
|
+
duration?: number;
|
|
113
|
+
/** Request path */
|
|
114
|
+
path?: string;
|
|
115
|
+
/** HTTP method */
|
|
116
|
+
method?: string;
|
|
117
|
+
/** Full accumulated context from the request logger */
|
|
118
|
+
context: Record<string, unknown>;
|
|
119
|
+
/**
|
|
120
|
+
* Set to true in mxllog:emit:keep hook to force keep this log.
|
|
121
|
+
* Multiple hooks can set this - if any sets it to true, the log is kept.
|
|
122
|
+
*/
|
|
123
|
+
shouldKeep?: boolean;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Context passed to the mxllog:enrich hook.
|
|
127
|
+
* Called after emit, before drain.
|
|
128
|
+
*/
|
|
129
|
+
interface EnrichContext {
|
|
130
|
+
/** The emitted wide event (mutable). */
|
|
131
|
+
event: WideEvent;
|
|
132
|
+
/** Request metadata (if available) */
|
|
133
|
+
request?: {
|
|
134
|
+
method?: string;
|
|
135
|
+
path: string;
|
|
136
|
+
requestId?: string;
|
|
137
|
+
};
|
|
138
|
+
/** Safe HTTP request headers (sensitive headers filtered out) */
|
|
139
|
+
headers?: Record<string, string>;
|
|
140
|
+
/** Optional response metadata */
|
|
141
|
+
response?: {
|
|
142
|
+
status?: number;
|
|
143
|
+
headers?: Record<string, string>;
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Context passed to the mxllog:drain hook.
|
|
148
|
+
* Contains the complete wide event and request metadata for external transport.
|
|
149
|
+
*/
|
|
150
|
+
interface DrainContext {
|
|
151
|
+
/** The complete wide event to drain */
|
|
152
|
+
event: WideEvent;
|
|
153
|
+
/** Request metadata (if available) */
|
|
154
|
+
request?: {
|
|
155
|
+
method?: string;
|
|
156
|
+
path?: string;
|
|
157
|
+
requestId?: string;
|
|
158
|
+
};
|
|
159
|
+
/** HTTP headers from the original request (useful for correlation with external services) */
|
|
160
|
+
headers?: Record<string, string>;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Sampling configuration for filtering logs
|
|
164
|
+
*/
|
|
165
|
+
interface SamplingConfig {
|
|
166
|
+
/**
|
|
167
|
+
* Sampling rates per log level (head sampling).
|
|
168
|
+
* Values are percentages from 0 to 100.
|
|
169
|
+
* Default: 100 for all levels (log everything).
|
|
170
|
+
* Error defaults to 100 even if not specified.
|
|
171
|
+
*
|
|
172
|
+
* @example
|
|
173
|
+
* ```ts
|
|
174
|
+
* sampling: {
|
|
175
|
+
* rates: {
|
|
176
|
+
* info: 10, // Keep 10% of info logs
|
|
177
|
+
* warn: 50, // Keep 50% of warning logs
|
|
178
|
+
* debug: 5, // Keep 5% of debug logs
|
|
179
|
+
* error: 100, // Always keep errors (default)
|
|
180
|
+
* }
|
|
181
|
+
* }
|
|
182
|
+
* ```
|
|
183
|
+
*/
|
|
184
|
+
rates?: SamplingRates;
|
|
185
|
+
/**
|
|
186
|
+
* Tail sampling conditions for forcing log retention (OR logic).
|
|
187
|
+
* If ANY condition matches, the log is kept regardless of head sampling.
|
|
188
|
+
* Use the `mxllog:emit:keep` Nitro hook for custom conditions.
|
|
189
|
+
*
|
|
190
|
+
* @example
|
|
191
|
+
* ```ts
|
|
192
|
+
* sampling: {
|
|
193
|
+
* rates: { info: 10 }, // Head sampling: keep 10% of info logs
|
|
194
|
+
* keep: [
|
|
195
|
+
* { status: 400 }, // Always keep if status >= 400
|
|
196
|
+
* { duration: 1000 }, // Always keep if duration >= 1000ms
|
|
197
|
+
* { path: '/api/critical/**' }, // Always keep critical paths
|
|
198
|
+
* ]
|
|
199
|
+
* }
|
|
200
|
+
* ```
|
|
201
|
+
*/
|
|
202
|
+
keep?: TailSamplingCondition[];
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Route-based service configuration
|
|
206
|
+
*/
|
|
207
|
+
interface RouteConfig {
|
|
208
|
+
/** Service name to use for routes matching this pattern */
|
|
209
|
+
service: string;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Environment context automatically included in every log event
|
|
213
|
+
*/
|
|
214
|
+
interface EnvironmentContext {
|
|
215
|
+
/** Service name (auto-detected from package.json or configurable) */
|
|
216
|
+
service: string;
|
|
217
|
+
/** Environment: 'development', 'production', 'test', etc. */
|
|
218
|
+
environment: 'development' | 'production' | 'test' | string;
|
|
219
|
+
/** Application version (auto-detected from package.json) */
|
|
220
|
+
version?: string;
|
|
221
|
+
/** Git commit hash (auto-detected from CI/CD env vars) */
|
|
222
|
+
commitHash?: string;
|
|
223
|
+
/** Deployment region (auto-detected from cloud provider env vars) */
|
|
224
|
+
region?: string;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Logger configuration options
|
|
228
|
+
*/
|
|
229
|
+
interface LoggerConfig {
|
|
230
|
+
/**
|
|
231
|
+
* Enable or disable all logging globally.
|
|
232
|
+
* When false, all emits, tagged logs, and request logger operations become no-ops.
|
|
233
|
+
* @default true
|
|
234
|
+
*/
|
|
235
|
+
enabled?: boolean;
|
|
236
|
+
/** Environment context overrides */
|
|
237
|
+
env?: Partial<EnvironmentContext>;
|
|
238
|
+
/** Enable pretty printing (auto-detected: true in dev, false in prod) */
|
|
239
|
+
pretty?: boolean;
|
|
240
|
+
/** Sampling configuration for filtering logs */
|
|
241
|
+
sampling?: SamplingConfig;
|
|
242
|
+
/**
|
|
243
|
+
* When pretty is disabled, emit JSON strings (default) or raw objects.
|
|
244
|
+
* Set to false for environments like Cloudflare Workers that expect objects.
|
|
245
|
+
* @default true
|
|
246
|
+
*/
|
|
247
|
+
stringify?: boolean;
|
|
248
|
+
/**
|
|
249
|
+
* Drain callback called with every emitted event (fire-and-forget).
|
|
250
|
+
* Use this to send logs to external services outside of Nitro.
|
|
251
|
+
* Compatible with drain adapters (`createAxiomDrain()`) and pipeline-wrapped drains.
|
|
252
|
+
*
|
|
253
|
+
* @example
|
|
254
|
+
* ```ts
|
|
255
|
+
* import { initLogger, log } from '@safaricom-mxl/log'
|
|
256
|
+
* import { createAxiomDrain } from '@safaricom-mxl/log/axiom'
|
|
257
|
+
*
|
|
258
|
+
* initLogger({
|
|
259
|
+
* drain: createAxiomDrain({ dataset: 'logs', token: '...' }),
|
|
260
|
+
* })
|
|
261
|
+
*
|
|
262
|
+
* log.info({ action: 'user_login' }) // automatically drained
|
|
263
|
+
* ```
|
|
264
|
+
*
|
|
265
|
+
* @example
|
|
266
|
+
* ```ts
|
|
267
|
+
* // With pipeline for batching and retry
|
|
268
|
+
* import { createDrainPipeline } from '@safaricom-mxl/log/pipeline'
|
|
269
|
+
*
|
|
270
|
+
* const pipeline = createDrainPipeline({ batch: { size: 25 } })
|
|
271
|
+
* const drain = pipeline(createAxiomDrain({ dataset: 'logs', token: '...' }))
|
|
272
|
+
*
|
|
273
|
+
* initLogger({ drain })
|
|
274
|
+
*
|
|
275
|
+
* // Flush on shutdown
|
|
276
|
+
* process.on('beforeExit', () => drain.flush())
|
|
277
|
+
* ```
|
|
278
|
+
*/
|
|
279
|
+
drain?: (ctx: DrainContext) => void | Promise<void>;
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Base structure for all wide events
|
|
283
|
+
*/
|
|
284
|
+
interface BaseWideEvent {
|
|
285
|
+
timestamp: string;
|
|
286
|
+
level: 'info' | 'error' | 'warn' | 'debug';
|
|
287
|
+
service: string;
|
|
288
|
+
environment: string;
|
|
289
|
+
version?: string;
|
|
290
|
+
commitHash?: string;
|
|
291
|
+
region?: string;
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Wide event with arbitrary additional fields
|
|
295
|
+
*/
|
|
296
|
+
type WideEvent = BaseWideEvent & Record<string, unknown>;
|
|
297
|
+
/**
|
|
298
|
+
* Recursively makes all properties optional.
|
|
299
|
+
* Arrays are kept as-is (not deeply partial).
|
|
300
|
+
*/
|
|
301
|
+
type DeepPartial<T> = T extends Array<unknown> ? T : T extends object ? { [K in keyof T]?: DeepPartial<T[K]> } : T;
|
|
302
|
+
/**
|
|
303
|
+
* Fields set internally by the mxllog plugin (status, service, etc.).
|
|
304
|
+
* These are always accepted by `set()` regardless of the user-defined field type.
|
|
305
|
+
*/
|
|
306
|
+
interface InternalFields {
|
|
307
|
+
status?: number;
|
|
308
|
+
service?: string;
|
|
309
|
+
requestLogs?: RequestLogEntry[];
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Request-scoped log entry captured during a request lifecycle.
|
|
313
|
+
*/
|
|
314
|
+
interface RequestLogEntry {
|
|
315
|
+
level: 'info' | 'warn';
|
|
316
|
+
message: string;
|
|
317
|
+
timestamp: string;
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Resolved context type for logger methods.
|
|
321
|
+
* User fields are deeply partial (matching deep merge behavior) with internal
|
|
322
|
+
* field keys omitted to avoid intersection conflicts, then internal fields
|
|
323
|
+
* are added back with their canonical types.
|
|
324
|
+
*/
|
|
325
|
+
type FieldContext<T extends object = Record<string, unknown>> = DeepPartial<Omit<T, keyof InternalFields>> & InternalFields;
|
|
326
|
+
/**
|
|
327
|
+
* Request-scoped logger for building wide events
|
|
328
|
+
*
|
|
329
|
+
* @example
|
|
330
|
+
* ```ts
|
|
331
|
+
* const logger = useLogger(event)
|
|
332
|
+
* logger.set({ user: { id: '123' } })
|
|
333
|
+
* logger.set({ cart: { items: 3 } })
|
|
334
|
+
* // emit() is called automatically by the plugin
|
|
335
|
+
* ```
|
|
336
|
+
*
|
|
337
|
+
* @example
|
|
338
|
+
* ```ts
|
|
339
|
+
* // With typed fields for compile-time safety
|
|
340
|
+
* interface MyFields {
|
|
341
|
+
* user: { id: string; plan: string }
|
|
342
|
+
* action: string
|
|
343
|
+
* }
|
|
344
|
+
* const logger = useLogger<MyFields>(event)
|
|
345
|
+
* logger.set({ user: { id: '123', plan: 'pro' } }) // OK
|
|
346
|
+
* logger.set({ user: { id: '123' } }) // OK (deep partial)
|
|
347
|
+
* logger.set({ action: 'checkout' }) // OK
|
|
348
|
+
* logger.set({ status: 200 }) // OK (internal field)
|
|
349
|
+
* logger.set({ account: '...' }) // TS error
|
|
350
|
+
* ```
|
|
351
|
+
*/
|
|
352
|
+
interface RequestLogger<T extends object = Record<string, unknown>> {
|
|
353
|
+
/**
|
|
354
|
+
* Add context to the wide event (deep merge via defu)
|
|
355
|
+
*/
|
|
356
|
+
set: (context: FieldContext<T>) => void;
|
|
357
|
+
/**
|
|
358
|
+
* Log an error and capture its details
|
|
359
|
+
*/
|
|
360
|
+
error: (error: Error | string, context?: FieldContext<T>) => void;
|
|
361
|
+
/**
|
|
362
|
+
* Capture an informational message inside the request wide event.
|
|
363
|
+
*/
|
|
364
|
+
info: (message: string, context?: FieldContext<T>) => void;
|
|
365
|
+
/**
|
|
366
|
+
* Capture a warning message inside the request wide event.
|
|
367
|
+
*/
|
|
368
|
+
warn: (message: string, context?: FieldContext<T>) => void;
|
|
369
|
+
/**
|
|
370
|
+
* Emit the final wide event with all accumulated context.
|
|
371
|
+
* Returns the emitted WideEvent, or null if the log was sampled out.
|
|
372
|
+
*/
|
|
373
|
+
emit: (overrides?: FieldContext<T> & {
|
|
374
|
+
_forceKeep?: boolean;
|
|
375
|
+
}) => WideEvent | null;
|
|
376
|
+
/**
|
|
377
|
+
* Get the current accumulated context
|
|
378
|
+
*/
|
|
379
|
+
getContext: () => FieldContext<T> & Record<string, unknown>;
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Log level type
|
|
383
|
+
*/
|
|
384
|
+
type LogLevel = 'info' | 'error' | 'warn' | 'debug';
|
|
385
|
+
/**
|
|
386
|
+
* Simple logging API - as easy as console.log
|
|
387
|
+
*
|
|
388
|
+
* @example
|
|
389
|
+
* ```ts
|
|
390
|
+
* log.info('auth', 'User logged in')
|
|
391
|
+
* log.error({ action: 'payment', error: 'failed' })
|
|
392
|
+
* ```
|
|
393
|
+
*/
|
|
394
|
+
interface Log {
|
|
395
|
+
/**
|
|
396
|
+
* Log an info message or wide event
|
|
397
|
+
* @example log.info('auth', 'User logged in')
|
|
398
|
+
* @example log.info({ action: 'login', userId: '123' })
|
|
399
|
+
*/
|
|
400
|
+
info(tag: string, message: string): void;
|
|
401
|
+
info(event: Record<string, unknown>): void;
|
|
402
|
+
/**
|
|
403
|
+
* Log an error message or wide event
|
|
404
|
+
* @example log.error('payment', 'Payment failed')
|
|
405
|
+
* @example log.error({ action: 'payment', error: 'declined' })
|
|
406
|
+
*/
|
|
407
|
+
error(tag: string, message: string): void;
|
|
408
|
+
error(event: Record<string, unknown>): void;
|
|
409
|
+
/**
|
|
410
|
+
* Log a warning message or wide event
|
|
411
|
+
* @example log.warn('api', 'Rate limit approaching')
|
|
412
|
+
* @example log.warn({ action: 'api', remaining: 10 })
|
|
413
|
+
*/
|
|
414
|
+
warn(tag: string, message: string): void;
|
|
415
|
+
warn(event: Record<string, unknown>): void;
|
|
416
|
+
/**
|
|
417
|
+
* Log a debug message or wide event
|
|
418
|
+
* @example log.debug('cache', 'Cache miss')
|
|
419
|
+
* @example log.debug({ action: 'cache', key: 'user_123' })
|
|
420
|
+
*/
|
|
421
|
+
debug(tag: string, message: string): void;
|
|
422
|
+
debug(event: Record<string, unknown>): void;
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* Error options for creating structured errors
|
|
426
|
+
*/
|
|
427
|
+
interface ErrorOptions {
|
|
428
|
+
/** What actually happened */
|
|
429
|
+
message: string;
|
|
430
|
+
/** HTTP status code (default: 500) */
|
|
431
|
+
status?: number;
|
|
432
|
+
/** Why this error occurred */
|
|
433
|
+
why?: string;
|
|
434
|
+
/** How to fix this issue */
|
|
435
|
+
fix?: string;
|
|
436
|
+
/** Link to documentation or more information */
|
|
437
|
+
link?: string;
|
|
438
|
+
/** The original error that caused this */
|
|
439
|
+
cause?: Error;
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* Options for creating a request logger
|
|
443
|
+
*/
|
|
444
|
+
interface RequestLoggerOptions {
|
|
445
|
+
method?: string;
|
|
446
|
+
path?: string;
|
|
447
|
+
requestId?: string;
|
|
448
|
+
}
|
|
449
|
+
/**
|
|
450
|
+
* H3 event context with mxllog logger attached
|
|
451
|
+
*/
|
|
452
|
+
interface H3EventContext {
|
|
453
|
+
log?: RequestLogger;
|
|
454
|
+
requestId?: string;
|
|
455
|
+
status?: number;
|
|
456
|
+
/** Internal: start time for duration calculation in tail sampling */
|
|
457
|
+
_mxllogStartTime?: number;
|
|
458
|
+
/** Internal: flag to prevent double emission on errors */
|
|
459
|
+
_mxllogEmitted?: boolean;
|
|
460
|
+
[key: string]: unknown;
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* Server event type for Nitro/h3 handlers
|
|
464
|
+
*/
|
|
465
|
+
interface ServerEvent {
|
|
466
|
+
method: string;
|
|
467
|
+
path: string;
|
|
468
|
+
context: H3EventContext & {
|
|
469
|
+
/** Cloudflare Workers context (available when deployed to CF Workers) */cloudflare?: {
|
|
470
|
+
context: {
|
|
471
|
+
waitUntil: (promise: Promise<unknown>) => void;
|
|
472
|
+
};
|
|
473
|
+
}; /** Vercel Edge context (available when deployed to Vercel Edge) */
|
|
474
|
+
waitUntil?: (promise: Promise<unknown>) => void;
|
|
475
|
+
};
|
|
476
|
+
node?: {
|
|
477
|
+
res?: {
|
|
478
|
+
statusCode?: number;
|
|
479
|
+
};
|
|
480
|
+
};
|
|
481
|
+
response?: Response;
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* Parsed mxllog error with all fields at the top level
|
|
485
|
+
*/
|
|
486
|
+
interface ParsedError {
|
|
487
|
+
message: string;
|
|
488
|
+
status: number;
|
|
489
|
+
why?: string;
|
|
490
|
+
fix?: string;
|
|
491
|
+
link?: string;
|
|
492
|
+
raw: unknown;
|
|
493
|
+
}
|
|
494
|
+
//#endregion
|
|
495
|
+
export { BaseWideEvent, DeepPartial, DrainContext, EnrichContext, EnvironmentContext, ErrorOptions, FieldContext, H3EventContext, IngestPayload, InternalFields, Log, LogLevel, LoggerConfig, ParsedError, RequestLogEntry, RequestLogger, RequestLoggerOptions, RouteConfig, SamplingConfig, SamplingRates, ServerEvent, TailSamplingCondition, TailSamplingContext, TransportConfig, WideEvent };
|
|
496
|
+
//# sourceMappingURL=types.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.mts","names":[],"sources":["../src/types.ts"],"mappings":"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"}
|
package/dist/types.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
package/dist/utils.d.mts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { EnvironmentContext, LogLevel } from "./types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/utils.d.ts
|
|
4
|
+
declare function formatDuration(ms: number): string;
|
|
5
|
+
declare function isServer(): boolean;
|
|
6
|
+
declare function isClient(): boolean;
|
|
7
|
+
declare function isDev(): boolean;
|
|
8
|
+
declare function detectEnvironment(): Partial<EnvironmentContext>;
|
|
9
|
+
declare function getConsoleMethod(level: LogLevel): LogLevel;
|
|
10
|
+
declare const colors: {
|
|
11
|
+
readonly reset: "\u001B[0m";
|
|
12
|
+
readonly bold: "\u001B[1m";
|
|
13
|
+
readonly dim: "\u001B[2m";
|
|
14
|
+
readonly red: "\u001B[31m";
|
|
15
|
+
readonly green: "\u001B[32m";
|
|
16
|
+
readonly yellow: "\u001B[33m";
|
|
17
|
+
readonly blue: "\u001B[34m";
|
|
18
|
+
readonly magenta: "\u001B[35m";
|
|
19
|
+
readonly cyan: "\u001B[36m";
|
|
20
|
+
readonly white: "\u001B[37m";
|
|
21
|
+
readonly gray: "\u001B[90m";
|
|
22
|
+
};
|
|
23
|
+
declare function getLevelColor(level: string): string;
|
|
24
|
+
/** Headers that should never be passed to hooks for security */
|
|
25
|
+
declare const SENSITIVE_HEADERS: string[];
|
|
26
|
+
declare function filterSafeHeaders(headers: Record<string, string>): Record<string, string>;
|
|
27
|
+
/**
|
|
28
|
+
* Match a path against a glob pattern.
|
|
29
|
+
* Supports * (any chars except /) and ** (any chars including /).
|
|
30
|
+
*/
|
|
31
|
+
declare function matchesPattern(path: string, pattern: string): boolean;
|
|
32
|
+
//#endregion
|
|
33
|
+
export { SENSITIVE_HEADERS, colors, detectEnvironment, filterSafeHeaders, formatDuration, getConsoleMethod, getLevelColor, isClient, isDev, isServer, matchesPattern };
|
|
34
|
+
//# sourceMappingURL=utils.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.mts","names":[],"sources":["../src/utils.ts"],"mappings":";;;iBAEgB,cAAA,CAAe,EAAA;AAAA,iBAOf,QAAA,CAAA;AAAA,iBAIA,QAAA,CAAA;AAAA,iBAIA,KAAA,CAAA;AAAA,iBAUA,iBAAA,CAAA,GAAqB,OAAA,CAAQ,kBAAA;AAAA,iBAmB7B,gBAAA,CAAiB,KAAA,EAAO,QAAA,GAAW,QAAA;AAAA,cAItC,MAAA;EAAA;;;;;;;;;;;;iBAcG,aAAA,CAAc,KAAA;;cAgBjB,iBAAA;AAAA,iBASG,iBAAA,CAAkB,OAAA,EAAS,MAAA,mBAAyB,MAAA;;;;;iBAgBpD,cAAA,CAAe,IAAA,UAAc,OAAA"}
|
package/dist/utils.mjs
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
//#region src/utils.ts
|
|
2
|
+
function formatDuration(ms) {
|
|
3
|
+
if (ms < 1e3) return `${Math.round(ms)}ms`;
|
|
4
|
+
return `${(ms / 1e3).toFixed(2)}s`;
|
|
5
|
+
}
|
|
6
|
+
function isServer() {
|
|
7
|
+
return typeof window === "undefined";
|
|
8
|
+
}
|
|
9
|
+
function isClient() {
|
|
10
|
+
return typeof window !== "undefined";
|
|
11
|
+
}
|
|
12
|
+
function isDev() {
|
|
13
|
+
if (typeof process !== "undefined") return process.env.NODE_ENV !== "production";
|
|
14
|
+
if (typeof window !== "undefined") return true;
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
function detectEnvironment() {
|
|
18
|
+
const env = typeof process !== "undefined" ? process.env : {};
|
|
19
|
+
const defaultEnvironment = isDev() ? "development" : "production";
|
|
20
|
+
return {
|
|
21
|
+
environment: env.NODE_ENV || defaultEnvironment,
|
|
22
|
+
service: env.SERVICE_NAME || "app",
|
|
23
|
+
version: env.APP_VERSION,
|
|
24
|
+
commitHash: env.COMMIT_SHA || env.GITHUB_SHA || env.VERCEL_GIT_COMMIT_SHA || env.CF_PAGES_COMMIT_SHA,
|
|
25
|
+
region: env.VERCEL_REGION || env.AWS_REGION || env.FLY_REGION || env.CF_REGION
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function getConsoleMethod(level) {
|
|
29
|
+
return level;
|
|
30
|
+
}
|
|
31
|
+
const colors = {
|
|
32
|
+
reset: "\x1B[0m",
|
|
33
|
+
bold: "\x1B[1m",
|
|
34
|
+
dim: "\x1B[2m",
|
|
35
|
+
red: "\x1B[31m",
|
|
36
|
+
green: "\x1B[32m",
|
|
37
|
+
yellow: "\x1B[33m",
|
|
38
|
+
blue: "\x1B[34m",
|
|
39
|
+
magenta: "\x1B[35m",
|
|
40
|
+
cyan: "\x1B[36m",
|
|
41
|
+
white: "\x1B[37m",
|
|
42
|
+
gray: "\x1B[90m"
|
|
43
|
+
};
|
|
44
|
+
function getLevelColor(level) {
|
|
45
|
+
switch (level) {
|
|
46
|
+
case "error": return colors.red;
|
|
47
|
+
case "warn": return colors.yellow;
|
|
48
|
+
case "info": return colors.cyan;
|
|
49
|
+
case "debug": return colors.gray;
|
|
50
|
+
default: return colors.white;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/** Headers that should never be passed to hooks for security */
|
|
54
|
+
const SENSITIVE_HEADERS = [
|
|
55
|
+
"authorization",
|
|
56
|
+
"cookie",
|
|
57
|
+
"set-cookie",
|
|
58
|
+
"x-api-key",
|
|
59
|
+
"x-auth-token",
|
|
60
|
+
"proxy-authorization"
|
|
61
|
+
];
|
|
62
|
+
function filterSafeHeaders(headers) {
|
|
63
|
+
const safeHeaders = {};
|
|
64
|
+
for (const [key, value] of Object.entries(headers)) if (!SENSITIVE_HEADERS.includes(key.toLowerCase())) safeHeaders[key] = value;
|
|
65
|
+
return safeHeaders;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Match a path against a glob pattern.
|
|
69
|
+
* Supports * (any chars except /) and ** (any chars including /).
|
|
70
|
+
*/
|
|
71
|
+
function matchesPattern(path, pattern) {
|
|
72
|
+
const regexPattern = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "{{GLOBSTAR}}").replace(/\*/g, "[^/]*").replace(/{{GLOBSTAR}}/g, ".*").replace(/\?/g, "[^/]");
|
|
73
|
+
return new RegExp(`^${regexPattern}$`).test(path);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
//#endregion
|
|
77
|
+
export { SENSITIVE_HEADERS, colors, detectEnvironment, filterSafeHeaders, formatDuration, getConsoleMethod, getLevelColor, isClient, isDev, isServer, matchesPattern };
|
|
78
|
+
//# sourceMappingURL=utils.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.mjs","names":[],"sources":["../src/utils.ts"],"sourcesContent":["import type { EnvironmentContext, LogLevel } from './types'\n\nexport function formatDuration(ms: number): string {\n if (ms < 1000) {\n return `${Math.round(ms)}ms`\n }\n return `${(ms / 1000).toFixed(2)}s`\n}\n\nexport function isServer(): boolean {\n return typeof window === 'undefined'\n}\n\nexport function isClient(): boolean {\n return typeof window !== 'undefined'\n}\n\nexport function isDev(): boolean {\n if (typeof process !== 'undefined') {\n return process.env.NODE_ENV !== 'production'\n }\n if (typeof window !== 'undefined') {\n return true\n }\n return false\n}\n\nexport function detectEnvironment(): Partial<EnvironmentContext> {\n const env = typeof process !== 'undefined' ? process.env : {}\n const defaultEnvironment = isDev() ? 'development' : 'production'\n\n return {\n environment: env.NODE_ENV || defaultEnvironment,\n service: env.SERVICE_NAME || 'app',\n version: env.APP_VERSION,\n commitHash: env.COMMIT_SHA\n || env.GITHUB_SHA\n || env.VERCEL_GIT_COMMIT_SHA\n || env.CF_PAGES_COMMIT_SHA,\n region: env.VERCEL_REGION\n || env.AWS_REGION\n || env.FLY_REGION\n || env.CF_REGION,\n }\n}\n\nexport function getConsoleMethod(level: LogLevel): LogLevel {\n return level\n}\n\nexport const colors = {\n reset: '\\x1B[0m',\n bold: '\\x1B[1m',\n dim: '\\x1B[2m',\n red: '\\x1B[31m',\n green: '\\x1B[32m',\n yellow: '\\x1B[33m',\n blue: '\\x1B[34m',\n magenta: '\\x1B[35m',\n cyan: '\\x1B[36m',\n white: '\\x1B[37m',\n gray: '\\x1B[90m',\n} as const\n\nexport function getLevelColor(level: string): string {\n switch (level) {\n case 'error':\n return colors.red\n case 'warn':\n return colors.yellow\n case 'info':\n return colors.cyan\n case 'debug':\n return colors.gray\n default:\n return colors.white\n }\n}\n\n/** Headers that should never be passed to hooks for security */\nexport const SENSITIVE_HEADERS = [\n 'authorization',\n 'cookie',\n 'set-cookie',\n 'x-api-key',\n 'x-auth-token',\n 'proxy-authorization',\n]\n\nexport function filterSafeHeaders(headers: Record<string, string>): Record<string, string> {\n const safeHeaders: Record<string, string> = {}\n\n for (const [key, value] of Object.entries(headers)) {\n if (!SENSITIVE_HEADERS.includes(key.toLowerCase())) {\n safeHeaders[key] = value\n }\n }\n\n return safeHeaders\n}\n\n/**\n * Match a path against a glob pattern.\n * Supports * (any chars except /) and ** (any chars including /).\n */\nexport function matchesPattern(path: string, pattern: string): boolean {\n const regexPattern = pattern\n .replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&') // Escape special regex chars except * and ?\n .replace(/\\*\\*/g, '{{GLOBSTAR}}') // Temp placeholder for **\n .replace(/\\*/g, '[^/]*') // * matches anything except /\n .replace(/{{GLOBSTAR}}/g, '.*') // ** matches anything including /\n .replace(/\\?/g, '[^/]') // ? matches single char except /\n\n const regex = new RegExp(`^${regexPattern}$`)\n return regex.test(path)\n}\n"],"mappings":";AAEA,SAAgB,eAAe,IAAoB;AACjD,KAAI,KAAK,IACP,QAAO,GAAG,KAAK,MAAM,GAAG,CAAC;AAE3B,QAAO,IAAI,KAAK,KAAM,QAAQ,EAAE,CAAC;;AAGnC,SAAgB,WAAoB;AAClC,QAAO,OAAO,WAAW;;AAG3B,SAAgB,WAAoB;AAClC,QAAO,OAAO,WAAW;;AAG3B,SAAgB,QAAiB;AAC/B,KAAI,OAAO,YAAY,YACrB,QAAO,QAAQ,IAAI,aAAa;AAElC,KAAI,OAAO,WAAW,YACpB,QAAO;AAET,QAAO;;AAGT,SAAgB,oBAAiD;CAC/D,MAAM,MAAM,OAAO,YAAY,cAAc,QAAQ,MAAM,EAAE;CAC7D,MAAM,qBAAqB,OAAO,GAAG,gBAAgB;AAErD,QAAO;EACL,aAAa,IAAI,YAAY;EAC7B,SAAS,IAAI,gBAAgB;EAC7B,SAAS,IAAI;EACb,YAAY,IAAI,cACX,IAAI,cACJ,IAAI,yBACJ,IAAI;EACT,QAAQ,IAAI,iBACP,IAAI,cACJ,IAAI,cACJ,IAAI;EACV;;AAGH,SAAgB,iBAAiB,OAA2B;AAC1D,QAAO;;AAGT,MAAa,SAAS;CACpB,OAAO;CACP,MAAM;CACN,KAAK;CACL,KAAK;CACL,OAAO;CACP,QAAQ;CACR,MAAM;CACN,SAAS;CACT,MAAM;CACN,OAAO;CACP,MAAM;CACP;AAED,SAAgB,cAAc,OAAuB;AACnD,SAAQ,OAAR;EACE,KAAK,QACH,QAAO,OAAO;EAChB,KAAK,OACH,QAAO,OAAO;EAChB,KAAK,OACH,QAAO,OAAO;EAChB,KAAK,QACH,QAAO,OAAO;EAChB,QACE,QAAO,OAAO;;;;AAKpB,MAAa,oBAAoB;CAC/B;CACA;CACA;CACA;CACA;CACA;CACD;AAED,SAAgB,kBAAkB,SAAyD;CACzF,MAAM,cAAsC,EAAE;AAE9C,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,CAChD,KAAI,CAAC,kBAAkB,SAAS,IAAI,aAAa,CAAC,CAChD,aAAY,OAAO;AAIvB,QAAO;;;;;;AAOT,SAAgB,eAAe,MAAc,SAA0B;CACrE,MAAM,eAAe,QAClB,QAAQ,qBAAqB,OAAO,CACpC,QAAQ,SAAS,eAAe,CAChC,QAAQ,OAAO,QAAQ,CACvB,QAAQ,iBAAiB,KAAK,CAC9B,QAAQ,OAAO,OAAO;AAGzB,QADc,IAAI,OAAO,IAAI,aAAa,GAAG,CAChC,KAAK,KAAK"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { LoggerConfig, RequestLogger } from "./types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/workers/index.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Options for createWorkersLogger
|
|
6
|
+
*/
|
|
7
|
+
interface WorkersLoggerOptions {
|
|
8
|
+
/** Override the request ID (default: cf-ray header) */
|
|
9
|
+
requestId?: string;
|
|
10
|
+
/** Headers to include in logs (default: none) */
|
|
11
|
+
headers?: string[];
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Initialize mxllog for Cloudflare Workers.
|
|
15
|
+
* Call once at module scope.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* initWorkersLogger({
|
|
20
|
+
* env: { service: 'my-api' },
|
|
21
|
+
* })
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
declare function initWorkersLogger(options?: LoggerConfig): void;
|
|
25
|
+
/**
|
|
26
|
+
* Create a request-scoped logger for Cloudflare Workers.
|
|
27
|
+
* Auto-extracts cf-ray, request.cf context, method, and path.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```ts
|
|
31
|
+
* export default {
|
|
32
|
+
* async fetch(request: Request) {
|
|
33
|
+
* const log = createWorkersLogger(request)
|
|
34
|
+
*
|
|
35
|
+
* log.set({ user: { id: '123' } })
|
|
36
|
+
* log.emit({ status: 200 })
|
|
37
|
+
*
|
|
38
|
+
* return new Response('ok')
|
|
39
|
+
* }
|
|
40
|
+
* }
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
declare function createWorkersLogger<T extends object = Record<string, unknown>>(request: Request, options?: WorkersLoggerOptions): RequestLogger<T>;
|
|
44
|
+
//#endregion
|
|
45
|
+
export { WorkersLoggerOptions, createWorkersLogger, initWorkersLogger };
|
|
46
|
+
//# sourceMappingURL=workers.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workers.d.mts","names":[],"sources":["../src/workers/index.ts"],"mappings":";;;;;AAMA;UAAiB,oBAAA;;EAEf,SAAA;EAEO;EAAP,OAAA;AAAA;;;;AAsEF;;;;;;;;iBArCgB,iBAAA,CAAkB,OAAA,GAAS,YAAA;;;;;;;;;;;;;;;;;;;iBAqC3B,mBAAA,oBAAuC,MAAA,kBAAA,CAAyB,OAAA,EAAS,OAAA,EAAS,OAAA,GAAS,oBAAA,GAA4B,aAAA,CAAc,CAAA"}
|