@stacksjs/logging 0.72.8 → 0.72.9
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/dist/index.d.ts +19 -8
- package/dist/index.js +9 -6
- package/package.json +7 -7
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,22 @@
|
|
|
1
|
+
import type { LogContext, LogLevel, LogRecord, LogTransport } from '@stacksjs/types';
|
|
2
|
+
// Request context propagation for structured logging, and the transport
|
|
3
|
+
// contract. Both are declared in `@stacksjs/types` so `config/logging.ts` can
|
|
4
|
+
// reference them without importing this package, which would be a cycle. They
|
|
5
|
+
// are re-exported here because this is where consumers already import them
|
|
6
|
+
// from.
|
|
7
|
+
export type { LogContext, LogLevel, LogRecord, LogTransport } from '@stacksjs/types';
|
|
8
|
+
/**
|
|
9
|
+
* Attach a transport at runtime, and get back a function that detaches it.
|
|
10
|
+
*
|
|
11
|
+
* The alternative to declaring one in `config/logging.ts`, for a package that
|
|
12
|
+
* has to attach without the application editing its config. Registering also
|
|
13
|
+
* initializes the logger, so a transport attached at boot starts receiving
|
|
14
|
+
* `debug` records immediately rather than waiting for the first console-visible
|
|
15
|
+
* line to build the config.
|
|
16
|
+
*/
|
|
17
|
+
export declare function registerTransport(transport: LogTransport): () => void;
|
|
18
|
+
/** The transports currently attached. A copy, so callers cannot mutate the list. */
|
|
19
|
+
export declare function transports(): readonly LogTransport[];
|
|
1
20
|
/**
|
|
2
21
|
* Parse + validate `LOG_LEVEL` (stacksjs/stacks#1932). Previously the
|
|
3
22
|
* env value was cast `as any` straight into the logger, so a typo
|
|
@@ -80,12 +99,6 @@ export declare function report(error: unknown, options?: ReportOptions): void;
|
|
|
80
99
|
declare function emit(level: 'debug' | 'info' | 'warn' | 'error', event: string, fields: StructuredFields): void;
|
|
81
100
|
export declare const log: Log;
|
|
82
101
|
export declare const struct: unknown;
|
|
83
|
-
// Request context propagation for structured logging
|
|
84
|
-
export declare interface LogContext {
|
|
85
|
-
requestId?: string
|
|
86
|
-
userId?: string | number
|
|
87
|
-
[key: string]: unknown
|
|
88
|
-
}
|
|
89
102
|
export declare interface ResolvedLogSettings {
|
|
90
103
|
level: LogLevel
|
|
91
104
|
format: LogFormat
|
|
@@ -160,8 +173,6 @@ export declare interface ReportOptions {
|
|
|
160
173
|
* `log.struct` to a custom transport in tests.
|
|
161
174
|
*/
|
|
162
175
|
declare interface StructuredFields { [key: string]: unknown }
|
|
163
|
-
/** Valid log levels — mirrors `@stacksjs/clarity`'s `LogLevel`. */
|
|
164
|
-
export type LogLevel = 'debug' | 'info' | 'success' | 'warning' | 'error';
|
|
165
176
|
export type LogFormat = 'json' | 'text';
|
|
166
177
|
export type ErrorMessage = string;
|
|
167
178
|
// Export logger getter for debugging
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var
|
|
3
|
-
`),
|
|
4
|
-
`);return
|
|
5
|
-
|
|
2
|
+
var R=import.meta.require;import{AsyncLocalStorage as x}from"async_hooks";import X from"process";import{Logger as v}from"@stacksjs/clarity";import{handleError as u}from"@stacksjs/error-handling";import{ExitCode as S}from"@stacksjs/types";var I=null,F=null,T=new Set;function z(B){return T.add(B),B.finally(()=>T.delete(B)).catch(()=>{}),B}var w=!1;function d(){if(w)return;w=!0,X.on("beforeExit",()=>{G.flush()})}var K=[],y=new Set,k={debug:0,info:1,success:1,warning:2,error:3};function h(B){let H=B;if(!H||typeof H!=="object"||typeof H.log!=="function")return X.stderr.write(`[logging] Ignoring a transport without a log() function.
|
|
3
|
+
`),null;if(typeof H.name!=="string"||!H.name)return X.stderr.write(`[logging] Ignoring a transport without a name.
|
|
4
|
+
`),null;return K.push(H),()=>{let J=K.indexOf(H);if(J!==-1)K.splice(J,1)}}function HB(B){let H=h(B);if(!H)return()=>{};return L(),H}function JB(){return[...K]}function q(B,H,J){if(K.length===0)return;let Q;try{Q={level:B,message:H,args:J,context:V(),timestamp:new Date().toISOString()}}catch{return}for(let U of K){if(U.level&&k[B]<k[U.level])continue;try{U.log(Q)}catch(Z){if(!y.has(U.name)){y.add(U.name);let j=Z instanceof Error?Z.message:String(Z);X.stderr.write(`[logging] Transport "${U.name}" threw: ${j}. Further throws from it are silent.
|
|
5
|
+
`)}}}}async function c(){let B=K.filter((H)=>typeof H.flush==="function").map((H)=>H.flush().catch(()=>{}));if(B.length>0)await Promise.allSettled(B)}var C=new Set(["debug","info","success","warning","error"]);function _(B,H="info"){if(!B)return H;let J=B.toLowerCase();if(J==="warn")return"warning";if(C.has(J))return J;return X.stderr.write(`[logging] Ignoring invalid LOG_LEVEL="${B}" (expected: ${[...C].join(", ")}); using "${H}".
|
|
6
|
+
`),H}function m(B){if(B==="json"||B==="text")return B;if(B)X.stderr.write(`[logging] Ignoring invalid LOG_FORMAT="${B}" (expected "json" or "text").
|
|
7
|
+
`);return X.env.NODE_ENV==="production"?"json":"text"}function p(B){let H=B.envLevel?_(B.envLevel):B.cfgLevel?_(B.cfgLevel):"info",J=B.envFormat?m(B.envFormat):B.cfgFormat==="json"||B.cfgFormat==="text"?B.cfgFormat:B.isProduction?"json":"text";return{level:H,format:J,writeToFile:B.cfgWriteToFile??!0}}function P(B,H=0){if(H>8)return{name:"Error",message:"[cause chain truncated]"};if(B instanceof Error)return{name:B.name,message:B.message,stack:B.stack,cause:B.cause!=null?P(B.cause,H+1):void 0};if(typeof B==="string")return{name:"Error",message:B};if(B==null)return{name:"Error",message:String(B)};try{return{name:"Error",message:JSON.stringify(W(B))}}catch{return{name:"Error",message:String(B)}}}function M(B){let H=B.stack||`${B.name}: ${B.message}`,J=B.cause;while(J)H+=`
|
|
8
|
+
caused by: ${J.stack||`${J.name}: ${J.message}`}`,J=J.cause;return H}function W(B,H=0){if(B instanceof Error)return P(B);if(H>=4||B===null||typeof B!=="object")return B;if(Array.isArray(B))return B.map((U)=>W(U,H+1));let J=Object.getPrototypeOf(B);if(J!==Object.prototype&&J!==null)return B;let Q={};for(let[U,Z]of Object.entries(B))Q[U]=W(Z,H+1);return Q}function E(B){return W(B)}var O=new x;function QB(B,H){return O.run(B,H)}function V(){let B=O.getStore(),H=i();if(!H)return B;return{trace_id:H,...B}}function i(){try{let H=globalThis[Symbol.for("stacks.router.traceStorage")]?.getStore?.();if(H)return H;return globalThis[Symbol.for("stacks.router.requestStorage")]?.getStore?.()?._requestId}catch{return}}async function L(){if(I)return;if(F)return F;return d(),F=(async()=>{let B,H,J,Q;try{let Y=(await import("@stacksjs/config")).logging;if(Y){if(B=Y.level,H=Y.format,typeof Y.writeToFile==="boolean")Q=Y.writeToFile;if(Y.logsPath)J=(await import("path")).dirname(Y.logsPath);if(Array.isArray(Y.transports))for(let b of Y.transports)h(b)}}catch{}let{level:U,format:Z,writeToFile:j}=p({envLevel:X.env.LOG_LEVEL,envFormat:X.env.LOG_FORMAT,cfgLevel:B,cfgFormat:H,cfgWriteToFile:Q,isProduction:X.env.NODE_ENV==="production"}),A=J;if(!A)try{A=(await import("@stacksjs/path")).projectPath("storage/logs")}catch{A="storage/logs"}I=new v("stacks",{level:U,logDirectory:A,showTags:!1,fancy:Z!=="json",format:Z,writeToFile:j})})(),F}async function $(){return await L(),I}function N(...B){let H=B.filter((Q)=>Q!==void 0).map((Q)=>{if(Q instanceof Error)return M(P(Q));if(typeof Q==="object"&&Q!==null)return JSON.stringify(W(Q),null,2);return String(Q)}).join(" "),J=O.getStore();if(J?.requestId)return`[${J.requestId}] ${H}`;return H}var n=new Set(["shouldExit","silent","message"]);function l(B){if(!B||typeof B!=="object"||B instanceof Error)return!1;if(!(("shouldExit"in B)||("silent"in B)))return!1;return Object.keys(B).every((H)=>n.has(H))}var G={info:async(...B)=>{let H=N(...B),J=await $();q("info",H,B),await J.info(H)},success:async(B)=>{let H=await $();q("success",B,[B]),await H.success(B)},warn:async(B,H)=>{let J=await $();if(q("warning",B,H===void 0?[B]:[B,H]),H==null){await J.warn(B);return}let Q=W(H);await J.warn(B,Q)},warning:async(B)=>{let H=await $();q("warning",B,[B]),await H.warn(B)},error:async(B,H,J)=>{let Q=l(H)?H:void 0,U;if(typeof B==="string")U=B;else U=M(P(B));if(H!==void 0&&!Q)U=`${U} ${M(P(H))}`;let Z={...V(),...J};if(Object.keys(Z).length>0)try{U=`${U} ${JSON.stringify(E(Z))}`}catch{}let j=await $();if(q("error",U,Q?[B]:[B,H,J].filter((A)=>A!==void 0)),await j.error(U),Q?.shouldExit)u(B,Q)},debug:async(...B)=>{let H=(X.env.LOG_LEVEL||"info").toLowerCase(),J=H==="info"||H==="warn"||H==="error";if(J&&K.length===0)return;let Q=N(...B);if(J){q("debug",Q,B);return}let U=await $();q("debug",Q,B),await U.debug(Q)},dump:async(...B)=>{let H=N(...B);await(await $()).debug(`DUMP: ${H}`)},dd:async(...B)=>{let H=N(...B);await(await $()).error(H),X.exit(S.FatalError)},echo:async(...B)=>{let H=N(...B);await(await $()).info(`ECHO: ${H}`)},time:(B)=>{let H=performance.now();return async(J)=>{let Q=performance.now()-H,U=await $(),Z=J?` ${JSON.stringify(E(J))}`:"";await U.info(`${B}: ${Q.toFixed(2)}ms${Z}`)}},syncWarn:(B)=>{X.stderr.write(`${B}
|
|
6
9
|
`)},syncError:(B)=>{X.stderr.write(`${B}
|
|
7
|
-
`)},fatal:(B,H=
|
|
8
|
-
`),X.exit(H)},exit:async(B,H=
|
|
10
|
+
`)},fatal:(B,H=S.FatalError)=>{X.stderr.write(`${B}
|
|
11
|
+
`),X.exit(H)},exit:async(B,H=S.Success)=>{if(B)await(H===S.Success?G.success(B):G.error(B));await G.flush(),X.exit(H)},flush:async()=>{if(T.size>0)await Promise.allSettled([...T]);if(await c(),!I&&!F)return;try{let B=await $(),H=B.flush;if(typeof H==="function")await H.call(B)}catch{}}};async function UB(...B){for(let H of B)await G.debug(H)}async function XB(...B){let H=N(...B);console.log(H),X.exit(S.FatalError)}async function ZB(...B){await G.debug(...B)}function g(B){if(B&&typeof B==="object"){let H=B;if(typeof H.status==="number")return H.status;if(typeof H.statusCode==="number")return H.statusCode}return}function $B(B,H={}){let J=H.status??g(B),Q=typeof J==="number"&&J>=400&&J<500,U=H.label??"Unhandled error",Z={...H.context,...J!=null?{status:J}:{}};if(Q){G.debug(`${U} (client error ${J}): ${P(B).message}`);return}G.error(U,B,Z)}function D(B,H,J){let Q=V(),U={event:H,traceId:Q?.requestId,...J};if(B==="warn")z(G.warn(`[${H}]`,U));else z(G[B](U))}var o={request(B,H,J,Q,U={}){let Z=J>=500?"error":J>=400?"warn":"info";D(Z,"http.request",{method:B,path:H,status:J,durationMs:Q,...U})},query(B,H,J={}){D("debug","db.query",{sql:B,durationMs:H,...J})},slowQuery(B,H,J={}){D("warn","db.slow_query",{sql:B,durationMs:H,...J})},job(B,H,J={}){D(H==="failed"?"error":"info",`job.${H}`,{jobName:B,...J})},cache(B,H,J={}){D("debug",`cache.${B}`,{key:H,...J})}};G.struct=o;export{QB as withLogContext,JB as transports,o as struct,p as resolveLogSettings,$B as report,M as renderNormalizedError,HB as registerTransport,_ as parseLogLevel,m as parseLogFormat,P as normalizeError,E as normalizeContext,$ as logger,G as log,V as getLogContext,N as formatMessage,ZB as echo,UB as dump,XB as dd};
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@stacksjs/logging",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"sideEffects": false,
|
|
5
|
-
"version": "0.72.
|
|
5
|
+
"version": "0.72.9",
|
|
6
6
|
"description": "The Stacks logging system.",
|
|
7
7
|
"author": "Chris Breuer",
|
|
8
8
|
"contributors": [
|
|
@@ -61,12 +61,12 @@
|
|
|
61
61
|
"@stacksjs/clarity": "^0.3.31"
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
64
|
-
"@stacksjs/cli": "0.72.
|
|
65
|
-
"@stacksjs/config": "0.72.
|
|
66
|
-
"@stacksjs/error-handling": "0.72.
|
|
67
|
-
"@stacksjs/path": "0.72.
|
|
68
|
-
"@stacksjs/storage": "0.72.
|
|
69
|
-
"@stacksjs/validation": "0.72.
|
|
64
|
+
"@stacksjs/cli": "0.72.9",
|
|
65
|
+
"@stacksjs/config": "0.72.9",
|
|
66
|
+
"@stacksjs/error-handling": "0.72.9",
|
|
67
|
+
"@stacksjs/path": "0.72.9",
|
|
68
|
+
"@stacksjs/storage": "0.72.9",
|
|
69
|
+
"@stacksjs/validation": "0.72.9",
|
|
70
70
|
"better-dx": "^0.2.23"
|
|
71
71
|
}
|
|
72
72
|
}
|