evlog 2.6.0 → 2.7.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 +1 -0
- package/dist/_drain-FZVTbHn9.mjs +18 -0
- package/dist/_drain-FZVTbHn9.mjs.map +1 -0
- package/dist/{_http-DHpGetLZ.mjs → _http-DpL_o_Wk.mjs} +2 -17
- package/dist/_http-DpL_o_Wk.mjs.map +1 -0
- package/dist/{_severity-Q1BuITU_.mjs → _severity-fhhv2Nq0.mjs} +1 -1
- package/dist/{_severity-Q1BuITU_.mjs.map → _severity-fhhv2Nq0.mjs.map} +1 -1
- package/dist/adapters/axiom.d.mts +1 -1
- package/dist/adapters/axiom.mjs +2 -1
- package/dist/adapters/axiom.mjs.map +1 -1
- package/dist/adapters/better-stack.d.mts +1 -1
- package/dist/adapters/better-stack.mjs +2 -1
- package/dist/adapters/better-stack.mjs.map +1 -1
- package/dist/adapters/fs.d.mts +37 -0
- package/dist/adapters/fs.d.mts.map +1 -0
- package/dist/adapters/fs.mjs +106 -0
- package/dist/adapters/fs.mjs.map +1 -0
- package/dist/adapters/otlp.d.mts +1 -1
- package/dist/adapters/otlp.mjs +3 -2
- package/dist/adapters/otlp.mjs.map +1 -1
- package/dist/adapters/posthog.d.mts +1 -1
- package/dist/adapters/posthog.mjs +2 -1
- package/dist/adapters/posthog.mjs.map +1 -1
- package/dist/adapters/sentry.d.mts +1 -1
- package/dist/adapters/sentry.mjs +3 -2
- package/dist/adapters/sentry.mjs.map +1 -1
- package/dist/browser.d.mts +1 -1
- package/dist/elysia/index.d.mts +2 -2
- package/dist/elysia/index.mjs +1 -1
- package/dist/enrichers.d.mts +1 -1
- package/dist/{error-iV3zJCY3.d.mts → error-BuPbEDGO.d.mts} +2 -2
- package/dist/{error-iV3zJCY3.d.mts.map → error-BuPbEDGO.d.mts.map} +1 -1
- package/dist/error.d.mts +1 -1
- package/dist/{errors-CKSfdvLa.d.mts → errors-nScQVwHW.d.mts} +2 -2
- package/dist/{errors-CKSfdvLa.d.mts.map → errors-nScQVwHW.d.mts.map} +1 -1
- package/dist/express/index.d.mts +2 -2
- package/dist/express/index.mjs +3 -3
- package/dist/express/index.mjs.map +1 -1
- package/dist/fastify/index.d.mts +2 -2
- package/dist/fastify/index.mjs +2 -2
- package/dist/{headers-Ba1eKT3i.mjs → headers-BSgpnR0c.mjs} +7 -6
- package/dist/headers-BSgpnR0c.mjs.map +1 -0
- package/dist/hono/index.d.mts +2 -2
- package/dist/hono/index.mjs +1 -1
- package/dist/index.d.mts +5 -5
- package/dist/{logger-CvDYZUze.d.mts → logger-BH1gOdNP.d.mts} +21 -5
- package/dist/logger-BH1gOdNP.d.mts.map +1 -0
- package/dist/logger.d.mts +2 -2
- package/dist/logger.mjs +25 -13
- package/dist/logger.mjs.map +1 -1
- package/dist/{middleware-hZqyXoSk.d.mts → middleware-CDLTVOBs.d.mts} +2 -2
- package/dist/{middleware-hZqyXoSk.d.mts.map → middleware-CDLTVOBs.d.mts.map} +1 -1
- package/dist/nestjs/index.d.mts +2 -2
- package/dist/nestjs/index.d.mts.map +1 -1
- package/dist/nestjs/index.mjs +3 -3
- package/dist/nestjs/index.mjs.map +1 -1
- package/dist/next/client.d.mts +1 -1
- package/dist/next/index.d.mts +10 -4
- package/dist/next/index.d.mts.map +1 -1
- package/dist/next/index.mjs +7 -4
- package/dist/next/index.mjs.map +1 -1
- package/dist/nitro/module.d.mts +2 -2
- package/dist/nitro/plugin.mjs +4 -2
- package/dist/nitro/plugin.mjs.map +1 -1
- package/dist/nitro/v3/module.d.mts +1 -1
- package/dist/nitro/v3/plugin.mjs +4 -2
- package/dist/nitro/v3/plugin.mjs.map +1 -1
- package/dist/nitro/v3/useLogger.d.mts +1 -1
- package/dist/{nitro-CGGTUned.d.mts → nitro-CaIIZfdG.d.mts} +10 -2
- package/dist/nitro-CaIIZfdG.d.mts.map +1 -0
- package/dist/nitro-D1pPm37T.mjs.map +1 -1
- package/dist/nuxt/module.d.mts +9 -1
- package/dist/nuxt/module.d.mts.map +1 -1
- package/dist/nuxt/module.mjs +1 -1
- package/dist/nuxt/module.mjs.map +1 -1
- package/dist/{parseError-BztqcPwZ.d.mts → parseError-DYrhDD1r.d.mts} +2 -2
- package/dist/parseError-DYrhDD1r.d.mts.map +1 -0
- package/dist/runtime/client/log.d.mts +1 -1
- package/dist/runtime/server/useLogger.d.mts +1 -1
- package/dist/runtime/utils/parseError.d.mts +2 -2
- package/dist/{storage-CJBW5Vos.mjs → storage-DHU1gGqV.mjs} +1 -1
- package/dist/{storage-CJBW5Vos.mjs.map → storage-DHU1gGqV.mjs.map} +1 -1
- package/dist/sveltekit/index.d.mts +2 -2
- package/dist/sveltekit/index.mjs +2 -2
- package/dist/toolkit.d.mts +3 -3
- package/dist/toolkit.mjs +2 -2
- package/dist/{types-B8-kC2ME.d.mts → types-US-1hJZl.d.mts} +11 -1
- package/dist/types-US-1hJZl.d.mts.map +1 -0
- package/dist/types.d.mts +1 -1
- package/dist/{useLogger-_Ec6mXoR.d.mts → useLogger-DBHI03WK.d.mts} +2 -2
- package/dist/{useLogger-_Ec6mXoR.d.mts.map → useLogger-DBHI03WK.d.mts.map} +1 -1
- package/dist/utils.d.mts +1 -1
- package/dist/workers.d.mts +1 -1
- package/package.json +19 -8
- package/dist/_http-DHpGetLZ.mjs.map +0 -1
- package/dist/headers-Ba1eKT3i.mjs.map +0 -1
- package/dist/logger-CvDYZUze.d.mts.map +0 -1
- package/dist/nitro-CGGTUned.d.mts.map +0 -1
- package/dist/parseError-BztqcPwZ.d.mts.map +0 -1
- package/dist/types-B8-kC2ME.d.mts.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error-
|
|
1
|
+
{"version":3,"file":"error-BuPbEDGO.d.mts","names":[],"sources":["../src/error.ts"],"mappings":";;;;;AAkBA;;;;;;;;;;;;;cAAa,UAAA,SAAmB,KAAA;EAQT;EAAA,SALZ,MAAA;EAAA,SACA,GAAA;EAAA,SACA,GAAA;EAAA,SACA,IAAA;cAEG,OAAA,EAAS,YAAA;EAiCP;EAAA,IAfV,UAAA,CAAA;EAesC;EAAA,IAVtC,UAAA,CAAA;EAkDJ;EAAA,IA7CI,aAAA,CAAA;EA6CY;EAAA,IAxCZ,IAAA,CAAA;IAAU,GAAA;IAAc,GAAA;IAAc,IAAA;EAAA;EAOjC,QAAA,CAAA;EAiCT,MAAA,CAAA,GAAU,MAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;iBAoCI,WAAA,CAAY,OAAA,EAAS,YAAA,YAAwB,UAAA"}
|
package/dist/error.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as createError, t as EvlogError } from "./error-
|
|
1
|
+
import { n as createError, t as EvlogError } from "./error-BuPbEDGO.mjs";
|
|
2
2
|
export { EvlogError, createError, createError as createEvlogError };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { v as RouteConfig } from "./types-
|
|
1
|
+
import { v as RouteConfig } from "./types-US-1hJZl.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/shared/routes.d.ts
|
|
4
4
|
declare function shouldLog(path: string, include?: string[], exclude?: string[]): boolean;
|
|
@@ -36,4 +36,4 @@ declare function getServiceForPath(path: string, routes?: Record<string, RouteCo
|
|
|
36
36
|
declare function extractErrorStatus(error: unknown): number;
|
|
37
37
|
//#endregion
|
|
38
38
|
export { getServiceForPath as n, shouldLog as r, extractErrorStatus as t };
|
|
39
|
-
//# sourceMappingURL=errors-
|
|
39
|
+
//# sourceMappingURL=errors-nScQVwHW.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors-
|
|
1
|
+
{"version":3,"file":"errors-nScQVwHW.d.mts","names":[],"sources":["../src/shared/routes.ts","../src/shared/errors.ts"],"mappings":";;;iBAGgB,SAAA,CAAU,IAAA,UAAc,OAAA,aAAoB,OAAA;;AAA5D;;;;;;;;;AAsCA;;;;;;;;;;;iBAAgB,iBAAA,CAAkB,IAAA,UAAc,MAAA,GAAS,MAAA,SAAe,WAAA;;;;;;AAtCxE;;;;iBCIgB,kBAAA,CAAmB,KAAA"}
|
package/dist/express/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { g as RequestLogger } from "../types-
|
|
2
|
-
import { t as BaseEvlogOptions } from "../middleware-
|
|
1
|
+
import { g as RequestLogger } from "../types-US-1hJZl.mjs";
|
|
2
|
+
import { t as BaseEvlogOptions } from "../middleware-CDLTVOBs.mjs";
|
|
3
3
|
import { RequestHandler } from "express";
|
|
4
4
|
|
|
5
5
|
//#region src/express/index.d.ts
|
package/dist/express/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { n as extractSafeNodeHeaders, r as createMiddlewareLogger } from "../headers-
|
|
2
|
-
import { t as createLoggerStorage } from "../storage-
|
|
1
|
+
import { n as extractSafeNodeHeaders, r as createMiddlewareLogger } from "../headers-BSgpnR0c.mjs";
|
|
2
|
+
import { t as createLoggerStorage } from "../storage-DHU1gGqV.mjs";
|
|
3
3
|
//#region src/express/index.ts
|
|
4
4
|
const { storage, useLogger } = createLoggerStorage("middleware context. Make sure app.use(evlog()) is registered before your routes.");
|
|
5
5
|
/**
|
|
@@ -24,7 +24,7 @@ function evlog(options = {}) {
|
|
|
24
24
|
return (req, res, next) => {
|
|
25
25
|
const { logger, finish, skipped } = createMiddlewareLogger({
|
|
26
26
|
method: req.method,
|
|
27
|
-
path: req.
|
|
27
|
+
path: new URL(req.originalUrl || req.url || "/", "http://localhost").pathname,
|
|
28
28
|
requestId: req.get("x-request-id") || crypto.randomUUID(),
|
|
29
29
|
headers: extractSafeNodeHeaders(req.headers),
|
|
30
30
|
...options
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/express/index.ts"],"sourcesContent":["import type { Request, Response, NextFunction, RequestHandler } from 'express'\nimport type { RequestLogger } from '../types'\nimport { createMiddlewareLogger, type BaseEvlogOptions } from '../shared/middleware'\nimport { extractSafeNodeHeaders } from '../shared/headers'\nimport { createLoggerStorage } from '../shared/storage'\n\nconst { storage, useLogger } = createLoggerStorage(\n 'middleware context. Make sure app.use(evlog()) is registered before your routes.',\n)\n\nexport type EvlogExpressOptions = BaseEvlogOptions\n\nexport { useLogger }\n\ndeclare module 'express-serve-static-core' {\n interface Request {\n log: RequestLogger\n }\n}\n\n/**\n * Create an evlog middleware for Express.\n *\n * @example\n * ```ts\n * import express from 'express'\n * import { evlog } from 'evlog/express'\n * import { createAxiomDrain } from 'evlog/axiom'\n *\n * const app = express()\n * app.use(evlog({\n * drain: createAxiomDrain(),\n * enrich: (ctx) => {\n * ctx.event.region = process.env.FLY_REGION\n * },\n * }))\n * ```\n */\nexport function evlog(options: EvlogExpressOptions = {}): RequestHandler {\n return (req: Request, res: Response, next: NextFunction) => {\n const { logger, finish, skipped } = createMiddlewareLogger({\n method: req.method,\n path: req.
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/express/index.ts"],"sourcesContent":["import type { Request, Response, NextFunction, RequestHandler } from 'express'\nimport type { RequestLogger } from '../types'\nimport { createMiddlewareLogger, type BaseEvlogOptions } from '../shared/middleware'\nimport { extractSafeNodeHeaders } from '../shared/headers'\nimport { createLoggerStorage } from '../shared/storage'\n\nconst { storage, useLogger } = createLoggerStorage(\n 'middleware context. Make sure app.use(evlog()) is registered before your routes.',\n)\n\nexport type EvlogExpressOptions = BaseEvlogOptions\n\nexport { useLogger }\n\ndeclare module 'express-serve-static-core' {\n interface Request {\n log: RequestLogger\n }\n}\n\n/**\n * Create an evlog middleware for Express.\n *\n * @example\n * ```ts\n * import express from 'express'\n * import { evlog } from 'evlog/express'\n * import { createAxiomDrain } from 'evlog/axiom'\n *\n * const app = express()\n * app.use(evlog({\n * drain: createAxiomDrain(),\n * enrich: (ctx) => {\n * ctx.event.region = process.env.FLY_REGION\n * },\n * }))\n * ```\n */\nexport function evlog(options: EvlogExpressOptions = {}): RequestHandler {\n return (req: Request, res: Response, next: NextFunction) => {\n const { logger, finish, skipped } = createMiddlewareLogger({\n method: req.method,\n path: new URL(req.originalUrl || req.url || '/', 'http://localhost').pathname,\n requestId: req.get('x-request-id') || crypto.randomUUID(),\n headers: extractSafeNodeHeaders(req.headers),\n ...options,\n })\n\n if (skipped) {\n next()\n return\n }\n\n req.log = logger\n\n res.on('finish', () => {\n finish({ status: res.statusCode }).catch(() => {})\n })\n\n storage.run(logger, () => next())\n }\n}\n"],"mappings":";;;AAMA,MAAM,EAAE,SAAS,cAAc,oBAC7B,mFACD;;;;;;;;;;;;;;;;;;;AA8BD,SAAgB,MAAM,UAA+B,EAAE,EAAkB;AACvE,SAAQ,KAAc,KAAe,SAAuB;EAC1D,MAAM,EAAE,QAAQ,QAAQ,YAAY,uBAAuB;GACzD,QAAQ,IAAI;GACZ,MAAM,IAAI,IAAI,IAAI,eAAe,IAAI,OAAO,KAAK,mBAAmB,CAAC;GACrE,WAAW,IAAI,IAAI,eAAe,IAAI,OAAO,YAAY;GACzD,SAAS,uBAAuB,IAAI,QAAQ;GAC5C,GAAG;GACJ,CAAC;AAEF,MAAI,SAAS;AACX,SAAM;AACN;;AAGF,MAAI,MAAM;AAEV,MAAI,GAAG,gBAAgB;AACrB,UAAO,EAAE,QAAQ,IAAI,YAAY,CAAC,CAAC,YAAY,GAAG;IAClD;AAEF,UAAQ,IAAI,cAAc,MAAM,CAAC"}
|
package/dist/fastify/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { g as RequestLogger } from "../types-
|
|
2
|
-
import { t as BaseEvlogOptions } from "../middleware-
|
|
1
|
+
import { g as RequestLogger } from "../types-US-1hJZl.mjs";
|
|
2
|
+
import { t as BaseEvlogOptions } from "../middleware-CDLTVOBs.mjs";
|
|
3
3
|
import { FastifyPluginCallback } from "fastify";
|
|
4
4
|
|
|
5
5
|
//#region src/fastify/index.d.ts
|
package/dist/fastify/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { n as extractSafeNodeHeaders, r as createMiddlewareLogger } from "../headers-
|
|
2
|
-
import { t as createLoggerStorage } from "../storage-
|
|
1
|
+
import { n as extractSafeNodeHeaders, r as createMiddlewareLogger } from "../headers-BSgpnR0c.mjs";
|
|
2
|
+
import { t as createLoggerStorage } from "../storage-DHU1gGqV.mjs";
|
|
3
3
|
//#region src/fastify/index.ts
|
|
4
4
|
const { storage, useLogger } = createLoggerStorage("plugin context. Make sure app.register(evlog) is called before your routes.");
|
|
5
5
|
const evlogPlugin = (fastify, options, done) => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { filterSafeHeaders } from "./utils.mjs";
|
|
2
|
-
import { createRequestLogger, isEnabled, shouldKeep } from "./logger.mjs";
|
|
2
|
+
import { createRequestLogger, getGlobalDrain, isEnabled, shouldKeep } from "./logger.mjs";
|
|
3
3
|
import { t as extractErrorStatus } from "./errors-BJRXUfMg.mjs";
|
|
4
4
|
import { n as shouldLog, t as getServiceForPath } from "./routes-CE3_c-iZ.mjs";
|
|
5
5
|
//#region src/shared/middleware.ts
|
|
@@ -33,14 +33,15 @@ async function runEnrichAndDrain(emittedEvent, options, requestInfo, responseSta
|
|
|
33
33
|
console.error("[evlog] enrich failed:", err);
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
|
-
|
|
36
|
+
const drain = options.drain ?? getGlobalDrain();
|
|
37
|
+
if (drain) {
|
|
37
38
|
const drainCtx = {
|
|
38
39
|
event: emittedEvent,
|
|
39
40
|
request: requestInfo,
|
|
40
41
|
headers: options.headers
|
|
41
42
|
};
|
|
42
43
|
try {
|
|
43
|
-
await
|
|
44
|
+
await drain(drainCtx);
|
|
44
45
|
} catch (err) {
|
|
45
46
|
console.error("[evlog] drain failed:", err);
|
|
46
47
|
}
|
|
@@ -71,7 +72,7 @@ function createMiddlewareLogger(options) {
|
|
|
71
72
|
method,
|
|
72
73
|
path,
|
|
73
74
|
requestId: resolvedRequestId
|
|
74
|
-
});
|
|
75
|
+
}, { _deferDrain: true });
|
|
75
76
|
const routeService = getServiceForPath(path, routes);
|
|
76
77
|
if (routeService) logger.set({ service: routeService });
|
|
77
78
|
const startTime = Date.now();
|
|
@@ -100,7 +101,7 @@ function createMiddlewareLogger(options) {
|
|
|
100
101
|
if (keep) await keep(tailCtx);
|
|
101
102
|
const forceKeep = tailCtx.shouldKeep || shouldKeep(tailCtx);
|
|
102
103
|
const emittedEvent = logger.emit({ _forceKeep: forceKeep });
|
|
103
|
-
if (emittedEvent && (options.enrich || options.drain)) await runEnrichAndDrain(emittedEvent, options, requestInfo, resolvedStatus);
|
|
104
|
+
if (emittedEvent && (options.enrich || options.drain || getGlobalDrain())) await runEnrichAndDrain(emittedEvent, options, requestInfo, resolvedStatus);
|
|
104
105
|
return emittedEvent;
|
|
105
106
|
};
|
|
106
107
|
return {
|
|
@@ -138,4 +139,4 @@ function extractSafeNodeHeaders(headers) {
|
|
|
138
139
|
//#endregion
|
|
139
140
|
export { extractSafeNodeHeaders as n, createMiddlewareLogger as r, extractSafeHeaders as t };
|
|
140
141
|
|
|
141
|
-
//# sourceMappingURL=headers-
|
|
142
|
+
//# sourceMappingURL=headers-BSgpnR0c.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"headers-BSgpnR0c.mjs","names":[],"sources":["../src/shared/middleware.ts","../src/shared/headers.ts"],"sourcesContent":["import type { DrainContext, EnrichContext, RequestLogger, RouteConfig, TailSamplingContext, WideEvent } from '../types'\nimport { createRequestLogger, getGlobalDrain, isEnabled, shouldKeep } from '../logger'\nimport { extractErrorStatus } from './errors'\nimport { shouldLog, getServiceForPath } from './routes'\n\n/**\n * Base options shared by all framework integrations.\n *\n * Every framework-specific options interface (e.g. `EvlogExpressOptions`)\n * extends this type. If a framework needs extra fields it can add them\n * on top; otherwise the base is used as-is.\n *\n * @beta Part of `evlog/toolkit` — the public API for building custom integrations.\n */\nexport interface BaseEvlogOptions {\n /** Route patterns to include in logging (glob). If not set, all routes are logged */\n include?: string[]\n /** Route patterns to exclude from logging. Exclusions take precedence over inclusions */\n exclude?: string[]\n /** Route-specific service configuration */\n routes?: Record<string, RouteConfig>\n /**\n * Drain callback called with every emitted event.\n * Use with drain adapters (Axiom, OTLP, Sentry, etc.) or custom endpoints.\n */\n drain?: (ctx: DrainContext) => void | Promise<void>\n /**\n * Enrich callback called after emit, before drain.\n * Use to add derived context (geo, deployment info, user agent, etc.).\n */\n enrich?: (ctx: EnrichContext) => void | Promise<void>\n /**\n * Custom tail sampling callback.\n * Set `ctx.shouldKeep = true` to force-keep the log regardless of head sampling.\n */\n keep?: (ctx: TailSamplingContext) => void | Promise<void>\n}\n\n/**\n * Internal options consumed by `createMiddlewareLogger`.\n * Extends `BaseEvlogOptions` with the request-specific fields\n * that framework adapters must provide.\n */\nexport interface MiddlewareLoggerOptions extends BaseEvlogOptions {\n method: string\n path: string\n requestId?: string\n /** Pre-filtered safe request headers (used for enrich/drain context) */\n headers?: Record<string, string>\n}\n\nexport interface MiddlewareLoggerResult {\n logger: RequestLogger\n finish: (opts?: { status?: number; error?: Error }) => Promise<WideEvent | null>\n skipped: boolean\n}\n\nconst noopResult: MiddlewareLoggerResult = {\n logger: {\n set() {},\n error() {},\n info() {},\n warn() {},\n emit() {\n return null \n },\n getContext() {\n return {} \n },\n },\n finish: () => Promise.resolve(null),\n skipped: true,\n}\n\nasync function runEnrichAndDrain(\n emittedEvent: WideEvent,\n options: MiddlewareLoggerOptions,\n requestInfo: { method: string; path: string; requestId?: string },\n responseStatus?: number,\n): Promise<void> {\n if (options.enrich) {\n const enrichCtx: EnrichContext = {\n event: emittedEvent,\n request: requestInfo,\n headers: options.headers,\n response: { status: responseStatus },\n }\n try {\n await options.enrich(enrichCtx)\n } catch (err) {\n console.error('[evlog] enrich failed:', err)\n }\n }\n\n const drain = options.drain ?? getGlobalDrain()\n if (drain) {\n const drainCtx: DrainContext = {\n event: emittedEvent,\n request: requestInfo,\n headers: options.headers,\n }\n try {\n await drain(drainCtx)\n } catch (err) {\n console.error('[evlog] drain failed:', err)\n }\n }\n}\n\n/**\n * Create a middleware-aware request logger with full lifecycle management.\n *\n * Handles the complete pipeline shared across all framework integrations:\n * route filtering, logger creation, service overrides, duration tracking,\n * tail sampling evaluation, event emission, enrichment, and draining.\n *\n * Framework adapters only need to:\n * 1. Extract method/path/requestId/headers from the framework request\n * 2. Call `createMiddlewareLogger()` with those + user options\n * 3. Check `skipped` — if true, skip to next middleware\n * 4. Store `logger` in framework-specific context (e.g., `c.set('log', logger)`)\n * 5. Call `finish({ status })` or `finish({ error })` at response end\n *\n * @beta Part of `evlog/toolkit` — the public API for building custom integrations.\n */\nexport function createMiddlewareLogger(options: MiddlewareLoggerOptions): MiddlewareLoggerResult {\n if (!isEnabled()) return noopResult\n\n const { method, path, requestId, include, exclude, routes, keep } = options\n\n if (!shouldLog(path, include, exclude)) {\n return noopResult\n }\n\n const resolvedRequestId = requestId || crypto.randomUUID()\n\n const logger = createRequestLogger({\n method,\n path,\n requestId: resolvedRequestId,\n }, { _deferDrain: true })\n\n const routeService = getServiceForPath(path, routes)\n if (routeService) {\n logger.set({ service: routeService })\n }\n\n const startTime = Date.now()\n const requestInfo = { method, path, requestId: resolvedRequestId }\n\n const finish = async (opts?: { status?: number; error?: Error }): Promise<WideEvent | null> => {\n const { status, error } = opts ?? {}\n\n if (error) {\n logger.error(error)\n const errorStatus = extractErrorStatus(error)\n logger.set({ status: errorStatus })\n } else if (status !== undefined) {\n logger.set({ status })\n }\n\n const durationMs = Date.now() - startTime\n\n const resolvedStatus = error\n ? extractErrorStatus(error)\n : status ?? (logger.getContext().status as number | undefined)\n\n const tailCtx: TailSamplingContext = {\n status: resolvedStatus,\n duration: durationMs,\n path,\n method,\n context: logger.getContext(),\n shouldKeep: false,\n }\n\n if (keep) {\n await keep(tailCtx)\n }\n\n const forceKeep = tailCtx.shouldKeep || shouldKeep(tailCtx)\n const emittedEvent = logger.emit({ _forceKeep: forceKeep })\n\n if (emittedEvent && (options.enrich || options.drain || getGlobalDrain())) {\n await runEnrichAndDrain(emittedEvent, options, requestInfo, resolvedStatus)\n }\n\n return emittedEvent\n }\n\n return { logger, finish, skipped: false }\n}\n","import { filterSafeHeaders } from '../utils'\n\n/**\n * Extract headers from a Web API `Headers` object and filter out sensitive ones.\n * Works with any runtime that supports the standard `Headers` API (Hono, Elysia,\n * Nitro v3, Cloudflare Workers, Bun, Deno, etc.).\n */\nexport function extractSafeHeaders(headers: Headers): Record<string, string> {\n const raw: Record<string, string> = {}\n headers.forEach((value, key) => {\n raw[key] = value\n })\n return filterSafeHeaders(raw)\n}\n\n/**\n * Extract headers from Node.js `IncomingHttpHeaders` and filter out sensitive ones.\n * Works with Express, Fastify, and any Node.js HTTP server using `req.headers`.\n */\nexport function extractSafeNodeHeaders(headers: Record<string, string | string[] | undefined>): Record<string, string> {\n const raw: Record<string, string> = {}\n for (const [key, value] of Object.entries(headers)) {\n if (value === undefined) continue\n raw[key] = Array.isArray(value) ? value.join(', ') : value\n }\n return filterSafeHeaders(raw)\n}\n"],"mappings":";;;;;AAyDA,MAAM,aAAqC;CACzC,QAAQ;EACN,MAAM;EACN,QAAQ;EACR,OAAO;EACP,OAAO;EACP,OAAO;AACL,UAAO;;EAET,aAAa;AACX,UAAO,EAAE;;EAEZ;CACD,cAAc,QAAQ,QAAQ,KAAK;CACnC,SAAS;CACV;AAED,eAAe,kBACb,cACA,SACA,aACA,gBACe;AACf,KAAI,QAAQ,QAAQ;EAClB,MAAM,YAA2B;GAC/B,OAAO;GACP,SAAS;GACT,SAAS,QAAQ;GACjB,UAAU,EAAE,QAAQ,gBAAgB;GACrC;AACD,MAAI;AACF,SAAM,QAAQ,OAAO,UAAU;WACxB,KAAK;AACZ,WAAQ,MAAM,0BAA0B,IAAI;;;CAIhD,MAAM,QAAQ,QAAQ,SAAS,gBAAgB;AAC/C,KAAI,OAAO;EACT,MAAM,WAAyB;GAC7B,OAAO;GACP,SAAS;GACT,SAAS,QAAQ;GAClB;AACD,MAAI;AACF,SAAM,MAAM,SAAS;WACd,KAAK;AACZ,WAAQ,MAAM,yBAAyB,IAAI;;;;;;;;;;;;;;;;;;;;AAqBjD,SAAgB,uBAAuB,SAA0D;AAC/F,KAAI,CAAC,WAAW,CAAE,QAAO;CAEzB,MAAM,EAAE,QAAQ,MAAM,WAAW,SAAS,SAAS,QAAQ,SAAS;AAEpE,KAAI,CAAC,UAAU,MAAM,SAAS,QAAQ,CACpC,QAAO;CAGT,MAAM,oBAAoB,aAAa,OAAO,YAAY;CAE1D,MAAM,SAAS,oBAAoB;EACjC;EACA;EACA,WAAW;EACZ,EAAE,EAAE,aAAa,MAAM,CAAC;CAEzB,MAAM,eAAe,kBAAkB,MAAM,OAAO;AACpD,KAAI,aACF,QAAO,IAAI,EAAE,SAAS,cAAc,CAAC;CAGvC,MAAM,YAAY,KAAK,KAAK;CAC5B,MAAM,cAAc;EAAE;EAAQ;EAAM,WAAW;EAAmB;CAElE,MAAM,SAAS,OAAO,SAAyE;EAC7F,MAAM,EAAE,QAAQ,UAAU,QAAQ,EAAE;AAEpC,MAAI,OAAO;AACT,UAAO,MAAM,MAAM;GACnB,MAAM,cAAc,mBAAmB,MAAM;AAC7C,UAAO,IAAI,EAAE,QAAQ,aAAa,CAAC;aAC1B,WAAW,KAAA,EACpB,QAAO,IAAI,EAAE,QAAQ,CAAC;EAGxB,MAAM,aAAa,KAAK,KAAK,GAAG;EAEhC,MAAM,iBAAiB,QACnB,mBAAmB,MAAM,GACzB,UAAW,OAAO,YAAY,CAAC;EAEnC,MAAM,UAA+B;GACnC,QAAQ;GACR,UAAU;GACV;GACA;GACA,SAAS,OAAO,YAAY;GAC5B,YAAY;GACb;AAED,MAAI,KACF,OAAM,KAAK,QAAQ;EAGrB,MAAM,YAAY,QAAQ,cAAc,WAAW,QAAQ;EAC3D,MAAM,eAAe,OAAO,KAAK,EAAE,YAAY,WAAW,CAAC;AAE3D,MAAI,iBAAiB,QAAQ,UAAU,QAAQ,SAAS,gBAAgB,EACtE,OAAM,kBAAkB,cAAc,SAAS,aAAa,eAAe;AAG7E,SAAO;;AAGT,QAAO;EAAE;EAAQ;EAAQ,SAAS;EAAO;;;;;;;;;ACvL3C,SAAgB,mBAAmB,SAA0C;CAC3E,MAAM,MAA8B,EAAE;AACtC,SAAQ,SAAS,OAAO,QAAQ;AAC9B,MAAI,OAAO;GACX;AACF,QAAO,kBAAkB,IAAI;;;;;;AAO/B,SAAgB,uBAAuB,SAAgF;CACrH,MAAM,MAA8B,EAAE;AACtC,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,EAAE;AAClD,MAAI,UAAU,KAAA,EAAW;AACzB,MAAI,OAAO,MAAM,QAAQ,MAAM,GAAG,MAAM,KAAK,KAAK,GAAG;;AAEvD,QAAO,kBAAkB,IAAI"}
|
package/dist/hono/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { g as RequestLogger } from "../types-
|
|
2
|
-
import { t as BaseEvlogOptions } from "../middleware-
|
|
1
|
+
import { g as RequestLogger } from "../types-US-1hJZl.mjs";
|
|
2
|
+
import { t as BaseEvlogOptions } from "../middleware-CDLTVOBs.mjs";
|
|
3
3
|
import { MiddlewareHandler } from "hono";
|
|
4
4
|
|
|
5
5
|
//#region src/hono/index.d.ts
|
package/dist/hono/index.mjs
CHANGED
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { C as TailSamplingContext, S as TailSamplingCondition, T as WideEvent, _ as RequestLoggerOptions, a as EnvironmentContext, b as SamplingRates, c as H3EventContext, d as Log, f as LogLevel, g as RequestLogger, i as EnrichContext, l as IngestPayload, m as ParsedError, n as DeepPartial, o as ErrorOptions, p as LoggerConfig, r as DrainContext, s as FieldContext, t as BaseWideEvent, u as InternalFields, w as TransportConfig, x as ServerEvent, y as SamplingConfig } from "./types-
|
|
2
|
-
import { n as createError, t as EvlogError } from "./error-
|
|
3
|
-
import {
|
|
4
|
-
import { t as useLogger } from "./useLogger-
|
|
5
|
-
import { t as parseError } from "./parseError-
|
|
1
|
+
import { C as TailSamplingContext, S as TailSamplingCondition, T as WideEvent, _ as RequestLoggerOptions, a as EnvironmentContext, b as SamplingRates, c as H3EventContext, d as Log, f as LogLevel, g as RequestLogger, i as EnrichContext, l as IngestPayload, m as ParsedError, n as DeepPartial, o as ErrorOptions, p as LoggerConfig, r as DrainContext, s as FieldContext, t as BaseWideEvent, u as InternalFields, w as TransportConfig, x as ServerEvent, y as SamplingConfig } from "./types-US-1hJZl.mjs";
|
|
2
|
+
import { n as createError, t as EvlogError } from "./error-BuPbEDGO.mjs";
|
|
3
|
+
import { c as shouldKeep, i as getEnvironment, n as createLogger, o as initLogger, r as createRequestLogger, s as isEnabled, t as _log } from "./logger-BH1gOdNP.mjs";
|
|
4
|
+
import { t as useLogger } from "./useLogger-DBHI03WK.mjs";
|
|
5
|
+
import { t as parseError } from "./parseError-DYrhDD1r.mjs";
|
|
6
6
|
export { type BaseWideEvent, type DeepPartial, type DrainContext, type EnrichContext, type EnvironmentContext, type ErrorOptions, EvlogError, type FieldContext, type H3EventContext, type IngestPayload, type InternalFields, type Log, type LogLevel, type LoggerConfig, type ParsedError, type RequestLogger, type RequestLoggerOptions, type SamplingConfig, type SamplingRates, type ServerEvent, type TailSamplingCondition, type TailSamplingContext, type TransportConfig, type WideEvent, createError, createError as createEvlogError, createLogger, createRequestLogger, getEnvironment, initLogger, isEnabled, _log as log, parseError, shouldKeep, useLogger };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as TailSamplingContext, _ as RequestLoggerOptions, a as EnvironmentContext, d as Log, g as RequestLogger, p as LoggerConfig } from "./types-
|
|
1
|
+
import { C as TailSamplingContext, _ as RequestLoggerOptions, a as EnvironmentContext, d as Log, g as RequestLogger, p as LoggerConfig, r as DrainContext } from "./types-US-1hJZl.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/logger.d.ts
|
|
4
4
|
/**
|
|
@@ -10,6 +10,12 @@ declare function initLogger(config?: LoggerConfig): void;
|
|
|
10
10
|
* Check if logging is globally enabled.
|
|
11
11
|
*/
|
|
12
12
|
declare function isEnabled(): boolean;
|
|
13
|
+
/**
|
|
14
|
+
* @internal Get the globally configured drain callback.
|
|
15
|
+
* Used by framework middleware to fall back to the global drain
|
|
16
|
+
* when no middleware-level drain is provided.
|
|
17
|
+
*/
|
|
18
|
+
declare function getGlobalDrain(): ((ctx: DrainContext) => void | Promise<void>) | undefined;
|
|
13
19
|
/**
|
|
14
20
|
* Evaluate tail sampling conditions to determine if a log should be force-kept.
|
|
15
21
|
* Returns true if ANY condition matches (OR logic).
|
|
@@ -25,6 +31,16 @@ declare function shouldKeep(ctx: TailSamplingContext): boolean;
|
|
|
25
31
|
* ```
|
|
26
32
|
*/
|
|
27
33
|
declare const _log: Log;
|
|
34
|
+
/**
|
|
35
|
+
* @internal Options for createLogger that are not part of the public API.
|
|
36
|
+
*/
|
|
37
|
+
interface CreateLoggerInternalOptions {
|
|
38
|
+
/**
|
|
39
|
+
* When true, the global drain is skipped on emit.
|
|
40
|
+
* Used by framework middleware that runs its own enrich+drain pipeline.
|
|
41
|
+
*/
|
|
42
|
+
_deferDrain?: boolean;
|
|
43
|
+
}
|
|
28
44
|
/**
|
|
29
45
|
* Create a scoped logger for building wide events.
|
|
30
46
|
* Use this for any context: workflows, jobs, scripts, queues, etc.
|
|
@@ -36,7 +52,7 @@ declare const _log: Log;
|
|
|
36
52
|
* log.emit()
|
|
37
53
|
* ```
|
|
38
54
|
*/
|
|
39
|
-
declare function createLogger<T extends object = Record<string, unknown>>(initialContext?: Record<string, unknown
|
|
55
|
+
declare function createLogger<T extends object = Record<string, unknown>>(initialContext?: Record<string, unknown>, internalOptions?: CreateLoggerInternalOptions): RequestLogger<T>;
|
|
40
56
|
/**
|
|
41
57
|
* Create a request-scoped logger for building wide events.
|
|
42
58
|
* Convenience wrapper around `createLogger` that pre-populates HTTP request fields.
|
|
@@ -49,11 +65,11 @@ declare function createLogger<T extends object = Record<string, unknown>>(initia
|
|
|
49
65
|
* log.emit()
|
|
50
66
|
* ```
|
|
51
67
|
*/
|
|
52
|
-
declare function createRequestLogger<T extends object = Record<string, unknown>>(options?: RequestLoggerOptions): RequestLogger<T>;
|
|
68
|
+
declare function createRequestLogger<T extends object = Record<string, unknown>>(options?: RequestLoggerOptions, internalOptions?: CreateLoggerInternalOptions): RequestLogger<T>;
|
|
53
69
|
/**
|
|
54
70
|
* Get the current environment context.
|
|
55
71
|
*/
|
|
56
72
|
declare function getEnvironment(): EnvironmentContext;
|
|
57
73
|
//#endregion
|
|
58
|
-
export {
|
|
59
|
-
//# sourceMappingURL=logger-
|
|
74
|
+
export { getGlobalDrain as a, shouldKeep as c, getEnvironment as i, createLogger as n, initLogger as o, createRequestLogger as r, isEnabled as s, _log as t };
|
|
75
|
+
//# sourceMappingURL=logger-BH1gOdNP.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger-BH1gOdNP.d.mts","names":[],"sources":["../src/logger.ts"],"mappings":";;;;;AAqCA;;iBAAgB,UAAA,CAAW,MAAA,GAAQ,YAAA;;;AA0BnC;iBAAgB,SAAA,CAAA;;;;AAShB;;iBAAgB,cAAA,CAAA,KAAoB,GAAA,EAAK,YAAA,YAAwB,OAAA;;;;;iBA8BjD,UAAA,CAAW,GAAA,EAAK,mBAAA;;AAAhC;;;;;AAgBC;;;cAuMK,IAAA,EAAM,GAAA;AAOU;;;AAAA,UAkBZ,2BAAA;EAKG;AAcb;;;EAdE,WAAA;AAAA;;;;;;;;;;;;iBAcc,YAAA,oBAAgC,MAAA,kBAAA,CAAyB,cAAA,GAAgB,MAAA,mBAA8B,eAAA,GAAkB,2BAAA,GAA8B,aAAA,CAAc,CAAA;;;;AAuHrL;;;;;;;;;iBAAgB,mBAAA,oBAAuC,MAAA,kBAAA,CAAyB,OAAA,GAAS,oBAAA,EAA2B,eAAA,GAAkB,2BAAA,GAA8B,aAAA,CAAc,CAAA;;;;iBAWlK,cAAA,CAAA,GAAkB,kBAAA"}
|
package/dist/logger.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
export { createLogger, createRequestLogger, getEnvironment, initLogger, isEnabled, _log as log, shouldKeep };
|
|
1
|
+
import { a as getGlobalDrain, c as shouldKeep, i as getEnvironment, n as createLogger, o as initLogger, r as createRequestLogger, s as isEnabled, t as _log } from "./logger-BH1gOdNP.mjs";
|
|
2
|
+
export { createLogger, createRequestLogger, getEnvironment, getGlobalDrain, initLogger, isEnabled, _log as log, shouldKeep };
|
package/dist/logger.mjs
CHANGED
|
@@ -22,6 +22,7 @@ let globalSampling = {};
|
|
|
22
22
|
let globalStringify = true;
|
|
23
23
|
let globalDrain;
|
|
24
24
|
let globalEnabled = true;
|
|
25
|
+
let globalSilent = false;
|
|
25
26
|
/**
|
|
26
27
|
* Initialize the logger with configuration.
|
|
27
28
|
* Call this once at application startup.
|
|
@@ -40,6 +41,8 @@ function initLogger(config = {}) {
|
|
|
40
41
|
globalSampling = config.sampling ?? {};
|
|
41
42
|
globalStringify = config.stringify ?? true;
|
|
42
43
|
globalDrain = config.drain;
|
|
44
|
+
globalSilent = config.silent ?? false;
|
|
45
|
+
if (globalSilent && !globalDrain && !config._suppressDrainWarning) console.warn("[evlog] silent mode is enabled but no drain is configured. Events will be built and sampled but not output anywhere. Set a drain via initLogger({ drain }) or a framework hook (evlog:drain).");
|
|
43
46
|
}
|
|
44
47
|
/**
|
|
45
48
|
* Check if logging is globally enabled.
|
|
@@ -48,6 +51,14 @@ function isEnabled() {
|
|
|
48
51
|
return globalEnabled;
|
|
49
52
|
}
|
|
50
53
|
/**
|
|
54
|
+
* @internal Get the globally configured drain callback.
|
|
55
|
+
* Used by framework middleware to fall back to the global drain
|
|
56
|
+
* when no middleware-level drain is provided.
|
|
57
|
+
*/
|
|
58
|
+
function getGlobalDrain() {
|
|
59
|
+
return globalDrain;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
51
62
|
* Determine if a log at the given level should be emitted based on sampling config.
|
|
52
63
|
* Error level defaults to 100% (always logged) unless explicitly configured otherwise.
|
|
53
64
|
*/
|
|
@@ -73,7 +84,7 @@ function shouldKeep(ctx) {
|
|
|
73
84
|
return false;
|
|
74
85
|
});
|
|
75
86
|
}
|
|
76
|
-
function emitWideEvent(level, event, skipSamplingCheck = false) {
|
|
87
|
+
function emitWideEvent(level, event, skipSamplingCheck = false, deferDrain = false) {
|
|
77
88
|
if (!globalEnabled) return null;
|
|
78
89
|
if (!skipSamplingCheck && !shouldSample(level)) return null;
|
|
79
90
|
const formatted = {
|
|
@@ -82,27 +93,27 @@ function emitWideEvent(level, event, skipSamplingCheck = false) {
|
|
|
82
93
|
...globalEnv,
|
|
83
94
|
...event
|
|
84
95
|
};
|
|
85
|
-
if (globalPretty) prettyPrintWideEvent(formatted);
|
|
96
|
+
if (!globalSilent) if (globalPretty) prettyPrintWideEvent(formatted);
|
|
86
97
|
else if (globalStringify) console[getConsoleMethod(level)](JSON.stringify(formatted));
|
|
87
98
|
else console[getConsoleMethod(level)](formatted);
|
|
88
|
-
if (globalDrain) Promise.resolve(globalDrain({ event: formatted })).catch((err) => {
|
|
99
|
+
if (globalDrain && !deferDrain) Promise.resolve(globalDrain({ event: formatted })).catch((err) => {
|
|
89
100
|
console.error("[evlog] drain failed:", err);
|
|
90
101
|
});
|
|
91
102
|
return formatted;
|
|
92
103
|
}
|
|
93
104
|
function emitTaggedLog(level, tag, message) {
|
|
94
105
|
if (!globalEnabled) return;
|
|
95
|
-
if (globalPretty) {
|
|
106
|
+
if (globalPretty && !globalSilent) {
|
|
96
107
|
if (!shouldSample(level)) return;
|
|
97
108
|
if (isClient()) {
|
|
98
109
|
const levelColor = getCssLevelColor(level);
|
|
99
110
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().slice(11, 23);
|
|
100
111
|
console.log(`%c${timestamp}%c %c[${escapeFormatString(tag)}]%c ${escapeFormatString(message)}`, cssColors.dim, cssColors.reset, levelColor, cssColors.reset);
|
|
101
|
-
|
|
112
|
+
} else {
|
|
113
|
+
const color = getLevelColor(level);
|
|
114
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString().slice(11, 23);
|
|
115
|
+
console.log(`${colors.dim}${timestamp}${colors.reset} ${color}[${tag}]${colors.reset} ${message}`);
|
|
102
116
|
}
|
|
103
|
-
const color = getLevelColor(level);
|
|
104
|
-
const timestamp = (/* @__PURE__ */ new Date()).toISOString().slice(11, 23);
|
|
105
|
-
console.log(`${colors.dim}${timestamp}${colors.reset} ${color}[${tag}]${colors.reset} ${message}`);
|
|
106
117
|
return;
|
|
107
118
|
}
|
|
108
119
|
emitWideEvent(level, {
|
|
@@ -231,8 +242,9 @@ const noopLogger = {
|
|
|
231
242
|
* log.emit()
|
|
232
243
|
* ```
|
|
233
244
|
*/
|
|
234
|
-
function createLogger(initialContext = {}) {
|
|
245
|
+
function createLogger(initialContext = {}, internalOptions) {
|
|
235
246
|
if (!globalEnabled) return noopLogger;
|
|
247
|
+
const deferDrain = internalOptions?._deferDrain ?? false;
|
|
236
248
|
const startTime = Date.now();
|
|
237
249
|
let context = { ...initialContext };
|
|
238
250
|
let hasError = false;
|
|
@@ -306,7 +318,7 @@ function createLogger(initialContext = {}) {
|
|
|
306
318
|
...context,
|
|
307
319
|
...restOverrides,
|
|
308
320
|
duration
|
|
309
|
-
}, true);
|
|
321
|
+
}, true, deferDrain);
|
|
310
322
|
},
|
|
311
323
|
getContext() {
|
|
312
324
|
return { ...context };
|
|
@@ -325,12 +337,12 @@ function createLogger(initialContext = {}) {
|
|
|
325
337
|
* log.emit()
|
|
326
338
|
* ```
|
|
327
339
|
*/
|
|
328
|
-
function createRequestLogger(options = {}) {
|
|
340
|
+
function createRequestLogger(options = {}, internalOptions) {
|
|
329
341
|
const initial = {};
|
|
330
342
|
if (options.method !== void 0) initial.method = options.method;
|
|
331
343
|
if (options.path !== void 0) initial.path = options.path;
|
|
332
344
|
if (options.requestId !== void 0) initial.requestId = options.requestId;
|
|
333
|
-
return createLogger(initial);
|
|
345
|
+
return createLogger(initial, internalOptions);
|
|
334
346
|
}
|
|
335
347
|
/**
|
|
336
348
|
* Get the current environment context.
|
|
@@ -339,6 +351,6 @@ function getEnvironment() {
|
|
|
339
351
|
return { ...globalEnv };
|
|
340
352
|
}
|
|
341
353
|
//#endregion
|
|
342
|
-
export { createLogger, createRequestLogger, getEnvironment, initLogger, isEnabled, _log as log, shouldKeep };
|
|
354
|
+
export { createLogger, createRequestLogger, getEnvironment, getGlobalDrain, initLogger, isEnabled, _log as log, shouldKeep };
|
|
343
355
|
|
|
344
356
|
//# sourceMappingURL=logger.mjs.map
|
package/dist/logger.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.mjs","names":[],"sources":["../src/logger.ts"],"sourcesContent":["import type { DrainContext, EnvironmentContext, FieldContext, Log, LogLevel, LoggerConfig, RequestLogger, RequestLoggerOptions, SamplingConfig, TailSamplingContext, WideEvent } from './types'\nimport { colors, cssColors, detectEnvironment, escapeFormatString, formatDuration, getConsoleMethod, getCssLevelColor, getLevelColor, isClient, isDev, matchesPattern } from './utils'\n\nfunction isPlainObject(val: unknown): val is Record<string, unknown> {\n return val !== null && typeof val === 'object' && !Array.isArray(val)\n}\n\nfunction deepDefaults(base: Record<string, unknown>, defaults: Record<string, unknown>): Record<string, unknown> {\n const result = { ...base }\n for (const key in defaults) {\n const baseVal = result[key]\n const defaultVal = defaults[key]\n if (baseVal === undefined || baseVal === null) {\n result[key] = defaultVal\n } else if (isPlainObject(baseVal) && isPlainObject(defaultVal)) {\n result[key] = deepDefaults(baseVal, defaultVal)\n }\n }\n return result\n}\n\nlet globalEnv: EnvironmentContext = {\n service: 'app',\n environment: 'development',\n}\n\nlet globalPretty = isDev()\nlet globalSampling: SamplingConfig = {}\nlet globalStringify = true\nlet globalDrain: ((ctx: DrainContext) => void | Promise<void>) | undefined\nlet globalEnabled = true\n\n/**\n * Initialize the logger with configuration.\n * Call this once at application startup.\n */\nexport function initLogger(config: LoggerConfig = {}): void {\n globalEnabled = config.enabled ?? true\n const detected = detectEnvironment()\n\n globalEnv = {\n service: config.env?.service ?? detected.service ?? 'app',\n environment: config.env?.environment ?? detected.environment ?? 'development',\n version: config.env?.version ?? detected.version,\n commitHash: config.env?.commitHash ?? detected.commitHash,\n region: config.env?.region ?? detected.region,\n }\n\n globalPretty = config.pretty ?? isDev()\n globalSampling = config.sampling ?? {}\n globalStringify = config.stringify ?? true\n globalDrain = config.drain\n}\n\n/**\n * Check if logging is globally enabled.\n */\nexport function isEnabled(): boolean {\n return globalEnabled\n}\n\n/**\n * Determine if a log at the given level should be emitted based on sampling config.\n * Error level defaults to 100% (always logged) unless explicitly configured otherwise.\n */\nfunction shouldSample(level: LogLevel): boolean {\n const { rates } = globalSampling\n if (!rates) {\n return true // No sampling configured, log everything\n }\n\n // Error defaults to 100% unless explicitly set\n const percentage = level === 'error' && rates.error === undefined\n ? 100\n : rates[level] ?? 100\n\n // 0% = never log, 100% = always log\n if (percentage <= 0) return false\n if (percentage >= 100) return true\n\n return Math.random() * 100 < percentage\n}\n\n/**\n * Evaluate tail sampling conditions to determine if a log should be force-kept.\n * Returns true if ANY condition matches (OR logic).\n */\nexport function shouldKeep(ctx: TailSamplingContext): boolean {\n const { keep } = globalSampling\n if (!keep?.length) return false\n\n return keep.some((condition) => {\n if (condition.status !== undefined && ctx.status !== undefined && ctx.status >= condition.status) {\n return true\n }\n if (condition.duration !== undefined && ctx.duration !== undefined && ctx.duration >= condition.duration) {\n return true\n }\n if (condition.path && ctx.path && matchesPattern(ctx.path, condition.path)) {\n return true\n }\n return false\n })\n}\n\nfunction emitWideEvent(level: LogLevel, event: Record<string, unknown>, skipSamplingCheck = false): WideEvent | null {\n if (!globalEnabled) return null\n\n if (!skipSamplingCheck && !shouldSample(level)) {\n return null\n }\n\n const formatted: WideEvent = {\n timestamp: new Date().toISOString(),\n level,\n ...globalEnv,\n ...event,\n }\n\n if (globalPretty) {\n prettyPrintWideEvent(formatted)\n } else if (globalStringify) {\n console[getConsoleMethod(level)](JSON.stringify(formatted))\n } else {\n console[getConsoleMethod(level)](formatted)\n }\n\n if (globalDrain) {\n Promise.resolve(globalDrain({ event: formatted })).catch((err) => {\n console.error('[evlog] drain failed:', err)\n })\n }\n\n return formatted\n}\n\nfunction emitTaggedLog(level: LogLevel, tag: string, message: string): void {\n if (!globalEnabled) return\n\n if (globalPretty) {\n if (!shouldSample(level)) {\n return\n }\n\n if (isClient()) {\n const levelColor = getCssLevelColor(level)\n const timestamp = new Date().toISOString().slice(11, 23)\n console.log(\n `%c${timestamp}%c %c[${escapeFormatString(tag)}]%c ${escapeFormatString(message)}`,\n cssColors.dim,\n cssColors.reset,\n levelColor,\n cssColors.reset,\n )\n return\n }\n\n const color = getLevelColor(level)\n const timestamp = new Date().toISOString().slice(11, 23)\n console.log(`${colors.dim}${timestamp}${colors.reset} ${color}[${tag}]${colors.reset} ${message}`)\n return\n }\n emitWideEvent(level, { tag, message })\n}\n\nfunction formatValue(value: unknown): string {\n if (value === null || value === undefined) {\n return String(value)\n }\n if (typeof value === 'object') {\n // Flatten object to key=value pairs\n const pairs: string[] = []\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n if (v !== undefined && v !== null) {\n if (typeof v === 'object') {\n // For nested objects, show as JSON\n pairs.push(`${k}=${JSON.stringify(v)}`)\n } else {\n pairs.push(`${k}=${v}`)\n }\n }\n }\n return pairs.join(' ')\n }\n return String(value)\n}\n\nfunction prettyPrintWideEvent(event: Record<string, unknown>): void {\n if (isClient()) {\n prettyPrintWideEventBrowser(event)\n return\n }\n\n const { timestamp, level, service, environment, version, ...rest } = event\n const levelColor = getLevelColor(level as string)\n const ts = (timestamp as string).slice(11, 23)\n\n let header = `${colors.dim}${ts}${colors.reset} ${levelColor}${(level as string).toUpperCase()}${colors.reset}`\n header += ` ${colors.cyan}[${service}]${colors.reset}`\n\n if (rest.method && rest.path) {\n header += ` ${rest.method} ${rest.path}`\n delete rest.method\n delete rest.path\n }\n\n if (rest.status) {\n const statusColor = (rest.status as number) >= 400 ? colors.red : colors.green\n header += ` ${statusColor}${rest.status}${colors.reset}`\n delete rest.status\n }\n\n if (rest.duration) {\n header += ` ${colors.dim}in ${rest.duration}${colors.reset}`\n delete rest.duration\n }\n\n console.log(header)\n\n const entries = Object.entries(rest).filter(([_, v]) => v !== undefined)\n const lastIndex = entries.length - 1\n\n entries.forEach(([key, value], index) => {\n const isLast = index === lastIndex\n const prefix = isLast ? '└─' : '├─'\n const formatted = formatValue(value)\n console.log(` ${colors.dim}${prefix}${colors.reset} ${colors.cyan}${key}:${colors.reset} ${formatted}`)\n })\n}\n\nfunction prettyPrintWideEventBrowser(event: Record<string, unknown>): void {\n const { timestamp, level, service, environment, version, ...rest } = event\n const levelColor = getCssLevelColor(level as string)\n const ts = (timestamp as string).slice(11, 23)\n\n const parts: string[] = []\n const styles: string[] = []\n\n parts.push(`%c${ts}%c %c${(level as string).toUpperCase()}%c %c[${escapeFormatString(String(service))}]%c`)\n styles.push(cssColors.dim, cssColors.reset, levelColor, cssColors.reset, cssColors.cyan, cssColors.reset)\n\n if (rest.method && rest.path) {\n parts.push(` ${escapeFormatString(String(rest.method))} ${escapeFormatString(String(rest.path))}`)\n delete rest.method\n delete rest.path\n }\n\n if (rest.status) {\n const statusColor = (rest.status as number) >= 400 ? cssColors.red : cssColors.green\n parts.push(` %c${rest.status}%c`)\n styles.push(statusColor, cssColors.reset)\n delete rest.status\n }\n\n if (rest.duration) {\n parts.push(` %c${escapeFormatString(`in ${rest.duration}`)}%c`)\n styles.push(cssColors.dim, cssColors.reset)\n delete rest.duration\n }\n\n console.log(parts.join(''), ...styles)\n\n const entries = Object.entries(rest).filter(([_, v]) => v !== undefined)\n const lastIndex = entries.length - 1\n\n entries.forEach(([key, value], index) => {\n const isLast = index === lastIndex\n const prefix = isLast ? '└─' : '├─'\n const formatted = escapeFormatString(formatValue(value))\n console.log(\n ` %c${prefix}%c %c${escapeFormatString(key)}:%c ${formatted}`,\n cssColors.dim,\n cssColors.reset,\n cssColors.cyan,\n cssColors.reset,\n )\n })\n}\n\nfunction createLogMethod(level: LogLevel) {\n return function logMethod(tagOrEvent: string | Record<string, unknown>, message?: string): void {\n if (typeof tagOrEvent === 'string' && message !== undefined) {\n emitTaggedLog(level, tagOrEvent, message)\n } else if (typeof tagOrEvent === 'object') {\n emitWideEvent(level, tagOrEvent)\n } else {\n emitTaggedLog(level, 'log', String(tagOrEvent))\n }\n }\n}\n\n/**\n * Simple logging API - as easy as console.log\n *\n * @example\n * ```ts\n * log.info('auth', 'User logged in')\n * log.error({ action: 'payment', error: 'failed' })\n * ```\n */\nconst _log: Log = {\n info: createLogMethod('info'),\n error: createLogMethod('error'),\n warn: createLogMethod('warn'),\n debug: createLogMethod('debug'),\n}\n\nexport { _log as log }\n\nconst noopLogger: RequestLogger = {\n set() {},\n error() {},\n info() {},\n warn() {},\n emit() {\n return null\n },\n getContext() {\n return {}\n },\n}\n\n/**\n * Create a scoped logger for building wide events.\n * Use this for any context: workflows, jobs, scripts, queues, etc.\n *\n * @example\n * ```ts\n * const log = createLogger({ jobId: job.id, queue: 'emails' })\n * log.set({ batch: { size: 50, processed: 12 } })\n * log.emit()\n * ```\n */\nexport function createLogger<T extends object = Record<string, unknown>>(initialContext: Record<string, unknown> = {}): RequestLogger<T> {\n if (!globalEnabled) return noopLogger as RequestLogger<T>\n\n const startTime = Date.now()\n let context: Record<string, unknown> = { ...initialContext }\n let hasError = false\n let hasWarn = false\n\n function addLog(level: 'info' | 'warn', message: string): void {\n const entry = {\n level,\n message,\n timestamp: new Date().toISOString(),\n }\n\n const requestLogs = Array.isArray(context.requestLogs)\n ? [...context.requestLogs, entry]\n : [entry]\n\n context = {\n ...context,\n requestLogs,\n }\n }\n\n return {\n set(data: FieldContext<T>): void {\n context = deepDefaults(data as Record<string, unknown>, context) as Record<string, unknown>\n },\n\n error(error: Error | string, errorContext?: FieldContext<T>): void {\n hasError = true\n const err = typeof error === 'string' ? new Error(error) : error\n\n const errorData = {\n ...(errorContext as Record<string, unknown>),\n error: {\n name: err.name,\n message: err.message,\n stack: err.stack,\n ...('status' in err && { status: (err as Record<string, unknown>).status }),\n ...('statusText' in err && { statusText: (err as Record<string, unknown>).statusText }),\n ...('statusCode' in err && { statusCode: (err as Record<string, unknown>).statusCode }),\n ...('statusMessage' in err && { statusMessage: (err as Record<string, unknown>).statusMessage }),\n ...('data' in err && { data: (err as Record<string, unknown>).data }),\n ...('cause' in err && { cause: (err as unknown as Record<string, unknown>).cause }),\n },\n }\n context = deepDefaults(errorData, context) as Record<string, unknown>\n },\n\n info(message: string, infoContext?: FieldContext<T>): void {\n addLog('info', message)\n if (infoContext) {\n const { requestLogs: _, ...rest } = infoContext as Record<string, unknown>\n context = deepDefaults(rest, context) as Record<string, unknown>\n }\n },\n\n warn(message: string, warnContext?: FieldContext<T>): void {\n hasWarn = true\n addLog('warn', message)\n if (warnContext) {\n const { requestLogs: _, ...rest } = warnContext as Record<string, unknown>\n context = deepDefaults(rest, context) as Record<string, unknown>\n }\n },\n\n emit(overrides?: FieldContext<T> & { _forceKeep?: boolean }): WideEvent | null {\n const durationMs = Date.now() - startTime\n const duration = formatDuration(durationMs)\n const level: LogLevel = hasError ? 'error' : hasWarn ? 'warn' : 'info'\n\n // Extract _forceKeep from overrides (set by evlog:emit:keep hook)\n const { _forceKeep, ...restOverrides } = (overrides ?? {}) as Record<string, unknown> & { _forceKeep?: boolean }\n\n // Build tail sampling context\n const tailCtx: TailSamplingContext = {\n status: (context.status ?? restOverrides.status) as number | undefined,\n duration: durationMs,\n path: context.path as string | undefined,\n method: context.method as string | undefined,\n context: { ...context, ...restOverrides },\n }\n\n // Tail sampling: force keep if hook or built-in conditions match\n const forceKeep = _forceKeep || shouldKeep(tailCtx)\n\n // Apply head sampling only if not force-kept\n if (!forceKeep && !shouldSample(level)) {\n return null\n }\n\n return emitWideEvent(level, {\n ...context,\n ...restOverrides,\n duration,\n }, true)\n },\n\n getContext(): FieldContext<T> & Record<string, unknown> {\n return { ...context }\n },\n }\n}\n\n/**\n * Create a request-scoped logger for building wide events.\n * Convenience wrapper around `createLogger` that pre-populates HTTP request fields.\n *\n * @example\n * ```ts\n * const log = createRequestLogger({ method: 'POST', path: '/checkout' })\n * log.set({ user: { id: '123' } })\n * log.set({ cart: { items: 3 } })\n * log.emit()\n * ```\n */\nexport function createRequestLogger<T extends object = Record<string, unknown>>(options: RequestLoggerOptions = {}): RequestLogger<T> {\n const initial: Record<string, unknown> = {}\n if (options.method !== undefined) initial.method = options.method\n if (options.path !== undefined) initial.path = options.path\n if (options.requestId !== undefined) initial.requestId = options.requestId\n return createLogger<T>(initial)\n}\n\n/**\n * Get the current environment context.\n */\nexport function getEnvironment(): EnvironmentContext {\n return { ...globalEnv }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"logger.mjs","names":[],"sources":["../src/logger.ts"],"sourcesContent":["import type { DrainContext, EnvironmentContext, FieldContext, Log, LogLevel, LoggerConfig, RequestLogger, RequestLoggerOptions, SamplingConfig, TailSamplingContext, WideEvent } from './types'\nimport { colors, cssColors, detectEnvironment, escapeFormatString, formatDuration, getConsoleMethod, getCssLevelColor, getLevelColor, isClient, isDev, matchesPattern } from './utils'\n\nfunction isPlainObject(val: unknown): val is Record<string, unknown> {\n return val !== null && typeof val === 'object' && !Array.isArray(val)\n}\n\nfunction deepDefaults(base: Record<string, unknown>, defaults: Record<string, unknown>): Record<string, unknown> {\n const result = { ...base }\n for (const key in defaults) {\n const baseVal = result[key]\n const defaultVal = defaults[key]\n if (baseVal === undefined || baseVal === null) {\n result[key] = defaultVal\n } else if (isPlainObject(baseVal) && isPlainObject(defaultVal)) {\n result[key] = deepDefaults(baseVal, defaultVal)\n }\n }\n return result\n}\n\nlet globalEnv: EnvironmentContext = {\n service: 'app',\n environment: 'development',\n}\n\nlet globalPretty = isDev()\nlet globalSampling: SamplingConfig = {}\nlet globalStringify = true\nlet globalDrain: ((ctx: DrainContext) => void | Promise<void>) | undefined\nlet globalEnabled = true\nlet globalSilent = false\n\n/**\n * Initialize the logger with configuration.\n * Call this once at application startup.\n */\nexport function initLogger(config: LoggerConfig = {}): void {\n globalEnabled = config.enabled ?? true\n const detected = detectEnvironment()\n\n globalEnv = {\n service: config.env?.service ?? detected.service ?? 'app',\n environment: config.env?.environment ?? detected.environment ?? 'development',\n version: config.env?.version ?? detected.version,\n commitHash: config.env?.commitHash ?? detected.commitHash,\n region: config.env?.region ?? detected.region,\n }\n\n globalPretty = config.pretty ?? isDev()\n globalSampling = config.sampling ?? {}\n globalStringify = config.stringify ?? true\n globalDrain = config.drain\n globalSilent = config.silent ?? false\n\n if (globalSilent && !globalDrain && !config._suppressDrainWarning) {\n console.warn('[evlog] silent mode is enabled but no drain is configured. Events will be built and sampled but not output anywhere. Set a drain via initLogger({ drain }) or a framework hook (evlog:drain).')\n }\n}\n\n/**\n * Check if logging is globally enabled.\n */\nexport function isEnabled(): boolean {\n return globalEnabled\n}\n\n/**\n * @internal Get the globally configured drain callback.\n * Used by framework middleware to fall back to the global drain\n * when no middleware-level drain is provided.\n */\nexport function getGlobalDrain(): ((ctx: DrainContext) => void | Promise<void>) | undefined {\n return globalDrain\n}\n\n/**\n * Determine if a log at the given level should be emitted based on sampling config.\n * Error level defaults to 100% (always logged) unless explicitly configured otherwise.\n */\nfunction shouldSample(level: LogLevel): boolean {\n const { rates } = globalSampling\n if (!rates) {\n return true // No sampling configured, log everything\n }\n\n // Error defaults to 100% unless explicitly set\n const percentage = level === 'error' && rates.error === undefined\n ? 100\n : rates[level] ?? 100\n\n // 0% = never log, 100% = always log\n if (percentage <= 0) return false\n if (percentage >= 100) return true\n\n return Math.random() * 100 < percentage\n}\n\n/**\n * Evaluate tail sampling conditions to determine if a log should be force-kept.\n * Returns true if ANY condition matches (OR logic).\n */\nexport function shouldKeep(ctx: TailSamplingContext): boolean {\n const { keep } = globalSampling\n if (!keep?.length) return false\n\n return keep.some((condition) => {\n if (condition.status !== undefined && ctx.status !== undefined && ctx.status >= condition.status) {\n return true\n }\n if (condition.duration !== undefined && ctx.duration !== undefined && ctx.duration >= condition.duration) {\n return true\n }\n if (condition.path && ctx.path && matchesPattern(ctx.path, condition.path)) {\n return true\n }\n return false\n })\n}\n\nfunction emitWideEvent(level: LogLevel, event: Record<string, unknown>, skipSamplingCheck = false, deferDrain = false): WideEvent | null {\n if (!globalEnabled) return null\n\n if (!skipSamplingCheck && !shouldSample(level)) {\n return null\n }\n\n const formatted: WideEvent = {\n timestamp: new Date().toISOString(),\n level,\n ...globalEnv,\n ...event,\n }\n\n if (!globalSilent) {\n if (globalPretty) {\n prettyPrintWideEvent(formatted)\n } else if (globalStringify) {\n console[getConsoleMethod(level)](JSON.stringify(formatted))\n } else {\n console[getConsoleMethod(level)](formatted)\n }\n }\n\n if (globalDrain && !deferDrain) {\n Promise.resolve(globalDrain({ event: formatted })).catch((err) => {\n console.error('[evlog] drain failed:', err)\n })\n }\n\n return formatted\n}\n\nfunction emitTaggedLog(level: LogLevel, tag: string, message: string): void {\n if (!globalEnabled) return\n\n if (globalPretty && !globalSilent) {\n if (!shouldSample(level)) {\n return\n }\n\n if (isClient()) {\n const levelColor = getCssLevelColor(level)\n const timestamp = new Date().toISOString().slice(11, 23)\n console.log(\n `%c${timestamp}%c %c[${escapeFormatString(tag)}]%c ${escapeFormatString(message)}`,\n cssColors.dim,\n cssColors.reset,\n levelColor,\n cssColors.reset,\n )\n } else {\n const color = getLevelColor(level)\n const timestamp = new Date().toISOString().slice(11, 23)\n console.log(`${colors.dim}${timestamp}${colors.reset} ${color}[${tag}]${colors.reset} ${message}`)\n }\n\n return\n }\n emitWideEvent(level, { tag, message })\n}\n\nfunction formatValue(value: unknown): string {\n if (value === null || value === undefined) {\n return String(value)\n }\n if (typeof value === 'object') {\n // Flatten object to key=value pairs\n const pairs: string[] = []\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n if (v !== undefined && v !== null) {\n if (typeof v === 'object') {\n // For nested objects, show as JSON\n pairs.push(`${k}=${JSON.stringify(v)}`)\n } else {\n pairs.push(`${k}=${v}`)\n }\n }\n }\n return pairs.join(' ')\n }\n return String(value)\n}\n\nfunction prettyPrintWideEvent(event: Record<string, unknown>): void {\n if (isClient()) {\n prettyPrintWideEventBrowser(event)\n return\n }\n\n const { timestamp, level, service, environment, version, ...rest } = event\n const levelColor = getLevelColor(level as string)\n const ts = (timestamp as string).slice(11, 23)\n\n let header = `${colors.dim}${ts}${colors.reset} ${levelColor}${(level as string).toUpperCase()}${colors.reset}`\n header += ` ${colors.cyan}[${service}]${colors.reset}`\n\n if (rest.method && rest.path) {\n header += ` ${rest.method} ${rest.path}`\n delete rest.method\n delete rest.path\n }\n\n if (rest.status) {\n const statusColor = (rest.status as number) >= 400 ? colors.red : colors.green\n header += ` ${statusColor}${rest.status}${colors.reset}`\n delete rest.status\n }\n\n if (rest.duration) {\n header += ` ${colors.dim}in ${rest.duration}${colors.reset}`\n delete rest.duration\n }\n\n console.log(header)\n\n const entries = Object.entries(rest).filter(([_, v]) => v !== undefined)\n const lastIndex = entries.length - 1\n\n entries.forEach(([key, value], index) => {\n const isLast = index === lastIndex\n const prefix = isLast ? '└─' : '├─'\n const formatted = formatValue(value)\n console.log(` ${colors.dim}${prefix}${colors.reset} ${colors.cyan}${key}:${colors.reset} ${formatted}`)\n })\n}\n\nfunction prettyPrintWideEventBrowser(event: Record<string, unknown>): void {\n const { timestamp, level, service, environment, version, ...rest } = event\n const levelColor = getCssLevelColor(level as string)\n const ts = (timestamp as string).slice(11, 23)\n\n const parts: string[] = []\n const styles: string[] = []\n\n parts.push(`%c${ts}%c %c${(level as string).toUpperCase()}%c %c[${escapeFormatString(String(service))}]%c`)\n styles.push(cssColors.dim, cssColors.reset, levelColor, cssColors.reset, cssColors.cyan, cssColors.reset)\n\n if (rest.method && rest.path) {\n parts.push(` ${escapeFormatString(String(rest.method))} ${escapeFormatString(String(rest.path))}`)\n delete rest.method\n delete rest.path\n }\n\n if (rest.status) {\n const statusColor = (rest.status as number) >= 400 ? cssColors.red : cssColors.green\n parts.push(` %c${rest.status}%c`)\n styles.push(statusColor, cssColors.reset)\n delete rest.status\n }\n\n if (rest.duration) {\n parts.push(` %c${escapeFormatString(`in ${rest.duration}`)}%c`)\n styles.push(cssColors.dim, cssColors.reset)\n delete rest.duration\n }\n\n console.log(parts.join(''), ...styles)\n\n const entries = Object.entries(rest).filter(([_, v]) => v !== undefined)\n const lastIndex = entries.length - 1\n\n entries.forEach(([key, value], index) => {\n const isLast = index === lastIndex\n const prefix = isLast ? '└─' : '├─'\n const formatted = escapeFormatString(formatValue(value))\n console.log(\n ` %c${prefix}%c %c${escapeFormatString(key)}:%c ${formatted}`,\n cssColors.dim,\n cssColors.reset,\n cssColors.cyan,\n cssColors.reset,\n )\n })\n}\n\nfunction createLogMethod(level: LogLevel) {\n return function logMethod(tagOrEvent: string | Record<string, unknown>, message?: string): void {\n if (typeof tagOrEvent === 'string' && message !== undefined) {\n emitTaggedLog(level, tagOrEvent, message)\n } else if (typeof tagOrEvent === 'object') {\n emitWideEvent(level, tagOrEvent)\n } else {\n emitTaggedLog(level, 'log', String(tagOrEvent))\n }\n }\n}\n\n/**\n * Simple logging API - as easy as console.log\n *\n * @example\n * ```ts\n * log.info('auth', 'User logged in')\n * log.error({ action: 'payment', error: 'failed' })\n * ```\n */\nconst _log: Log = {\n info: createLogMethod('info'),\n error: createLogMethod('error'),\n warn: createLogMethod('warn'),\n debug: createLogMethod('debug'),\n}\n\nexport { _log as log }\n\nconst noopLogger: RequestLogger = {\n set() {},\n error() {},\n info() {},\n warn() {},\n emit() {\n return null\n },\n getContext() {\n return {}\n },\n}\n\n/**\n * @internal Options for createLogger that are not part of the public API.\n */\ninterface CreateLoggerInternalOptions {\n /**\n * When true, the global drain is skipped on emit.\n * Used by framework middleware that runs its own enrich+drain pipeline.\n */\n _deferDrain?: boolean\n}\n\n/**\n * Create a scoped logger for building wide events.\n * Use this for any context: workflows, jobs, scripts, queues, etc.\n *\n * @example\n * ```ts\n * const log = createLogger({ jobId: job.id, queue: 'emails' })\n * log.set({ batch: { size: 50, processed: 12 } })\n * log.emit()\n * ```\n */\nexport function createLogger<T extends object = Record<string, unknown>>(initialContext: Record<string, unknown> = {}, internalOptions?: CreateLoggerInternalOptions): RequestLogger<T> {\n if (!globalEnabled) return noopLogger as RequestLogger<T>\n\n const deferDrain = internalOptions?._deferDrain ?? false\n const startTime = Date.now()\n let context: Record<string, unknown> = { ...initialContext }\n let hasError = false\n let hasWarn = false\n\n function addLog(level: 'info' | 'warn', message: string): void {\n const entry = {\n level,\n message,\n timestamp: new Date().toISOString(),\n }\n\n const requestLogs = Array.isArray(context.requestLogs)\n ? [...context.requestLogs, entry]\n : [entry]\n\n context = {\n ...context,\n requestLogs,\n }\n }\n\n return {\n set(data: FieldContext<T>): void {\n context = deepDefaults(data as Record<string, unknown>, context) as Record<string, unknown>\n },\n\n error(error: Error | string, errorContext?: FieldContext<T>): void {\n hasError = true\n const err = typeof error === 'string' ? new Error(error) : error\n\n const errorData = {\n ...(errorContext as Record<string, unknown>),\n error: {\n name: err.name,\n message: err.message,\n stack: err.stack,\n ...('status' in err && { status: (err as Record<string, unknown>).status }),\n ...('statusText' in err && { statusText: (err as Record<string, unknown>).statusText }),\n ...('statusCode' in err && { statusCode: (err as Record<string, unknown>).statusCode }),\n ...('statusMessage' in err && { statusMessage: (err as Record<string, unknown>).statusMessage }),\n ...('data' in err && { data: (err as Record<string, unknown>).data }),\n ...('cause' in err && { cause: (err as unknown as Record<string, unknown>).cause }),\n },\n }\n context = deepDefaults(errorData, context) as Record<string, unknown>\n },\n\n info(message: string, infoContext?: FieldContext<T>): void {\n addLog('info', message)\n if (infoContext) {\n const { requestLogs: _, ...rest } = infoContext as Record<string, unknown>\n context = deepDefaults(rest, context) as Record<string, unknown>\n }\n },\n\n warn(message: string, warnContext?: FieldContext<T>): void {\n hasWarn = true\n addLog('warn', message)\n if (warnContext) {\n const { requestLogs: _, ...rest } = warnContext as Record<string, unknown>\n context = deepDefaults(rest, context) as Record<string, unknown>\n }\n },\n\n emit(overrides?: FieldContext<T> & { _forceKeep?: boolean }): WideEvent | null {\n const durationMs = Date.now() - startTime\n const duration = formatDuration(durationMs)\n const level: LogLevel = hasError ? 'error' : hasWarn ? 'warn' : 'info'\n\n // Extract _forceKeep from overrides (set by evlog:emit:keep hook)\n const { _forceKeep, ...restOverrides } = (overrides ?? {}) as Record<string, unknown> & { _forceKeep?: boolean }\n\n // Build tail sampling context\n const tailCtx: TailSamplingContext = {\n status: (context.status ?? restOverrides.status) as number | undefined,\n duration: durationMs,\n path: context.path as string | undefined,\n method: context.method as string | undefined,\n context: { ...context, ...restOverrides },\n }\n\n // Tail sampling: force keep if hook or built-in conditions match\n const forceKeep = _forceKeep || shouldKeep(tailCtx)\n\n // Apply head sampling only if not force-kept\n if (!forceKeep && !shouldSample(level)) {\n return null\n }\n\n return emitWideEvent(level, {\n ...context,\n ...restOverrides,\n duration,\n }, true, deferDrain)\n },\n\n getContext(): FieldContext<T> & Record<string, unknown> {\n return { ...context }\n },\n }\n}\n\n/**\n * Create a request-scoped logger for building wide events.\n * Convenience wrapper around `createLogger` that pre-populates HTTP request fields.\n *\n * @example\n * ```ts\n * const log = createRequestLogger({ method: 'POST', path: '/checkout' })\n * log.set({ user: { id: '123' } })\n * log.set({ cart: { items: 3 } })\n * log.emit()\n * ```\n */\nexport function createRequestLogger<T extends object = Record<string, unknown>>(options: RequestLoggerOptions = {}, internalOptions?: CreateLoggerInternalOptions): RequestLogger<T> {\n const initial: Record<string, unknown> = {}\n if (options.method !== undefined) initial.method = options.method\n if (options.path !== undefined) initial.path = options.path\n if (options.requestId !== undefined) initial.requestId = options.requestId\n return createLogger<T>(initial, internalOptions)\n}\n\n/**\n * Get the current environment context.\n */\nexport function getEnvironment(): EnvironmentContext {\n return { ...globalEnv }\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as TailSamplingContext, T as WideEvent, g as RequestLogger, i as EnrichContext, r as DrainContext, v as RouteConfig } from "./types-
|
|
1
|
+
import { C as TailSamplingContext, T as WideEvent, g as RequestLogger, i as EnrichContext, r as DrainContext, v as RouteConfig } from "./types-US-1hJZl.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/shared/middleware.d.ts
|
|
4
4
|
/**
|
|
@@ -72,4 +72,4 @@ interface MiddlewareLoggerResult {
|
|
|
72
72
|
declare function createMiddlewareLogger(options: MiddlewareLoggerOptions): MiddlewareLoggerResult;
|
|
73
73
|
//#endregion
|
|
74
74
|
export { createMiddlewareLogger as i, MiddlewareLoggerOptions as n, MiddlewareLoggerResult as r, BaseEvlogOptions as t };
|
|
75
|
-
//# sourceMappingURL=middleware-
|
|
75
|
+
//# sourceMappingURL=middleware-CDLTVOBs.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware-
|
|
1
|
+
{"version":3,"file":"middleware-CDLTVOBs.d.mts","names":[],"sources":["../src/shared/middleware.ts"],"mappings":";;;;;AAcA;;;;;;;UAAiB,gBAAA;EAgByB;EAdxC,OAAA;EAmB4C;EAjB5C,OAAA;EAiBmD;EAfnD,MAAA,GAAS,MAAA,SAAe,WAAA;EAFxB;;;;EAOA,KAAA,IAAS,GAAA,EAAK,YAAA,YAAwB,OAAA;EAAxB;;;;EAKd,MAAA,IAAU,GAAA,EAAK,aAAA,YAAyB,OAAA;EAA9B;;;;EAKV,IAAA,IAAQ,GAAA,EAAK,mBAAA,YAA+B,OAAA;AAAA;;;AAQ9C;;;UAAiB,uBAAA,SAAgC,gBAAA;EAC/C,MAAA;EACA,IAAA;EACA,SAAA;EAAA;EAEA,OAAA,GAAU,MAAA;AAAA;AAAA,UAGK,sBAAA;EACf,MAAA,EAAQ,aAAA;EACR,MAAA,GAAS,IAAA;IAAS,MAAA;IAAiB,KAAA,GAAQ,KAAA;EAAA,MAAY,OAAA,CAAQ,SAAA;EAC/D,OAAA;AAAA;;;;;;;;;;;;;;;;AAuEF;iBAAgB,sBAAA,CAAuB,OAAA,EAAS,uBAAA,GAA0B,sBAAA"}
|
package/dist/nestjs/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { g as RequestLogger } from "../types-
|
|
2
|
-
import { t as BaseEvlogOptions } from "../middleware-
|
|
1
|
+
import { g as RequestLogger } from "../types-US-1hJZl.mjs";
|
|
2
|
+
import { t as BaseEvlogOptions } from "../middleware-CDLTVOBs.mjs";
|
|
3
3
|
import { DynamicModule, MiddlewareConsumer, NestModule } from "@nestjs/common";
|
|
4
4
|
|
|
5
5
|
//#region src/nestjs/index.d.ts
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/nestjs/index.ts"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/nestjs/index.ts"],"mappings":";;;;;cAQiB,SAAA,sBAAS,MAAA,wBAAA,aAAA,CAAA,CAAA;AAAA,KAId,kBAAA,GAAqB,gBAAA;AAAA,UAIhB,uBAAA;EANhB;EAQC,OAAA;EAVwB;EAYxB,UAAA,MAAgB,IAAA,YAAgB,kBAAA,GAAqB,OAAA,CAAQ,kBAAA;EAZrC;EAcxB,MAAA;AAAA;AAAA;EAAA,UAIU,eAAA;IACR,GAAA,GAAM,aAAA;EAAA;AAAA;AAAA;EAAA,UAKE,OAAA;IACR,GAAA,GAAM,aAAA;EAAA;AAAA;AAjBV;;;;;;;;;;;;;;;;;AAOC;;;;;;;AAPD,cA0Ea,WAAA,YAAuB,UAAA;EAAA,eAEnB,OAAA;EAjEM;AAAA;;;;;;;;;;EAAA,OA8Ed,OAAA,CAAQ,OAAA,GAAS,kBAAA,GAA0B,aAAA;EAf3B;;;;;;;;;;;;;;EAAA,OAqChB,YAAA,CAAa,YAAA,EAAc,uBAAA,GAA0B,aAAA;EAkB5D,SAAA,CAAU,QAAA,EAAU,kBAAA;AAAA"}
|
package/dist/nestjs/index.mjs
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { n as extractSafeNodeHeaders, r as createMiddlewareLogger } from "../headers-
|
|
2
|
-
import { t as createLoggerStorage } from "../storage-
|
|
1
|
+
import { n as extractSafeNodeHeaders, r as createMiddlewareLogger } from "../headers-BSgpnR0c.mjs";
|
|
2
|
+
import { t as createLoggerStorage } from "../storage-DHU1gGqV.mjs";
|
|
3
3
|
//#region src/nestjs/index.ts
|
|
4
4
|
const { storage, useLogger } = createLoggerStorage("middleware context. Make sure EvlogModule.forRoot() is imported in your AppModule.");
|
|
5
5
|
function createEvlogMiddleware(getOptions) {
|
|
6
6
|
return (req, res, next) => {
|
|
7
7
|
const options = getOptions();
|
|
8
8
|
const headers = extractSafeNodeHeaders(req.headers);
|
|
9
|
-
const url = new URL(req.url || "/", "http://localhost");
|
|
9
|
+
const url = new URL(req.originalUrl || req.url || "/", "http://localhost");
|
|
10
10
|
const { logger, finish, skipped } = createMiddlewareLogger({
|
|
11
11
|
method: req.method || "GET",
|
|
12
12
|
path: url.pathname,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/nestjs/index.ts"],"sourcesContent":["import type {
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/nestjs/index.ts"],"sourcesContent":["import type { ServerResponse } from 'node:http'\nimport type { Request } from 'express'\nimport type { DynamicModule, MiddlewareConsumer, NestModule } from '@nestjs/common'\nimport type { RequestLogger } from '../types'\nimport { createMiddlewareLogger, type BaseEvlogOptions } from '../shared/middleware'\nimport { extractSafeNodeHeaders } from '../shared/headers'\nimport { createLoggerStorage } from '../shared/storage'\n\nconst { storage, useLogger } = createLoggerStorage(\n 'middleware context. Make sure EvlogModule.forRoot() is imported in your AppModule.',\n)\n\nexport type EvlogNestJSOptions = BaseEvlogOptions\n\nexport { useLogger }\n\nexport interface EvlogModuleAsyncOptions {\n /** Modules to import (for dependency injection into the factory) */\n imports?: any[]\n /** Factory function that returns evlog options. Can be async. */\n useFactory: (...args: any[]) => EvlogNestJSOptions | Promise<EvlogNestJSOptions>\n /** Injection tokens to resolve and pass to the factory */\n inject?: any[]\n}\n\ndeclare module 'http' {\n interface IncomingMessage {\n log?: RequestLogger\n }\n}\n\ndeclare module 'express-serve-static-core' {\n interface Request {\n log?: RequestLogger\n }\n}\n\nfunction createEvlogMiddleware(getOptions: () => EvlogNestJSOptions) {\n return (req: Request, res: ServerResponse, next: () => void) => {\n const options = getOptions()\n const headers = extractSafeNodeHeaders(req.headers)\n const url = new URL(req.originalUrl || req.url || '/', 'http://localhost')\n\n const { logger, finish, skipped } = createMiddlewareLogger({\n method: req.method || 'GET',\n path: url.pathname,\n requestId: headers['x-request-id'] || crypto.randomUUID(),\n headers,\n ...options,\n })\n\n if (skipped) {\n next()\n return\n }\n\n req.log = logger\n\n res.on('finish', () => {\n finish({ status: res.statusCode }).catch(() => {})\n })\n\n storage.run(logger, () => next())\n }\n}\n\n/**\n * NestJS module for evlog wide event logging.\n *\n * Registers a global middleware that creates a request-scoped logger\n * for every incoming request. Use `useLogger()` to access it anywhere\n * in the call stack, or `req.log` directly in controllers.\n *\n * @example\n * ```ts\n * import { Module } from '@nestjs/common'\n * import { EvlogModule } from 'evlog/nestjs'\n * import { createAxiomDrain } from 'evlog/axiom'\n *\n * @Module({\n * imports: [\n * EvlogModule.forRoot({\n * drain: createAxiomDrain(),\n * exclude: ['/health'],\n * }),\n * ],\n * })\n * export class AppModule {}\n * ```\n */\nexport class EvlogModule implements NestModule {\n\n private static options: EvlogNestJSOptions = {}\n\n /**\n * Register evlog with static configuration.\n *\n * @example\n * ```ts\n * EvlogModule.forRoot({\n * drain: createAxiomDrain(),\n * enrich: (ctx) => { ctx.event.region = process.env.FLY_REGION },\n * })\n * ```\n */\n static forRoot(options: EvlogNestJSOptions = {}): DynamicModule {\n EvlogModule.options = options\n return {\n module: EvlogModule,\n global: true,\n }\n }\n\n /**\n * Register evlog with async configuration (e.g. from `ConfigService`).\n *\n * @example\n * ```ts\n * EvlogModule.forRootAsync({\n * imports: [ConfigModule],\n * inject: [ConfigService],\n * useFactory: (config: ConfigService) => ({\n * drain: createAxiomDrain({ token: config.get('AXIOM_TOKEN') }),\n * }),\n * })\n * ```\n */\n static forRootAsync(asyncOptions: EvlogModuleAsyncOptions): DynamicModule {\n return {\n module: EvlogModule,\n imports: asyncOptions.imports || [],\n providers: [\n {\n provide: 'EVLOG_OPTIONS',\n useFactory: async (...args: any[]) => {\n EvlogModule.options = await asyncOptions.useFactory(...args)\n return EvlogModule.options\n },\n inject: asyncOptions.inject || [],\n },\n ],\n global: true,\n }\n }\n\n configure(consumer: MiddlewareConsumer): void {\n consumer\n .apply(createEvlogMiddleware(() => EvlogModule.options))\n .forRoutes('*')\n }\n\n}\n"],"mappings":";;;AAQA,MAAM,EAAE,SAAS,cAAc,oBAC7B,qFACD;AA2BD,SAAS,sBAAsB,YAAsC;AACnE,SAAQ,KAAc,KAAqB,SAAqB;EAC9D,MAAM,UAAU,YAAY;EAC5B,MAAM,UAAU,uBAAuB,IAAI,QAAQ;EACnD,MAAM,MAAM,IAAI,IAAI,IAAI,eAAe,IAAI,OAAO,KAAK,mBAAmB;EAE1E,MAAM,EAAE,QAAQ,QAAQ,YAAY,uBAAuB;GACzD,QAAQ,IAAI,UAAU;GACtB,MAAM,IAAI;GACV,WAAW,QAAQ,mBAAmB,OAAO,YAAY;GACzD;GACA,GAAG;GACJ,CAAC;AAEF,MAAI,SAAS;AACX,SAAM;AACN;;AAGF,MAAI,MAAM;AAEV,MAAI,GAAG,gBAAgB;AACrB,UAAO,EAAE,QAAQ,IAAI,YAAY,CAAC,CAAC,YAAY,GAAG;IAClD;AAEF,UAAQ,IAAI,cAAc,MAAM,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BrC,IAAa,cAAb,MAAa,YAAkC;CAE7C,OAAe,UAA8B,EAAE;;;;;;;;;;;;CAa/C,OAAO,QAAQ,UAA8B,EAAE,EAAiB;AAC9D,cAAY,UAAU;AACtB,SAAO;GACL,QAAQ;GACR,QAAQ;GACT;;;;;;;;;;;;;;;;CAiBH,OAAO,aAAa,cAAsD;AACxE,SAAO;GACL,QAAQ;GACR,SAAS,aAAa,WAAW,EAAE;GACnC,WAAW,CACT;IACE,SAAS;IACT,YAAY,OAAO,GAAG,SAAgB;AACpC,iBAAY,UAAU,MAAM,aAAa,WAAW,GAAG,KAAK;AAC5D,YAAO,YAAY;;IAErB,QAAQ,aAAa,UAAU,EAAE;IAClC,CACF;GACD,QAAQ;GACT;;CAGH,UAAU,UAAoC;AAC5C,WACG,MAAM,4BAA4B,YAAY,QAAQ,CAAC,CACvD,UAAU,IAAI"}
|
package/dist/next/client.d.mts
CHANGED
package/dist/next/index.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { a as EnvironmentContext, d as Log, g as RequestLogger, y as SamplingConfig } from "../types-
|
|
2
|
-
import { n as createError } from "../error-
|
|
3
|
-
import { t as _log } from "../logger-
|
|
4
|
-
import { t as BaseEvlogOptions } from "../middleware-
|
|
1
|
+
import { a as EnvironmentContext, d as Log, g as RequestLogger, y as SamplingConfig } from "../types-US-1hJZl.mjs";
|
|
2
|
+
import { n as createError } from "../error-BuPbEDGO.mjs";
|
|
3
|
+
import { t as _log } from "../logger-BH1gOdNP.mjs";
|
|
4
|
+
import { t as BaseEvlogOptions } from "../middleware-CDLTVOBs.mjs";
|
|
5
5
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
6
6
|
|
|
7
7
|
//#region src/next/types.d.ts
|
|
@@ -34,6 +34,12 @@ interface NextEvlogOptions extends BaseEvlogOptions {
|
|
|
34
34
|
* @default true
|
|
35
35
|
*/
|
|
36
36
|
stringify?: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Suppress built-in console output.
|
|
39
|
+
* Events are still built, sampled, and passed to drains.
|
|
40
|
+
* @default false
|
|
41
|
+
*/
|
|
42
|
+
silent?: boolean;
|
|
37
43
|
}
|
|
38
44
|
interface EvlogMiddlewareConfig {
|
|
39
45
|
/**
|