jsonl-logger 0.3.0 → 0.4.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 +53 -1
- package/dist/google-cloud-logging.js +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +5 -5
- package/dist/intercept.js +7 -7
- package/dist/preload.js +7 -7
- package/dist/types.d.ts +8 -0
- package/dist/victoria-logs.js +1 -1
- package/package.json +2 -2
- package/src/google-cloud-logging.ts +8 -0
- package/src/index.ts +12 -1
- package/src/intercept.ts +16 -2
- package/src/types.ts +9 -0
- package/src/victoria-logs.ts +7 -0
package/README.md
CHANGED
|
@@ -83,6 +83,58 @@ console.log('plain text') // → structured JSON
|
|
|
83
83
|
originalConsole.log('bypass interception')
|
|
84
84
|
```
|
|
85
85
|
|
|
86
|
+
## OpenTelemetry
|
|
87
|
+
|
|
88
|
+
The logger supports automatic trace context injection. Supply a `traceContext` getter that returns the active span's trace/span IDs — the formatter maps them to platform-specific fields automatically.
|
|
89
|
+
|
|
90
|
+
### With `@opentelemetry/api`
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
import { trace } from '@opentelemetry/api'
|
|
94
|
+
import { Logger } from 'jsonl-logger'
|
|
95
|
+
|
|
96
|
+
const logger = new Logger({}, {
|
|
97
|
+
traceContext: () => {
|
|
98
|
+
const span = trace.getActiveSpan()
|
|
99
|
+
if (!span) return undefined
|
|
100
|
+
const { traceId, spanId, traceFlags } = span.spanContext()
|
|
101
|
+
return { traceId, spanId, traceFlags }
|
|
102
|
+
},
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
logger.info('request handled', { path: '/api' })
|
|
106
|
+
// GCL output includes "logging.googleapis.com/trace", "logging.googleapis.com/spanId", etc.
|
|
107
|
+
// VictoriaLogs output includes "trace_id", "span_id", etc.
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Custom trace context
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
const logger = new Logger({}, {
|
|
114
|
+
traceContext: () => ({
|
|
115
|
+
traceId: myTracer.currentTraceId(),
|
|
116
|
+
spanId: myTracer.currentSpanId(),
|
|
117
|
+
}),
|
|
118
|
+
})
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
The `traceContext` option is also available on `intercept()`:
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
import { intercept } from 'jsonl-logger/intercept'
|
|
125
|
+
|
|
126
|
+
intercept({
|
|
127
|
+
traceContext: () => {
|
|
128
|
+
const span = trace.getActiveSpan()
|
|
129
|
+
if (!span) return undefined
|
|
130
|
+
const { traceId, spanId, traceFlags } = span.spanContext()
|
|
131
|
+
return { traceId, spanId, traceFlags }
|
|
132
|
+
},
|
|
133
|
+
})
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Child loggers inherit the `traceContext` getter from their parent.
|
|
137
|
+
|
|
86
138
|
## Next.js Integration
|
|
87
139
|
|
|
88
140
|
The preload module reads `LOG_FORMAT` and only activates when it's set. Safe to include unconditionally — it's a no-op without `LOG_FORMAT`.
|
|
@@ -188,7 +240,7 @@ The logger auto-detects the runtime and uses the fastest available I/O:
|
|
|
188
240
|
|
|
189
241
|
| Subpath | Export |
|
|
190
242
|
|---------|--------|
|
|
191
|
-
| `jsonl-logger` | `Logger`, `logger`, `errorInfo()`, types (`ErrorInfo`, `LogRecord`, etc.) |
|
|
243
|
+
| `jsonl-logger` | `Logger`, `logger`, `errorInfo()`, types (`ErrorInfo`, `LogRecord`, `TraceContext`, etc.) |
|
|
192
244
|
| `jsonl-logger/google-cloud-logging` | `GoogleCloudLogging` formatter |
|
|
193
245
|
| `jsonl-logger/victoria-logs` | `VictoriaLogs` formatter |
|
|
194
246
|
| `jsonl-logger/intercept` | `intercept()`, `originalConsole` |
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var g={debug:"DEBUG",info:"INFO",warn:"WARNING",error:"ERROR",fatal:"CRITICAL"},a={messageKey:"message",format(e){let t={message:e.message,timestamp:e.timestamp,severity:g[e.level],...e.context};if(e.trace){if(t["logging.googleapis.com/trace"]=e.trace.traceId,t["logging.googleapis.com/spanId"]=e.trace.spanId,e.trace.traceFlags!==void 0)t["logging.googleapis.com/trace_sampled"]=(e.trace.traceFlags&1)===1}return t}};export{a as GoogleCloudLogging};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ErrorInfo, LogContext, LoggerOptions } from './types';
|
|
2
|
-
export type { ErrorInfo, Formatter, FormatterName, InterceptOptions, LogContext, LoggerOptions, LogLevel, LogRecord, } from './types';
|
|
2
|
+
export type { ErrorInfo, Formatter, FormatterName, InterceptOptions, LogContext, LoggerOptions, LogLevel, LogRecord, TraceContext, } from './types';
|
|
3
3
|
export { logLevelValues, stripAnsi } from './types';
|
|
4
4
|
export declare function errorInfo(err: Error): ErrorInfo;
|
|
5
5
|
export declare class Logger {
|
|
@@ -7,6 +7,7 @@ export declare class Logger {
|
|
|
7
7
|
private min;
|
|
8
8
|
private json;
|
|
9
9
|
private fmt;
|
|
10
|
+
private tc?;
|
|
10
11
|
constructor(context?: LogContext, options?: LoggerOptions);
|
|
11
12
|
child(context: LogContext): Logger;
|
|
12
13
|
private log;
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
var
|
|
2
|
-
`);else if(
|
|
3
|
-
`);if(
|
|
1
|
+
var k={debug:"DEBUG",info:"INFO",warn:"WARNING",error:"ERROR",fatal:"CRITICAL"},f={messageKey:"message",format(t){let o={message:t.message,timestamp:t.timestamp,severity:k[t.level],...t.context};if(t.trace){if(o["logging.googleapis.com/trace"]=t.trace.traceId,o["logging.googleapis.com/spanId"]=t.trace.spanId,t.trace.traceFlags!==void 0)o["logging.googleapis.com/trace_sampled"]=(t.trace.traceFlags&1)===1}return o}};var d={messageKey:"_msg",format(t){let o={_msg:t.message,_time:t.timestamp,level:t.level,...t.context};if(t.trace){if(o.trace_id=t.trace.traceId,o.span_id=t.trace.spanId,t.trace.traceFlags!==void 0)o.trace_flags=t.trace.traceFlags}return o}};var i=process.env.LOG_FORMAT,C=!!i,a={debug:0,info:1,warn:2,error:3,fatal:4},$=/\x1b\[[0-9;]*m/g;function u(t){return t.replace($,"")}function p(t,o,e="error"){if(t[`${e}.name`]=o.name,t[`${e}.message`]=o.message,o.stack)t[`${e}.stack`]=o.stack;if(o.cause)p(t,o.cause,`${e}.cause`)}var L=typeof process<"u"&&process.stdout&&typeof process.stdout.write==="function"?"node":typeof Deno<"u"&&Deno.stdout?"deno":"browser",x=L==="deno"?new TextEncoder:null;function R(t,o){if(L==="node")(o?process.stderr??process.stdout:process.stdout).write(`${t}
|
|
2
|
+
`);else if(L==="deno"&&x){let e=x.encode(`${t}
|
|
3
|
+
`);if(o)Deno.stderr.writeSync(e);else Deno.stdout.writeSync(e)}else if(o)console.error(t);else console.log(t)}var E={"google-cloud-logging":f,"victoria-logs":d},O=i&&E[i]||f,w=C,S=process.env.LOG_LEVEL||(w?"info":"debug"),y={debug:!1,info:!1,warn:!1,error:!0,fatal:!0};function b(t,o){return o.add(t),{name:t.name,message:t.message,stack:t.stack,...t.cause instanceof Error&&!o.has(t.cause)?{cause:b(t.cause,o)}:{}}}function j(t){return b(t,new WeakSet)}class h{ctx;min;json;fmt;tc;constructor(t,o){this.ctx=t||{},this.json=o?.json??w,this.fmt=o?.formatter??O,this.tc=o?.traceContext;let e=o?.level??S;this.min=a[e]??a.info}child(t){let o=new h({...this.ctx,...t},{json:this.json,formatter:this.fmt,traceContext:this.tc});return o.min=this.min,o}log(t,o,e,c){if(a[t]<this.min)return;let s={level:t,message:this.json?u(o).trim():o,timestamp:new Date().toISOString(),context:e?{...this.ctx,...e}:this.ctx};if(this.tc)s.trace=this.tc();if(c)s.error=j(c);if(this.json){let g=this.fmt.format(s);if(s.error)p(g,s.error);R(JSON.stringify(g),y[t])}else this.logPlain(t,s)}logPlain(t,o){let e={debug:"\x1B[36m",info:"\x1B[32m",warn:"\x1B[33m",error:"\x1B[31m",fatal:"\x1B[35m"},c="\x1B[0m",s=e[t],g=new Date(o.timestamp).toLocaleTimeString("en-US",{hour12:!1}),I=t.toUpperCase().padEnd(5),v=o.context,F=Object.keys(v).length>0?` ${JSON.stringify(v)}`:"",m="";if(o.error){let n=o.error,l=!0;while(n){if(n.stack)m+=l?`
|
|
4
4
|
${n.stack}`:`
|
|
5
|
-
Caused by: ${n.stack}`;else
|
|
5
|
+
Caused by: ${n.stack}`;else m+=l?`
|
|
6
6
|
${n.name}: ${n.message}`:`
|
|
7
|
-
Caused by: ${n.name}: ${n.message}`;n=n.cause,l=!1}}let
|
|
7
|
+
Caused by: ${n.name}: ${n.message}`;n=n.cause,l=!1}}let r=`${s}${g} ${I}\x1B[0m ${o.message}${F}${m}`;switch(t){case"debug":console.debug(r);break;case"warn":console.warn(r);break;case"error":case"fatal":console.error(r);break;default:console.log(r)}}debug(t,o){this.log("debug",t,o)}info(t,o){this.log("info",t,o)}warn(t,o){this.log("warn",t,o)}error(t,o,e){this.log("error",t,o,e)}fatal(t,o,e){this.log("fatal",t,o,e)}}var J=new h;export{u as stripAnsi,J as logger,a as logLevelValues,j as errorInfo,h as Logger};
|
package/dist/intercept.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
var
|
|
2
|
-
`);else if(
|
|
3
|
-
`);if(
|
|
4
|
-
${
|
|
5
|
-
Caused by: ${
|
|
6
|
-
${
|
|
7
|
-
Caused by: ${
|
|
1
|
+
var j={debug:"DEBUG",info:"INFO",warn:"WARNING",error:"ERROR",fatal:"CRITICAL"},u={messageKey:"message",format(t){let o={message:t.message,timestamp:t.timestamp,severity:j[t.level],...t.context};if(t.trace){if(o["logging.googleapis.com/trace"]=t.trace.traceId,o["logging.googleapis.com/spanId"]=t.trace.spanId,t.trace.traceFlags!==void 0)o["logging.googleapis.com/trace_sampled"]=(t.trace.traceFlags&1)===1}return o}};var w={messageKey:"_msg",format(t){let o={_msg:t.message,_time:t.timestamp,level:t.level,...t.context};if(t.trace){if(o.trace_id=t.trace.traceId,o.span_id=t.trace.spanId,t.trace.traceFlags!==void 0)o.trace_flags=t.trace.traceFlags}return o}};var x=process.env.LOG_FORMAT,$=!!x,m={debug:0,info:1,warn:2,error:3,fatal:4},_=/\x1b\[[0-9;]*m/g;function h(t){return t.replace(_,"")}function p(t,o,n="error"){if(t[`${n}.name`]=o.name,t[`${n}.message`]=o.message,o.stack)t[`${n}.stack`]=o.stack;if(o.cause)p(t,o.cause,`${n}.cause`)}var b=typeof process<"u"&&process.stdout&&typeof process.stdout.write==="function"?"node":typeof Deno<"u"&&Deno.stdout?"deno":"browser",k=b==="deno"?new TextEncoder:null;function l(t,o){if(b==="node")(o?process.stderr??process.stdout:process.stdout).write(`${t}
|
|
2
|
+
`);else if(b==="deno"&&k){let n=k.encode(`${t}
|
|
3
|
+
`);if(o)Deno.stderr.writeSync(n);else Deno.stdout.writeSync(n)}else if(o)console.error(t);else console.log(t)}var E={"google-cloud-logging":u,"victoria-logs":w},N=x&&E[x]||u,v=$,T=process.env.LOG_LEVEL||(v?"info":"debug"),y={debug:!1,info:!1,warn:!1,error:!0,fatal:!0};function d(t,o){return o.add(t),{name:t.name,message:t.message,stack:t.stack,...t.cause instanceof Error&&!o.has(t.cause)?{cause:d(t.cause,o)}:{}}}function F(t){return d(t,new WeakSet)}class I{ctx;min;json;fmt;tc;constructor(t,o){this.ctx=t||{},this.json=o?.json??v,this.fmt=o?.formatter??N,this.tc=o?.traceContext;let n=o?.level??T;this.min=m[n]??m.info}child(t){let o=new I({...this.ctx,...t},{json:this.json,formatter:this.fmt,traceContext:this.tc});return o.min=this.min,o}log(t,o,n,e){if(m[t]<this.min)return;let c={level:t,message:this.json?h(o).trim():o,timestamp:new Date().toISOString(),context:n?{...this.ctx,...n}:this.ctx};if(this.tc)c.trace=this.tc();if(e)c.error=F(e);if(this.json){let a=this.fmt.format(c);if(c.error)p(a,c.error);l(JSON.stringify(a),y[t])}else this.logPlain(t,c)}logPlain(t,o){let n={debug:"\x1B[36m",info:"\x1B[32m",warn:"\x1B[33m",error:"\x1B[31m",fatal:"\x1B[35m"},e="\x1B[0m",c=n[t],a=new Date(o.timestamp).toLocaleTimeString("en-US",{hour12:!1}),i=t.toUpperCase().padEnd(5),L=o.context,R=Object.keys(L).length>0?` ${JSON.stringify(L)}`:"",f="";if(o.error){let s=o.error,C=!0;while(s){if(s.stack)f+=C?`
|
|
4
|
+
${s.stack}`:`
|
|
5
|
+
Caused by: ${s.stack}`;else f+=C?`
|
|
6
|
+
${s.name}: ${s.message}`:`
|
|
7
|
+
Caused by: ${s.name}: ${s.message}`;s=s.cause,C=!1}}let g=`${c}${a} ${i}\x1B[0m ${o.message}${R}${f}`;switch(t){case"debug":console.debug(g);break;case"warn":console.warn(g);break;case"error":case"fatal":console.error(g);break;default:console.log(g)}}debug(t,o){this.log("debug",t,o)}info(t,o){this.log("info",t,o)}warn(t,o){this.log("warn",t,o)}error(t,o,n){this.log("error",t,o,n)}fatal(t,o,n){this.log("fatal",t,o,n)}}var H=new I;var D={log:console.log.bind(console),info:console.info.bind(console),warn:console.warn.bind(console),error:console.error.bind(console),debug:console.debug.bind(console)};function G(...t){let o="";for(let n=0;n<t.length;n++){if(n>0)o+=" ";let e=t[n];if(typeof e==="string")o+=h(e);else if(e instanceof Error)o+=e.message;else try{o+=JSON.stringify(e)}catch{o+=String(e)}}return o.trim()}function A(...t){let o;for(let n of t)if(typeof n==="object"&&n!==null&&!(n instanceof Error)&&!Array.isArray(n)){if(!o)o={};Object.assign(o,n)}return o}function J(...t){for(let o of t)if(o instanceof Error)return o}var O={debug:!1,info:!1,warn:!1,error:!0,fatal:!0};function U(t,o,n,e,c){let a=`"${o.messageKey}"`;return(...i)=>{if(i.length===1&&typeof i[0]==="string"&&i[0].charCodeAt(0)===123&&i[0].includes(a)){l(i[0],O[t]);return}if(m[t]<n)return;let L=G(...i);if(e&&!e(t,L))return;let R=A(...i),f=J(...i),g={level:t,message:L,timestamp:new Date().toISOString(),context:R||{},error:f?F(f):void 0,trace:c?.()},s=o.format(g);if(g.error)p(s,g.error);l(JSON.stringify(s),O[t])}}var S="__jsonlLoggerIntercepted";function K(t){if(globalThis[S])return;globalThis[S]=!0;let o=t?.formatter??u,n=m[t?.level??"debug"],e=t?.filter,c=t?.traceContext,a=[["log","info"],["info","info"],["warn","warn"],["error","error"],["debug","debug"]];for(let[i,L]of a)console[i]=U(L,o,n,e,c)}export{D as originalConsole,K as intercept};
|
package/dist/preload.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
var N={debug:"DEBUG",info:"INFO",warn:"WARNING",error:"ERROR",fatal:"CRITICAL"},
|
|
2
|
-
`);else if(C==="deno"&&
|
|
3
|
-
`);if(
|
|
4
|
-
${
|
|
5
|
-
Caused by: ${
|
|
6
|
-
${
|
|
7
|
-
Caused by: ${
|
|
1
|
+
var N={debug:"DEBUG",info:"INFO",warn:"WARNING",error:"ERROR",fatal:"CRITICAL"},g={messageKey:"message",format(t){let o={message:t.message,timestamp:t.timestamp,severity:N[t.level],...t.context};if(t.trace){if(o["logging.googleapis.com/trace"]=t.trace.traceId,o["logging.googleapis.com/spanId"]=t.trace.spanId,t.trace.traceFlags!==void 0)o["logging.googleapis.com/trace_sampled"]=(t.trace.traceFlags&1)===1}return o}};var x={messageKey:"_msg",format(t){let o={_msg:t.message,_time:t.timestamp,level:t.level,...t.context};if(t.trace){if(o.trace_id=t.trace.traceId,o.span_id=t.trace.spanId,t.trace.traceFlags!==void 0)o.trace_flags=t.trace.traceFlags}return o}};var l=process.env.LOG_FORMAT,d=!!l,f={debug:0,info:1,warn:2,error:3,fatal:4},S=/\x1b\[[0-9;]*m/g;function r(t){return t.replace(S,"")}function u(t,o,n="error"){if(t[`${n}.name`]=o.name,t[`${n}.message`]=o.message,o.stack)t[`${n}.stack`]=o.stack;if(o.cause)u(t,o.cause,`${n}.cause`)}var C=typeof process<"u"&&process.stdout&&typeof process.stdout.write==="function"?"node":typeof Deno<"u"&&Deno.stdout?"deno":"browser",I=C==="deno"?new TextEncoder:null;function h(t,o){if(C==="node")(o?process.stderr??process.stdout:process.stdout).write(`${t}
|
|
2
|
+
`);else if(C==="deno"&&I){let n=I.encode(`${t}
|
|
3
|
+
`);if(o)Deno.stderr.writeSync(n);else Deno.stdout.writeSync(n)}else if(o)console.error(t);else console.log(t)}var _={"google-cloud-logging":g,"victoria-logs":x},j=l&&_[l]||g,v=d,y=process.env.LOG_LEVEL||(v?"info":"debug"),G={debug:!1,info:!1,warn:!1,error:!0,fatal:!0};function k(t,o){return o.add(t),{name:t.name,message:t.message,stack:t.stack,...t.cause instanceof Error&&!o.has(t.cause)?{cause:k(t.cause,o)}:{}}}function b(t){return k(t,new WeakSet)}class w{ctx;min;json;fmt;tc;constructor(t,o){this.ctx=t||{},this.json=o?.json??v,this.fmt=o?.formatter??j,this.tc=o?.traceContext;let n=o?.level??y;this.min=f[n]??f.info}child(t){let o=new w({...this.ctx,...t},{json:this.json,formatter:this.fmt,traceContext:this.tc});return o.min=this.min,o}log(t,o,n,e){if(f[t]<this.min)return;let i={level:t,message:this.json?r(o).trim():o,timestamp:new Date().toISOString(),context:n?{...this.ctx,...n}:this.ctx};if(this.tc)i.trace=this.tc();if(e)i.error=b(e);if(this.json){let a=this.fmt.format(i);if(i.error)u(a,i.error);h(JSON.stringify(a),G[t])}else this.logPlain(t,i)}logPlain(t,o){let n={debug:"\x1B[36m",info:"\x1B[32m",warn:"\x1B[33m",error:"\x1B[31m",fatal:"\x1B[35m"},e="\x1B[0m",i=n[t],a=new Date(o.timestamp).toLocaleTimeString("en-US",{hour12:!1}),c=t.toUpperCase().padEnd(5),L=o.context,R=Object.keys(L).length>0?` ${JSON.stringify(L)}`:"",p="";if(o.error){let s=o.error,F=!0;while(s){if(s.stack)p+=F?`
|
|
4
|
+
${s.stack}`:`
|
|
5
|
+
Caused by: ${s.stack}`;else p+=F?`
|
|
6
|
+
${s.name}: ${s.message}`:`
|
|
7
|
+
Caused by: ${s.name}: ${s.message}`;s=s.cause,F=!1}}let m=`${i}${a} ${c}\x1B[0m ${o.message}${R}${p}`;switch(t){case"debug":console.debug(m);break;case"warn":console.warn(m);break;case"error":case"fatal":console.error(m);break;default:console.log(m)}}debug(t,o){this.log("debug",t,o)}info(t,o){this.log("info",t,o)}warn(t,o){this.log("warn",t,o)}error(t,o,n){this.log("error",t,o,n)}fatal(t,o,n){this.log("fatal",t,o,n)}}var P=new w;var K={log:console.log.bind(console),info:console.info.bind(console),warn:console.warn.bind(console),error:console.error.bind(console),debug:console.debug.bind(console)};function T(...t){let o="";for(let n=0;n<t.length;n++){if(n>0)o+=" ";let e=t[n];if(typeof e==="string")o+=r(e);else if(e instanceof Error)o+=e.message;else try{o+=JSON.stringify(e)}catch{o+=String(e)}}return o.trim()}function V(...t){let o;for(let n of t)if(typeof n==="object"&&n!==null&&!(n instanceof Error)&&!Array.isArray(n)){if(!o)o={};Object.assign(o,n)}return o}function A(...t){for(let o of t)if(o instanceof Error)return o}var $={debug:!1,info:!1,warn:!1,error:!0,fatal:!0};function J(t,o,n,e,i){let a=`"${o.messageKey}"`;return(...c)=>{if(c.length===1&&typeof c[0]==="string"&&c[0].charCodeAt(0)===123&&c[0].includes(a)){h(c[0],$[t]);return}if(f[t]<n)return;let L=T(...c);if(e&&!e(t,L))return;let R=V(...c),p=A(...c),m={level:t,message:L,timestamp:new Date().toISOString(),context:R||{},error:p?b(p):void 0,trace:i?.()},s=o.format(m);if(m.error)u(s,m.error);h(JSON.stringify(s),$[t])}}var O="__jsonlLoggerIntercepted";function E(t){if(globalThis[O])return;globalThis[O]=!0;let o=t?.formatter??g,n=f[t?.level??"debug"],e=t?.filter,i=t?.traceContext,a=[["log","info"],["info","info"],["warn","warn"],["error","error"],["debug","debug"]];for(let[c,L]of a)console[c]=J(L,o,n,e,i)}if(l){let o={"google-cloud-logging":g,"victoria-logs":x}[l]??g,n=process.env.LOG_LEVEL||"info";E({formatter:o,level:n})}
|
package/dist/types.d.ts
CHANGED
|
@@ -6,12 +6,18 @@ export type ErrorInfo = {
|
|
|
6
6
|
stack?: string;
|
|
7
7
|
cause?: ErrorInfo;
|
|
8
8
|
};
|
|
9
|
+
export type TraceContext = {
|
|
10
|
+
traceId: string;
|
|
11
|
+
spanId: string;
|
|
12
|
+
traceFlags?: number;
|
|
13
|
+
};
|
|
9
14
|
export type LogRecord = {
|
|
10
15
|
level: LogLevel;
|
|
11
16
|
message: string;
|
|
12
17
|
timestamp: string;
|
|
13
18
|
context: LogContext;
|
|
14
19
|
error?: ErrorInfo;
|
|
20
|
+
trace?: TraceContext;
|
|
15
21
|
};
|
|
16
22
|
export type Formatter = {
|
|
17
23
|
format: (record: LogRecord) => Record<string, unknown>;
|
|
@@ -21,6 +27,7 @@ export type LoggerOptions = {
|
|
|
21
27
|
formatter?: Formatter;
|
|
22
28
|
json?: boolean;
|
|
23
29
|
level?: LogLevel;
|
|
30
|
+
traceContext?: () => TraceContext | undefined;
|
|
24
31
|
};
|
|
25
32
|
export type FormatterName = 'google-cloud-logging' | 'victoria-logs';
|
|
26
33
|
export declare const defaultFormat: FormatterName | undefined;
|
|
@@ -29,6 +36,7 @@ export type InterceptOptions = {
|
|
|
29
36
|
formatter?: Formatter;
|
|
30
37
|
filter?: (level: LogLevel, message: string) => boolean;
|
|
31
38
|
level?: LogLevel;
|
|
39
|
+
traceContext?: () => TraceContext | undefined;
|
|
32
40
|
};
|
|
33
41
|
export declare const logLevelValues: Record<LogLevel, number>;
|
|
34
42
|
export declare function stripAnsi(str: string): string;
|
package/dist/victoria-logs.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var a={messageKey:"_msg",format(t){let e={_msg:t.message,_time:t.timestamp,level:t.level,...t.context};if(t.trace){if(e.trace_id=t.trace.traceId,e.span_id=t.trace.spanId,t.trace.traceFlags!==void 0)e.trace_flags=t.trace.traceFlags}return e}};export{a as VictoriaLogs};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jsonl-logger",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Lightweight ESM-only JSON Lines logger with pluggable formatters for Google Cloud Logging, VictoriaLogs, and more",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"test": "bun test"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
|
-
"@biomejs/biome": "2.4.
|
|
52
|
+
"@biomejs/biome": "2.4.3",
|
|
53
53
|
"@types/bun": "1.3.9",
|
|
54
54
|
"typescript": "5.9.3"
|
|
55
55
|
},
|
|
@@ -17,6 +17,14 @@ export const GoogleCloudLogging: Formatter = {
|
|
|
17
17
|
severity: severityMap[record.level],
|
|
18
18
|
...record.context,
|
|
19
19
|
}
|
|
20
|
+
if (record.trace) {
|
|
21
|
+
entry['logging.googleapis.com/trace'] = record.trace.traceId
|
|
22
|
+
entry['logging.googleapis.com/spanId'] = record.trace.spanId
|
|
23
|
+
if (record.trace.traceFlags !== undefined) {
|
|
24
|
+
entry['logging.googleapis.com/trace_sampled'] =
|
|
25
|
+
(record.trace.traceFlags & 1) === 1
|
|
26
|
+
}
|
|
27
|
+
}
|
|
20
28
|
return entry
|
|
21
29
|
},
|
|
22
30
|
}
|
package/src/index.ts
CHANGED
|
@@ -7,6 +7,7 @@ import type {
|
|
|
7
7
|
LoggerOptions,
|
|
8
8
|
LogLevel,
|
|
9
9
|
LogRecord,
|
|
10
|
+
TraceContext,
|
|
10
11
|
} from './types'
|
|
11
12
|
import {
|
|
12
13
|
defaultFormat,
|
|
@@ -27,6 +28,7 @@ export type {
|
|
|
27
28
|
LoggerOptions,
|
|
28
29
|
LogLevel,
|
|
29
30
|
LogRecord,
|
|
31
|
+
TraceContext,
|
|
30
32
|
} from './types'
|
|
31
33
|
export { logLevelValues, stripAnsi } from './types'
|
|
32
34
|
|
|
@@ -71,11 +73,13 @@ export class Logger {
|
|
|
71
73
|
private min: number
|
|
72
74
|
private json: boolean
|
|
73
75
|
private fmt: Formatter
|
|
76
|
+
private tc?: () => TraceContext | undefined
|
|
74
77
|
|
|
75
78
|
constructor(context?: LogContext, options?: LoggerOptions) {
|
|
76
79
|
this.ctx = context || {}
|
|
77
80
|
this.json = options?.json ?? defaultJson
|
|
78
81
|
this.fmt = options?.formatter ?? defaultFormatter
|
|
82
|
+
this.tc = options?.traceContext
|
|
79
83
|
const level: LogLevel = options?.level ?? defaultLevel
|
|
80
84
|
this.min = logLevelValues[level] ?? logLevelValues.info
|
|
81
85
|
}
|
|
@@ -86,6 +90,7 @@ export class Logger {
|
|
|
86
90
|
{
|
|
87
91
|
json: this.json,
|
|
88
92
|
formatter: this.fmt,
|
|
93
|
+
traceContext: this.tc,
|
|
89
94
|
},
|
|
90
95
|
)
|
|
91
96
|
child.min = this.min
|
|
@@ -107,6 +112,10 @@ export class Logger {
|
|
|
107
112
|
context: meta ? { ...this.ctx, ...meta } : this.ctx,
|
|
108
113
|
}
|
|
109
114
|
|
|
115
|
+
if (this.tc) {
|
|
116
|
+
record.trace = this.tc()
|
|
117
|
+
}
|
|
118
|
+
|
|
110
119
|
if (err) {
|
|
111
120
|
record.error = errorInfo(err)
|
|
112
121
|
}
|
|
@@ -145,7 +154,9 @@ export class Logger {
|
|
|
145
154
|
let isRoot = true
|
|
146
155
|
while (current) {
|
|
147
156
|
if (current.stack) {
|
|
148
|
-
errStr += isRoot
|
|
157
|
+
errStr += isRoot
|
|
158
|
+
? `\n${current.stack}`
|
|
159
|
+
: `\nCaused by: ${current.stack}`
|
|
149
160
|
} else {
|
|
150
161
|
errStr += isRoot
|
|
151
162
|
? `\n ${current.name}: ${current.message}`
|
package/src/intercept.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { GoogleCloudLogging } from './google-cloud-logging'
|
|
2
2
|
import { errorInfo } from './index'
|
|
3
|
-
import type {
|
|
3
|
+
import type {
|
|
4
|
+
Formatter,
|
|
5
|
+
InterceptOptions,
|
|
6
|
+
LogLevel,
|
|
7
|
+
TraceContext,
|
|
8
|
+
} from './types'
|
|
4
9
|
import { flattenError, logLevelValues, stripAnsi, write } from './types'
|
|
5
10
|
|
|
6
11
|
type ConsoleMethods = {
|
|
@@ -75,6 +80,7 @@ function createOverride(
|
|
|
75
80
|
formatter: Formatter,
|
|
76
81
|
minLevel: number,
|
|
77
82
|
filter?: (level: LogLevel, message: string) => boolean,
|
|
83
|
+
traceContext?: () => TraceContext | undefined,
|
|
78
84
|
): (...args: unknown[]) => void {
|
|
79
85
|
const msgKey = `"${formatter.messageKey}"`
|
|
80
86
|
|
|
@@ -105,6 +111,7 @@ function createOverride(
|
|
|
105
111
|
timestamp: new Date().toISOString(),
|
|
106
112
|
context: meta || {},
|
|
107
113
|
error: error ? errorInfo(error) : undefined,
|
|
114
|
+
trace: traceContext?.(),
|
|
108
115
|
}
|
|
109
116
|
|
|
110
117
|
const formatted = formatter.format(record)
|
|
@@ -122,6 +129,7 @@ export function intercept(options?: InterceptOptions): void {
|
|
|
122
129
|
const formatter = options?.formatter ?? GoogleCloudLogging
|
|
123
130
|
const minLevel = logLevelValues[options?.level ?? 'debug']
|
|
124
131
|
const filter = options?.filter
|
|
132
|
+
const traceContext = options?.traceContext
|
|
125
133
|
|
|
126
134
|
const methodMap: [keyof ConsoleMethods, LogLevel][] = [
|
|
127
135
|
['log', 'info'],
|
|
@@ -132,6 +140,12 @@ export function intercept(options?: InterceptOptions): void {
|
|
|
132
140
|
]
|
|
133
141
|
|
|
134
142
|
for (const [method, level] of methodMap) {
|
|
135
|
-
console[method] = createOverride(
|
|
143
|
+
console[method] = createOverride(
|
|
144
|
+
level,
|
|
145
|
+
formatter,
|
|
146
|
+
minLevel,
|
|
147
|
+
filter,
|
|
148
|
+
traceContext,
|
|
149
|
+
)
|
|
136
150
|
}
|
|
137
151
|
}
|
package/src/types.ts
CHANGED
|
@@ -9,12 +9,19 @@ export type ErrorInfo = {
|
|
|
9
9
|
cause?: ErrorInfo
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
+
export type TraceContext = {
|
|
13
|
+
traceId: string
|
|
14
|
+
spanId: string
|
|
15
|
+
traceFlags?: number
|
|
16
|
+
}
|
|
17
|
+
|
|
12
18
|
export type LogRecord = {
|
|
13
19
|
level: LogLevel
|
|
14
20
|
message: string
|
|
15
21
|
timestamp: string
|
|
16
22
|
context: LogContext
|
|
17
23
|
error?: ErrorInfo
|
|
24
|
+
trace?: TraceContext
|
|
18
25
|
}
|
|
19
26
|
|
|
20
27
|
export type Formatter = {
|
|
@@ -26,6 +33,7 @@ export type LoggerOptions = {
|
|
|
26
33
|
formatter?: Formatter
|
|
27
34
|
json?: boolean
|
|
28
35
|
level?: LogLevel
|
|
36
|
+
traceContext?: () => TraceContext | undefined
|
|
29
37
|
}
|
|
30
38
|
|
|
31
39
|
export type FormatterName = 'google-cloud-logging' | 'victoria-logs'
|
|
@@ -37,6 +45,7 @@ export type InterceptOptions = {
|
|
|
37
45
|
formatter?: Formatter
|
|
38
46
|
filter?: (level: LogLevel, message: string) => boolean
|
|
39
47
|
level?: LogLevel
|
|
48
|
+
traceContext?: () => TraceContext | undefined
|
|
40
49
|
}
|
|
41
50
|
|
|
42
51
|
export const logLevelValues: Record<LogLevel, number> = {
|
package/src/victoria-logs.ts
CHANGED
|
@@ -9,6 +9,13 @@ export const VictoriaLogs: Formatter = {
|
|
|
9
9
|
level: record.level,
|
|
10
10
|
...record.context,
|
|
11
11
|
}
|
|
12
|
+
if (record.trace) {
|
|
13
|
+
entry.trace_id = record.trace.traceId
|
|
14
|
+
entry.span_id = record.trace.spanId
|
|
15
|
+
if (record.trace.traceFlags !== undefined) {
|
|
16
|
+
entry.trace_flags = record.trace.traceFlags
|
|
17
|
+
}
|
|
18
|
+
}
|
|
12
19
|
return entry
|
|
13
20
|
},
|
|
14
21
|
}
|