@lssm/lib.logger 0.0.0-canary-20251217062943 → 0.0.0-canary-20251217072406

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.
@@ -1 +1,88 @@
1
- import"zone.js";const e=globalThis.Zone,t=`__lssm_log_context_data__`;function n(){if(e)return e.current.get(t)}var r=class r{static instance;static fallbackCounter=0;static getInstance(){return r.instance||=new r,r.instance}run(n,r){let i={context:{...n},trace:this.getCurrentTrace()};return e?e.current.fork({name:`log-context`,properties:{[t]:i}}).run(r):r()}extend(e,t){let n={...this.getContext(),...e};return this.run(n,t)}set(e,t){let r=n();r&&(r.context[e]=t)}get(e){return n()?.context?.[e]}getContext(){return n()?.context||{}}setTrace(e){let t=n();t&&(t.trace=e)}getCurrentTrace(){return n()?.trace}generateId(){return typeof crypto<`u`&&typeof crypto.randomUUID==`function`?crypto.randomUUID():(r.fallbackCounter+=1,`log-${r.fallbackCounter}`)}};export{r as LogContext};
1
+ import "zone.js";
2
+
3
+ //#region src/context.browser.ts
4
+ const ZONE = globalThis.Zone;
5
+ const STORE_KEY = "__lssm_log_context_data__";
6
+ function getStore() {
7
+ if (!ZONE) return void 0;
8
+ return ZONE.current.get(STORE_KEY);
9
+ }
10
+ /**
11
+ * Browser implementation of LogContext using Zone.js for async context
12
+ * propagation (similar to AsyncLocalStorage in Node).
13
+ */
14
+ var LogContext = class LogContext {
15
+ static instance;
16
+ static fallbackCounter = 0;
17
+ static getInstance() {
18
+ if (!LogContext.instance) LogContext.instance = new LogContext();
19
+ return LogContext.instance;
20
+ }
21
+ /**
22
+ * Run a function with a new context
23
+ */
24
+ run(context, fn) {
25
+ const contextData = {
26
+ context: { ...context },
27
+ trace: this.getCurrentTrace()
28
+ };
29
+ if (!ZONE) return fn();
30
+ return ZONE.current.fork({
31
+ name: "log-context",
32
+ properties: { [STORE_KEY]: contextData }
33
+ }).run(fn);
34
+ }
35
+ /**
36
+ * Run a function with an extended context (merges with current)
37
+ */
38
+ extend(additionalContext, fn) {
39
+ const mergedContext = {
40
+ ...this.getContext(),
41
+ ...additionalContext
42
+ };
43
+ return this.run(mergedContext, fn);
44
+ }
45
+ /**
46
+ * Set context data for the current execution context
47
+ */
48
+ set(key, value) {
49
+ const current = getStore();
50
+ if (current) current.context[key] = value;
51
+ }
52
+ /**
53
+ * Get a specific context value
54
+ */
55
+ get(key) {
56
+ return getStore()?.context?.[key];
57
+ }
58
+ /**
59
+ * Get all context data
60
+ */
61
+ getContext() {
62
+ return getStore()?.context || {};
63
+ }
64
+ /**
65
+ * Set trace context
66
+ */
67
+ setTrace(trace) {
68
+ const current = getStore();
69
+ if (current) current.trace = trace;
70
+ }
71
+ /**
72
+ * Get current trace context
73
+ */
74
+ getCurrentTrace() {
75
+ return getStore()?.trace;
76
+ }
77
+ /**
78
+ * Generate a unique ID for requests/operations
79
+ */
80
+ generateId() {
81
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") return crypto.randomUUID();
82
+ LogContext.fallbackCounter += 1;
83
+ return `log-${LogContext.fallbackCounter}`;
84
+ }
85
+ };
86
+
87
+ //#endregion
88
+ export { LogContext };
package/dist/context.mjs CHANGED
@@ -1 +1 @@
1
- export{};
1
+ export { };
@@ -1 +1,78 @@
1
- import{AsyncLocalStorage as e}from"node:async_hooks";var t=class t{static instance;storage;constructor(){this.storage=new e}static getInstance(){return t.instance||=new t,t.instance}run(e,t){let n={context:{...e},trace:this.getCurrentTrace()};return this.storage.run(n,t)}extend(e,t){let n={...this.getContext(),...e};return this.run(n,t)}set(e,t){let n=this.storage.getStore();n&&(n.context[e]=t)}get(e){return this.storage.getStore()?.context?.[e]}getContext(){return this.storage.getStore()?.context||{}}setTrace(e){let t=this.storage.getStore();t&&(t.trace=e)}getCurrentTrace(){return this.storage.getStore()?.trace}generateId(){return crypto.randomUUID()}};export{t as LogContext};
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+
3
+ //#region src/context.node.ts
4
+ /**
5
+ * Node.js implementation of LogContext using AsyncLocalStorage.
6
+ */
7
+ var LogContext = class LogContext {
8
+ static instance;
9
+ storage;
10
+ constructor() {
11
+ this.storage = new AsyncLocalStorage();
12
+ }
13
+ static getInstance() {
14
+ if (!LogContext.instance) LogContext.instance = new LogContext();
15
+ return LogContext.instance;
16
+ }
17
+ /**
18
+ * Run a function with a new context
19
+ */
20
+ run(context, fn) {
21
+ const contextData = {
22
+ context: { ...context },
23
+ trace: this.getCurrentTrace()
24
+ };
25
+ return this.storage.run(contextData, fn);
26
+ }
27
+ /**
28
+ * Run a function with an extended context (merges with current)
29
+ */
30
+ extend(additionalContext, fn) {
31
+ const mergedContext = {
32
+ ...this.getContext(),
33
+ ...additionalContext
34
+ };
35
+ return this.run(mergedContext, fn);
36
+ }
37
+ /**
38
+ * Set context data for the current execution context
39
+ */
40
+ set(key, value) {
41
+ const current = this.storage.getStore();
42
+ if (current) current.context[key] = value;
43
+ }
44
+ /**
45
+ * Get a specific context value
46
+ */
47
+ get(key) {
48
+ return this.storage.getStore()?.context?.[key];
49
+ }
50
+ /**
51
+ * Get all context data
52
+ */
53
+ getContext() {
54
+ return this.storage.getStore()?.context || {};
55
+ }
56
+ /**
57
+ * Set trace context
58
+ */
59
+ setTrace(trace) {
60
+ const current = this.storage.getStore();
61
+ if (current) current.trace = trace;
62
+ }
63
+ /**
64
+ * Get current trace context
65
+ */
66
+ getCurrentTrace() {
67
+ return this.storage.getStore()?.trace;
68
+ }
69
+ /**
70
+ * Generate a unique ID for requests/operations
71
+ */
72
+ generateId() {
73
+ return crypto.randomUUID();
74
+ }
75
+ };
76
+
77
+ //#endregion
78
+ export { LogContext };
@@ -1 +1,84 @@
1
- import{LogContext as e}from"./context.node.mjs";import{Logger as t}from"./logger.node.mjs";import{Elysia as n}from"elysia";function r(n={}){let{logger:r=new t,logRequests:i=!0,logResponses:a=!0,excludePaths:o=[`/health`,`/metrics`]}=n,s=e.getInstance();return function(e){return e.derive(e=>{let{request:t,path:n}=e;if(o.some(e=>n.startsWith(e)))return{logger:r};let a=new URL(t.url),c={requestId:s.generateId(),method:t.method,url:t.url,path:a.pathname,userAgent:t.headers.get(`user-agent`)||void 0,timestamp:new Date().toISOString()},l=performance.now();return s.run(c,()=>{i&&r.info(`→ ${t.method} ${n}`,{method:t.method,path:n,userAgent:c.userAgent,requestId:c.requestId})}),{logger:r,requestContext:c,startTime:l}}).onAfterHandle(e=>{let{request:t,startTime:n,requestContext:r,logger:i}=e;if(!n||!r)return;let o=performance.now()-n,s=new URL(t.url).pathname;a&&i.info(`← 200 ${t.method} ${s}`,{method:t.method,path:s,duration:`${o.toFixed(2)}ms`,requestId:r.requestId})}).onError(e=>{let{request:t,error:n,code:r,startTime:i,requestContext:a,logger:o}=e;if(!i||!a)return;let s=performance.now()-i,c=new URL(t.url).pathname;o?.error(`✖ ${r} ${t.method} ${c}`,{method:t.method,path:c,error:n?.toString?.()||`Unknown error`,code:r,duration:`${s.toFixed(2)}ms`,requestId:a.requestId})}).derive(()=>({logInfo:(e,t)=>{r.info(e,t)},logError:(e,t,n)=>{r.error(e,n,t)},traceOperation:async(e,t)=>r.trace({operationType:`custom`,operationName:e,autoTiming:!0},t)}))}}const i=r;export{i as createElysiaLogger,r as elysiaLogger};
1
+ import { LogContext } from "./context.node.mjs";
2
+ import { Logger } from "./logger.node.mjs";
3
+ import { Elysia } from "elysia";
4
+
5
+ //#region src/elysia-plugin.ts
6
+ /**
7
+ * Simple ElysiaJS Logger Plugin
8
+ * Provides automatic request logging and tracing
9
+ */
10
+ function elysiaLogger(config = {}) {
11
+ const { logger = new Logger(), logRequests = true, logResponses = true, excludePaths = ["/health", "/metrics"] } = config;
12
+ const context = LogContext.getInstance();
13
+ return function(app) {
14
+ return app.derive((ctx) => {
15
+ const { request, path } = ctx;
16
+ if (excludePaths.some((excludePath) => path.startsWith(excludePath))) return { logger };
17
+ const url = new URL(request.url);
18
+ const requestContext = {
19
+ requestId: context.generateId(),
20
+ method: request.method,
21
+ url: request.url,
22
+ path: url.pathname,
23
+ userAgent: request.headers.get("user-agent") || void 0,
24
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
25
+ };
26
+ const startTime = performance.now();
27
+ context.run(requestContext, () => {
28
+ if (logRequests) logger.info(`→ ${request.method} ${path}`, {
29
+ method: request.method,
30
+ path,
31
+ userAgent: requestContext.userAgent,
32
+ requestId: requestContext.requestId
33
+ });
34
+ });
35
+ return {
36
+ logger,
37
+ requestContext,
38
+ startTime
39
+ };
40
+ }).onAfterHandle((ctx) => {
41
+ const { request, startTime, requestContext, logger: logger$1 } = ctx;
42
+ if (!startTime || !requestContext) return;
43
+ const duration = performance.now() - startTime;
44
+ const path = new URL(request.url).pathname;
45
+ if (logResponses) logger$1.info(`← 200 ${request.method} ${path}`, {
46
+ method: request.method,
47
+ path,
48
+ duration: `${duration.toFixed(2)}ms`,
49
+ requestId: requestContext.requestId
50
+ });
51
+ }).onError((ctx) => {
52
+ const { request, error, code, startTime, requestContext, logger: logger$1 } = ctx;
53
+ if (!startTime || !requestContext) return;
54
+ const duration = performance.now() - startTime;
55
+ const path = new URL(request.url).pathname;
56
+ logger$1?.error(`✖ ${code} ${request.method} ${path}`, {
57
+ method: request.method,
58
+ path,
59
+ error: error?.toString?.() || "Unknown error",
60
+ code,
61
+ duration: `${duration.toFixed(2)}ms`,
62
+ requestId: requestContext.requestId
63
+ });
64
+ }).derive(() => ({
65
+ logInfo: (message, metadata) => {
66
+ logger.info(message, metadata);
67
+ },
68
+ logError: (message, error, metadata) => {
69
+ logger.error(message, metadata, error);
70
+ },
71
+ traceOperation: async (operationName, operation) => {
72
+ return logger.trace({
73
+ operationType: "custom",
74
+ operationName,
75
+ autoTiming: true
76
+ }, operation);
77
+ }
78
+ }));
79
+ };
80
+ }
81
+ const createElysiaLogger = elysiaLogger;
82
+
83
+ //#endregion
84
+ export { createElysiaLogger, elysiaLogger };
@@ -1,9 +1,179 @@
1
- import{LogLevel as e}from"./types.mjs";const t={reset:`\x1B[0m`,bright:`\x1B[1m`,dim:`\x1B[2m`,red:`\x1B[31m`,green:`\x1B[32m`,yellow:`\x1B[33m`,blue:`\x1B[34m`,magenta:`\x1B[35m`,cyan:`\x1B[36m`,white:`\x1B[37m`,gray:`\x1B[90m`,bgRed:`\x1B[41m`,bgYellow:`\x1B[43m`},n={[e.TRACE]:{color:t.gray,symbol:`○`,name:`TRACE`},[e.DEBUG]:{color:t.blue,symbol:`●`,name:`DEBUG`},[e.INFO]:{color:t.green,symbol:`●`,name:`INFO `},[e.WARN]:{color:t.yellow,symbol:`▲`,name:`WARN `},[e.ERROR]:{color:t.red,symbol:`✖`,name:`ERROR`},[e.FATAL]:{color:t.bgRed+t.white,symbol:`💀`,name:`FATAL`}};var r=class{enableColors;constructor(e=!0){this.enableColors=e}format(e){let r=[],i=n[e.level],a=this.formatTimestamp(e.timestamp);r.push(this.colorize(a,t.gray));let o=`${i.symbol} ${i.name}`;if(r.push(this.colorize(o,i.color)),e.traceId){let n=this.formatTraceInfo(e);r.push(this.colorize(n,t.cyan))}if(r.push(this.colorize(e.message,t.white)),e.duration!==void 0){let n=`(${this.formatDuration(e.duration)})`;r.push(this.colorize(n,t.magenta))}let s=r.join(` `);if(e.context&&Object.keys(e.context).length>0&&(s+=`
2
- `+this.formatContext(e.context)),e.metadata&&Object.keys(e.metadata).length>0&&(s+=`
3
- `+this.formatMetadata(e.metadata)),e.error&&(s+=`
4
- `+this.formatError(e.error)),e.tags&&e.tags.length>0){let n=e.tags.map(e=>`#${e}`).join(` `);s+=`
5
- `+this.colorize(`Tags: ${n}`,t.blue)}return s}formatTimestamp(e){return e.toISOString().substring(11,23)}formatTraceInfo(e){let t=[`trace:${e.traceId?.substring(0,8)||`unknown`}`];return e.spanId&&e.spanId.length>=8&&t.push(`span:${e.spanId.substring(0,8)}`),e.parentId&&e.parentId.length>=8&&t.push(`parent:${e.parentId.substring(0,8)}`),`[${t.join(`|`)}]`}formatDuration(e){return e<1?`${(e*1e3).toFixed(0)}μs`:e<1e3?`${e.toFixed(2)}ms`:`${(e/1e3).toFixed(2)}s`}formatContext(e){let n=this.formatObject(e,2);return this.colorize(`Context: ${n}`,t.cyan)}formatMetadata(e){let n=this.formatObject(e,2);return this.colorize(`Metadata: ${n}`,t.blue)}formatError(e){let n=this.colorize(`Error: ${e.name}: ${e.message}`,t.red);if(e.stack){let r=e.stack.split(`
6
- `).slice(1,6).map(e=>` ${e}`).join(`
7
- `);n+=`
8
- `+this.colorize(r,t.gray)}return n}formatObject(e,t=0){let n=` `.repeat(t),r=Object.entries(e);return r.length===0?`{}`:r[0]&&typeof r[0][1]!=`object`?`{ ${r[0][0]}: ${this.formatValue(r[0][1])} }`:`{\n${r.map(([e,r])=>`${n} ${e}: ${this.formatValue(r,t+2)}`).join(`
9
- `)}\n${n}}`}formatValue(e,t=0){return e===null?`null`:e===void 0?`undefined`:typeof e==`string`?`"${e}"`:typeof e==`boolean`||typeof e==`number`?String(e):e instanceof Date?e.toISOString():Array.isArray(e)?e.length===0?`[]`:`[${e.map(e=>this.formatValue(e)).join(`, `)}]`:typeof e==`object`?this.formatObject(e,t):String(e)}colorize(e,n){return this.enableColors?`${n}${e}${t.reset}`:e}},i=class{format(e){let t={timestamp:e.timestamp,level:e.level,message:e.message};return e.traceId&&(t.traceId=e.traceId),e.spanId&&(t.spanId=e.spanId),e.parentId&&(t.parentId=e.parentId),e.duration!==void 0&&(t.duration=e.duration),e.context&&Object.keys(e.context).length>0&&(t.context=e.context),e.metadata&&Object.keys(e.metadata).length>0&&(t.metadata=e.metadata),e.error&&(t.error={name:e.error.name,message:e.error.message,stack:e.error.stack}),e.tags&&e.tags.length>0&&(t.tags=e.tags),JSON.stringify(t)}},a=class{template;dateFormat;constructor(e=`{timestamp} [{level}] {message}`,t){this.template=e,this.dateFormat=t||(e=>e.toISOString())}format(t){let n=e[t.level],r=this.dateFormat(t.timestamp),i=this.template.replace(`{timestamp}`,r).replace(`{level}`,n).replace(`{message}`,t.message).replace(`{traceId}`,t.traceId||``).replace(`{spanId}`,t.spanId||``).replace(`{duration}`,t.duration?.toString()||``);return t.context&&(i=i.replace(`{context}`,JSON.stringify(t.context))),t.metadata&&(i=i.replace(`{metadata}`,JSON.stringify(t.metadata))),i}};export{a as CustomFormatter,r as DevFormatter,i as ProductionFormatter};
1
+ import { LogLevel } from "./types.mjs";
2
+
3
+ //#region src/formatters.ts
4
+ const colors = {
5
+ reset: "\x1B[0m",
6
+ bright: "\x1B[1m",
7
+ dim: "\x1B[2m",
8
+ red: "\x1B[31m",
9
+ green: "\x1B[32m",
10
+ yellow: "\x1B[33m",
11
+ blue: "\x1B[34m",
12
+ magenta: "\x1B[35m",
13
+ cyan: "\x1B[36m",
14
+ white: "\x1B[37m",
15
+ gray: "\x1B[90m",
16
+ bgRed: "\x1B[41m",
17
+ bgYellow: "\x1B[43m"
18
+ };
19
+ const levelConfig = {
20
+ [LogLevel.TRACE]: {
21
+ color: colors.gray,
22
+ symbol: "○",
23
+ name: "TRACE"
24
+ },
25
+ [LogLevel.DEBUG]: {
26
+ color: colors.blue,
27
+ symbol: "●",
28
+ name: "DEBUG"
29
+ },
30
+ [LogLevel.INFO]: {
31
+ color: colors.green,
32
+ symbol: "●",
33
+ name: "INFO "
34
+ },
35
+ [LogLevel.WARN]: {
36
+ color: colors.yellow,
37
+ symbol: "▲",
38
+ name: "WARN "
39
+ },
40
+ [LogLevel.ERROR]: {
41
+ color: colors.red,
42
+ symbol: "✖",
43
+ name: "ERROR"
44
+ },
45
+ [LogLevel.FATAL]: {
46
+ color: colors.bgRed + colors.white,
47
+ symbol: "💀",
48
+ name: "FATAL"
49
+ }
50
+ };
51
+ var DevFormatter = class {
52
+ enableColors;
53
+ constructor(enableColors = true) {
54
+ this.enableColors = enableColors;
55
+ }
56
+ format(entry) {
57
+ const parts = [];
58
+ const config = levelConfig[entry.level];
59
+ const timestamp = this.formatTimestamp(entry.timestamp);
60
+ parts.push(this.colorize(timestamp, colors.gray));
61
+ const levelText = `${config.symbol} ${config.name}`;
62
+ parts.push(this.colorize(levelText, config.color));
63
+ if (entry.traceId) {
64
+ const traceInfo = this.formatTraceInfo(entry);
65
+ parts.push(this.colorize(traceInfo, colors.cyan));
66
+ }
67
+ parts.push(this.colorize(entry.message, colors.white));
68
+ if (entry.duration !== void 0) {
69
+ const durationText = `(${this.formatDuration(entry.duration)})`;
70
+ parts.push(this.colorize(durationText, colors.magenta));
71
+ }
72
+ let output = parts.join(" ");
73
+ if (entry.context && Object.keys(entry.context).length > 0) output += "\n" + this.formatContext(entry.context);
74
+ if (entry.metadata && Object.keys(entry.metadata).length > 0) output += "\n" + this.formatMetadata(entry.metadata);
75
+ if (entry.error) output += "\n" + this.formatError(entry.error);
76
+ if (entry.tags && entry.tags.length > 0) {
77
+ const tagsText = entry.tags.map((tag) => `#${tag}`).join(" ");
78
+ output += "\n" + this.colorize(`Tags: ${tagsText}`, colors.blue);
79
+ }
80
+ return output;
81
+ }
82
+ formatTimestamp(timestamp) {
83
+ return timestamp.toISOString().substring(11, 23);
84
+ }
85
+ formatTraceInfo(entry) {
86
+ const parts = [`trace:${entry.traceId?.substring(0, 8) || "unknown"}`];
87
+ if (entry.spanId && entry.spanId.length >= 8) parts.push(`span:${entry.spanId.substring(0, 8)}`);
88
+ if (entry.parentId && entry.parentId.length >= 8) parts.push(`parent:${entry.parentId.substring(0, 8)}`);
89
+ return `[${parts.join("|")}]`;
90
+ }
91
+ formatDuration(duration) {
92
+ if (duration < 1) return `${(duration * 1e3).toFixed(0)}μs`;
93
+ else if (duration < 1e3) return `${duration.toFixed(2)}ms`;
94
+ else return `${(duration / 1e3).toFixed(2)}s`;
95
+ }
96
+ formatContext(context) {
97
+ const formatted = this.formatObject(context, 2);
98
+ return this.colorize(`Context: ${formatted}`, colors.cyan);
99
+ }
100
+ formatMetadata(metadata) {
101
+ const formatted = this.formatObject(metadata, 2);
102
+ return this.colorize(`Metadata: ${formatted}`, colors.blue);
103
+ }
104
+ formatError(error) {
105
+ let output = this.colorize(`Error: ${error.name}: ${error.message}`, colors.red);
106
+ if (error.stack) {
107
+ const indentedStack = error.stack.split("\n").slice(1, 6).map((line) => ` ${line}`).join("\n");
108
+ output += "\n" + this.colorize(indentedStack, colors.gray);
109
+ }
110
+ return output;
111
+ }
112
+ formatObject(obj, indent = 0) {
113
+ const spaces = " ".repeat(indent);
114
+ const entries = Object.entries(obj);
115
+ if (entries.length === 0) return "{}";
116
+ if (entries[0] && typeof entries[0][1] !== "object") return `{ ${entries[0][0]}: ${this.formatValue(entries[0][1])} }`;
117
+ return `{\n${entries.map(([key, value]) => {
118
+ return `${spaces} ${key}: ${this.formatValue(value, indent + 2)}`;
119
+ }).join("\n")}\n${spaces}}`;
120
+ }
121
+ formatValue(value, indent = 0) {
122
+ if (value === null) return "null";
123
+ if (value === void 0) return "undefined";
124
+ if (typeof value === "string") return `"${value}"`;
125
+ if (typeof value === "boolean" || typeof value === "number") return String(value);
126
+ if (value instanceof Date) return value.toISOString();
127
+ if (Array.isArray(value)) {
128
+ if (value.length === 0) return "[]";
129
+ return `[${value.map((v) => this.formatValue(v)).join(", ")}]`;
130
+ }
131
+ if (typeof value === "object") return this.formatObject(value, indent);
132
+ return String(value);
133
+ }
134
+ colorize(text, color) {
135
+ if (!this.enableColors) return text;
136
+ return `${color}${text}${colors.reset}`;
137
+ }
138
+ };
139
+ var ProductionFormatter = class {
140
+ format(entry) {
141
+ const logObject = {
142
+ timestamp: entry.timestamp,
143
+ level: entry.level,
144
+ message: entry.message
145
+ };
146
+ if (entry.traceId) logObject.traceId = entry.traceId;
147
+ if (entry.spanId) logObject.spanId = entry.spanId;
148
+ if (entry.parentId) logObject.parentId = entry.parentId;
149
+ if (entry.duration !== void 0) logObject.duration = entry.duration;
150
+ if (entry.context && Object.keys(entry.context).length > 0) logObject.context = entry.context;
151
+ if (entry.metadata && Object.keys(entry.metadata).length > 0) logObject.metadata = entry.metadata;
152
+ if (entry.error) logObject.error = {
153
+ name: entry.error.name,
154
+ message: entry.error.message,
155
+ stack: entry.error.stack
156
+ };
157
+ if (entry.tags && entry.tags.length > 0) logObject.tags = entry.tags;
158
+ return JSON.stringify(logObject);
159
+ }
160
+ };
161
+ var CustomFormatter = class {
162
+ template;
163
+ dateFormat;
164
+ constructor(template = "{timestamp} [{level}] {message}", dateFormat) {
165
+ this.template = template;
166
+ this.dateFormat = dateFormat || ((date) => date.toISOString());
167
+ }
168
+ format(entry) {
169
+ const levelName = LogLevel[entry.level];
170
+ const timestamp = this.dateFormat(entry.timestamp);
171
+ let formatted = this.template.replace("{timestamp}", timestamp).replace("{level}", levelName).replace("{message}", entry.message).replace("{traceId}", entry.traceId || "").replace("{spanId}", entry.spanId || "").replace("{duration}", entry.duration?.toString() || "");
172
+ if (entry.context) formatted = formatted.replace("{context}", JSON.stringify(entry.context));
173
+ if (entry.metadata) formatted = formatted.replace("{metadata}", JSON.stringify(entry.metadata));
174
+ return formatted;
175
+ }
176
+ };
177
+
178
+ //#endregion
179
+ export { CustomFormatter, DevFormatter, ProductionFormatter };
@@ -1 +1,8 @@
1
- import{LogContext as e}from"./context.browser.mjs";import{LogLevel as t}from"./types.mjs";import{Timer as n}from"./timer.mjs";import{DevFormatter as r,ProductionFormatter as i}from"./formatters.mjs";import{Tracer as a}from"./tracer.browser.mjs";import{Logger as o}from"./logger.browser.mjs";export{r as DevFormatter,e as LogContext,t as LogLevel,o as Logger,i as ProductionFormatter,n as Timer,a as Tracer};
1
+ import { LogContext } from "./context.browser.mjs";
2
+ import { LogLevel } from "./types.mjs";
3
+ import { Timer } from "./timer.mjs";
4
+ import { DevFormatter, ProductionFormatter } from "./formatters.mjs";
5
+ import { Tracer } from "./tracer.browser.mjs";
6
+ import { Logger } from "./logger.browser.mjs";
7
+
8
+ export { DevFormatter, LogContext, LogLevel, Logger, ProductionFormatter, Timer, Tracer };
package/dist/index.mjs CHANGED
@@ -1 +1,9 @@
1
- import{LogContext as e}from"./context.node.mjs";import{LogLevel as t}from"./types.mjs";import{Timer as n}from"./timer.mjs";import{Tracer as r}from"./tracer.node.mjs";import{DevFormatter as i,ProductionFormatter as a}from"./formatters.mjs";import{Logger as o}from"./logger.node.mjs";import{createElysiaLogger as s,elysiaLogger as c}from"./elysia-plugin.mjs";export{i as DevFormatter,e as LogContext,t as LogLevel,o as Logger,a as ProductionFormatter,n as Timer,r as Tracer,s as createElysiaLogger,c as elysiaLogger};
1
+ import { LogContext } from "./context.node.mjs";
2
+ import { LogLevel } from "./types.mjs";
3
+ import { Timer } from "./timer.mjs";
4
+ import { Tracer } from "./tracer.node.mjs";
5
+ import { DevFormatter, ProductionFormatter } from "./formatters.mjs";
6
+ import { Logger } from "./logger.node.mjs";
7
+ import { createElysiaLogger, elysiaLogger } from "./elysia-plugin.mjs";
8
+
9
+ export { DevFormatter, LogContext, LogLevel, Logger, ProductionFormatter, Timer, Tracer, createElysiaLogger, elysiaLogger };
@@ -1 +1,189 @@
1
- import{LogContext as e}from"./context.browser.mjs";import{LogLevel as t}from"./types.mjs";import{TimerManager as n}from"./timer.mjs";import{DevFormatter as r,ProductionFormatter as i}from"./formatters.mjs";import{Tracer as a}from"./tracer.browser.mjs";var o=class o{config;formatter;context;tracer;timerManager;constructor(o){this.config={level:t.INFO,environment:process.env.NODE_ENV||`development`,enableTracing:!0,enableTiming:!0,enableContext:!0,enableColors:!0,maxContextDepth:10,timestampFormat:`iso`,...o},this.context=e.getInstance(),this.tracer=new a,this.timerManager=new n,this.formatter=this.config.environment===`production`?new i:new r(this.config.enableColors)}traceLog(e,n){this.log(t.TRACE,e,n)}debug(e,n){this.log(t.DEBUG,e,n)}info(e,n){this.log(t.INFO,e,n)}warn(e,n){this.log(t.WARN,e,n)}error(e,n,r){this.log(t.ERROR,e,n,r)}fatal(e,n,r){this.log(t.FATAL,e,n,r)}withContext(e,t){return this.context.run(e,t)}extendContext(e,t){return this.context.extend(e,t)}setContext(e,t){this.context.set(e,t)}getContext(){return this.context.getContext()}trace=async(e,t)=>this.config.enableTracing?this.tracer.trace(e,t):await t();getTraceId(){return this.tracer.getCurrentTrace()?.traceId}startSpan(e){return this.config.enableTracing?this.tracer.startSpan(e):null}finishSpan(e){if(this.config.enableTracing)return this.tracer.finishSpan(e)}addTraceMetadata(e,t){this.config.enableTracing&&this.tracer.addMetadata(e,t)}addTraceTags(...e){this.config.enableTracing&&this.tracer.addTags(...e)}startTimer(e){return this.config.enableTiming?this.timerManager.start(e):null}stopTimer(e){if(this.config.enableTiming)return this.timerManager.stop(e)}getTimer(e){return this.timerManager.get(e)}child(e){let t=new o(this.config);return Object.entries(e).forEach(([e,n])=>{t.setContext(e,n)}),t}setLevel(e){this.config.level=e}setFormatter(e){this.formatter=e}async profile(e,n,r){let i=this.startTimer(`profile-${e}`),a=performance.now();try{let o=await this.tracer.trace({operationType:`custom`,operationName:`profile:${e}`,autoTiming:!0},n),s=performance.now()-a;return i?.stop(),r?.logLevel||t.DEBUG,this.log(t.DEBUG,`Profile: ${e} completed`,{operation:e,duration:`${s.toFixed(2)}ms`,result:r?.logResult?o:`[result hidden]`}),o}catch(t){let n=performance.now()-a;throw i?.stop(),this.error(`Profile: ${e} failed`,{operation:e,duration:`${n.toFixed(2)}ms`,error:t.message},t),t}}logRequest(e,t,n,r){let i=this.getHttpLogLevel(n),a=`${e.toUpperCase()} ${t}${n?` ${n}`:``}`;this.log(i,a,{method:e,url:t,statusCode:n,duration:r?`${r.toFixed(2)}ms`:void 0,type:`http_request`})}async flush(){this.timerManager.clear()}getStats(){return{activeTimers:this.timerManager.getActive().length,activeSpans:this.tracer.getActiveSpans().length,config:{...this.config}}}output(e,n){n>=t.ERROR?console.error(e):console.log(e)}log(e,t,n,r){if(e<this.config.level)return;let i=this.config.enableTracing?this.tracer.getCurrentTrace():void 0,a=this.config.enableContext?this.context.getContext():void 0,o={level:e,message:t,timestamp:new Date,traceId:i?.traceId,parentId:i?.parentId,spanId:i?.spanId,context:a,metadata:n,error:r,tags:i?.tags};i?.metadata?.duration&&(o.duration=i.metadata.duration);let s=this.formatter.format(o);this.output(s,e)}getHttpLogLevel(e){return e?e>=500?t.ERROR:e>=400?t.WARN:t.INFO:t.INFO}};export{o as Logger};
1
+ import { LogContext } from "./context.browser.mjs";
2
+ import { LogLevel } from "./types.mjs";
3
+ import { TimerManager } from "./timer.mjs";
4
+ import { DevFormatter, ProductionFormatter } from "./formatters.mjs";
5
+ import { Tracer } from "./tracer.browser.mjs";
6
+
7
+ //#region src/logger.browser.ts
8
+ var Logger = class Logger {
9
+ config;
10
+ formatter;
11
+ context;
12
+ tracer;
13
+ timerManager;
14
+ constructor(config) {
15
+ this.config = {
16
+ level: LogLevel.INFO,
17
+ environment: process.env.NODE_ENV || "development",
18
+ enableTracing: true,
19
+ enableTiming: true,
20
+ enableContext: true,
21
+ enableColors: true,
22
+ maxContextDepth: 10,
23
+ timestampFormat: "iso",
24
+ ...config
25
+ };
26
+ this.context = LogContext.getInstance();
27
+ this.tracer = new Tracer();
28
+ this.timerManager = new TimerManager();
29
+ this.formatter = this.config.environment === "production" ? new ProductionFormatter() : new DevFormatter(this.config.enableColors);
30
+ }
31
+ traceLog(message, metadata) {
32
+ this.log(LogLevel.TRACE, message, metadata);
33
+ }
34
+ debug(message, metadata) {
35
+ this.log(LogLevel.DEBUG, message, metadata);
36
+ }
37
+ info(message, metadata) {
38
+ this.log(LogLevel.INFO, message, metadata);
39
+ }
40
+ warn(message, metadata) {
41
+ this.log(LogLevel.WARN, message, metadata);
42
+ }
43
+ error(message, metadata, error) {
44
+ this.log(LogLevel.ERROR, message, metadata, error);
45
+ }
46
+ fatal(message, metadata, error) {
47
+ this.log(LogLevel.FATAL, message, metadata, error);
48
+ }
49
+ withContext(context, fn) {
50
+ return this.context.run(context, fn);
51
+ }
52
+ extendContext(additionalContext, fn) {
53
+ return this.context.extend(additionalContext, fn);
54
+ }
55
+ setContext(key, value) {
56
+ this.context.set(key, value);
57
+ }
58
+ getContext() {
59
+ return this.context.getContext();
60
+ }
61
+ trace = async (options, fn) => {
62
+ if (!this.config.enableTracing) return await fn();
63
+ return this.tracer.trace(options, fn);
64
+ };
65
+ getTraceId() {
66
+ return this.tracer.getCurrentTrace()?.traceId;
67
+ }
68
+ startSpan(options) {
69
+ if (!this.config.enableTracing) return null;
70
+ return this.tracer.startSpan(options);
71
+ }
72
+ finishSpan(spanId) {
73
+ if (!this.config.enableTracing) return;
74
+ return this.tracer.finishSpan(spanId);
75
+ }
76
+ addTraceMetadata(key, value) {
77
+ if (this.config.enableTracing) this.tracer.addMetadata(key, value);
78
+ }
79
+ addTraceTags(...tags) {
80
+ if (this.config.enableTracing) this.tracer.addTags(...tags);
81
+ }
82
+ startTimer(id) {
83
+ if (!this.config.enableTiming) return null;
84
+ return this.timerManager.start(id);
85
+ }
86
+ stopTimer(id) {
87
+ if (!this.config.enableTiming) return;
88
+ return this.timerManager.stop(id);
89
+ }
90
+ getTimer(id) {
91
+ return this.timerManager.get(id);
92
+ }
93
+ child(context) {
94
+ const childLogger = new Logger(this.config);
95
+ Object.entries(context).forEach(([key, value]) => {
96
+ childLogger.setContext(key, value);
97
+ });
98
+ return childLogger;
99
+ }
100
+ setLevel(level) {
101
+ this.config.level = level;
102
+ }
103
+ setFormatter(formatter) {
104
+ this.formatter = formatter;
105
+ }
106
+ async profile(operationName, fn, options) {
107
+ const timer = this.startTimer(`profile-${operationName}`);
108
+ const startTime = performance.now();
109
+ try {
110
+ const result = await this.tracer.trace({
111
+ operationType: "custom",
112
+ operationName: `profile:${operationName}`,
113
+ autoTiming: true
114
+ }, fn);
115
+ const duration = performance.now() - startTime;
116
+ timer?.stop();
117
+ options?.logLevel || LogLevel.DEBUG;
118
+ this.log(LogLevel.DEBUG, `Profile: ${operationName} completed`, {
119
+ operation: operationName,
120
+ duration: `${duration.toFixed(2)}ms`,
121
+ result: options?.logResult ? result : "[result hidden]"
122
+ });
123
+ return result;
124
+ } catch (error) {
125
+ const duration = performance.now() - startTime;
126
+ timer?.stop();
127
+ this.error(`Profile: ${operationName} failed`, {
128
+ operation: operationName,
129
+ duration: `${duration.toFixed(2)}ms`,
130
+ error: error.message
131
+ }, error);
132
+ throw error;
133
+ }
134
+ }
135
+ logRequest(method, url, statusCode, duration) {
136
+ const level = this.getHttpLogLevel(statusCode);
137
+ const message = `${method.toUpperCase()} ${url}${statusCode ? ` ${statusCode}` : ""}`;
138
+ this.log(level, message, {
139
+ method,
140
+ url,
141
+ statusCode,
142
+ duration: duration ? `${duration.toFixed(2)}ms` : void 0,
143
+ type: "http_request"
144
+ });
145
+ }
146
+ async flush() {
147
+ this.timerManager.clear();
148
+ }
149
+ getStats() {
150
+ return {
151
+ activeTimers: this.timerManager.getActive().length,
152
+ activeSpans: this.tracer.getActiveSpans().length,
153
+ config: { ...this.config }
154
+ };
155
+ }
156
+ output(message, level) {
157
+ if (level >= LogLevel.ERROR) console.error(message);
158
+ else console.log(message);
159
+ }
160
+ log(level, message, metadata, error) {
161
+ if (level < this.config.level) return;
162
+ const currentTrace = this.config.enableTracing ? this.tracer.getCurrentTrace() : void 0;
163
+ const contextData = this.config.enableContext ? this.context.getContext() : void 0;
164
+ const entry = {
165
+ level,
166
+ message,
167
+ timestamp: /* @__PURE__ */ new Date(),
168
+ traceId: currentTrace?.traceId,
169
+ parentId: currentTrace?.parentId,
170
+ spanId: currentTrace?.spanId,
171
+ context: contextData,
172
+ metadata,
173
+ error,
174
+ tags: currentTrace?.tags
175
+ };
176
+ if (currentTrace?.metadata?.duration) entry.duration = currentTrace.metadata.duration;
177
+ const formatted = this.formatter.format(entry);
178
+ this.output(formatted, level);
179
+ }
180
+ getHttpLogLevel(statusCode) {
181
+ if (!statusCode) return LogLevel.INFO;
182
+ if (statusCode >= 500) return LogLevel.ERROR;
183
+ if (statusCode >= 400) return LogLevel.WARN;
184
+ return LogLevel.INFO;
185
+ }
186
+ };
187
+
188
+ //#endregion
189
+ export { Logger };
package/dist/logger.mjs CHANGED
@@ -1 +1,3 @@
1
- import{Logger as e}from"./logger.node.mjs";export{e as Logger};
1
+ import { Logger } from "./logger.node.mjs";
2
+
3
+ export { Logger };
@@ -1 +1,189 @@
1
- import{LogContext as e}from"./context.node.mjs";import{LogLevel as t}from"./types.mjs";import{TimerManager as n}from"./timer.mjs";import{Tracer as r}from"./tracer.node.mjs";import{DevFormatter as i,ProductionFormatter as a}from"./formatters.mjs";var o=class o{config;formatter;context;tracer;timerManager;constructor(o){this.config={level:t.INFO,environment:process.env.NODE_ENV||`development`,enableTracing:!0,enableTiming:!0,enableContext:!0,enableColors:!0,maxContextDepth:10,timestampFormat:`iso`,...o},this.context=e.getInstance(),this.tracer=new r,this.timerManager=new n,this.formatter=this.config.environment===`production`?new a:new i(this.config.enableColors)}traceLog(e,n){this.log(t.TRACE,e,n)}debug(e,n){this.log(t.DEBUG,e,n)}info(e,n){this.log(t.INFO,e,n)}warn(e,n){this.log(t.WARN,e,n)}error(e,n,r){this.log(t.ERROR,e,n,r)}fatal(e,n,r){this.log(t.FATAL,e,n,r)}withContext(e,t){return this.context.run(e,t)}extendContext(e,t){return this.context.extend(e,t)}setContext(e,t){this.context.set(e,t)}getContext(){return this.context.getContext()}trace=async(e,t)=>this.config.enableTracing?this.tracer.trace(e,t):await t();getTraceId(){return this.tracer.getCurrentTrace()?.traceId}startSpan(e){return this.config.enableTracing?this.tracer.startSpan(e):null}finishSpan(e){if(this.config.enableTracing)return this.tracer.finishSpan(e)}addTraceMetadata(e,t){this.config.enableTracing&&this.tracer.addMetadata(e,t)}addTraceTags(...e){this.config.enableTracing&&this.tracer.addTags(...e)}startTimer(e){return this.config.enableTiming?this.timerManager.start(e):null}stopTimer(e){if(this.config.enableTiming)return this.timerManager.stop(e)}getTimer(e){return this.timerManager.get(e)}child(e){let t=new o(this.config);return Object.entries(e).forEach(([e,n])=>{t.setContext(e,n)}),t}setLevel(e){this.config.level=e}setFormatter(e){this.formatter=e}async profile(e,n,r){let i=this.startTimer(`profile-${e}`),a=performance.now();try{let o=await this.tracer.trace({operationType:`custom`,operationName:`profile:${e}`,autoTiming:!0},n),s=performance.now()-a;i?.stop();let c=r?.logLevel||t.DEBUG;return this.log(c,`Profile: ${e} completed`,{operation:e,duration:`${s.toFixed(2)}ms`,result:r?.logResult?o:`[result hidden]`}),o}catch(t){let n=performance.now()-a;throw i?.stop(),this.error(`Profile: ${e} failed`,{operation:e,duration:`${n.toFixed(2)}ms`,error:t.message},t),t}}logRequest(e,t,n,r){let i=this.getHttpLogLevel(n),a=`${e.toUpperCase()} ${t}${n?` ${n}`:``}`;this.log(i,a,{method:e,url:t,statusCode:n,duration:r?`${r.toFixed(2)}ms`:void 0,type:`http_request`})}async flush(){this.timerManager.clear()}getStats(){return{activeTimers:this.timerManager.getActive().length,activeSpans:this.tracer.getActiveSpans().length,config:{...this.config}}}output(e,n){n>=t.ERROR?console.error(e):console.log(e)}log(e,t,n,r){if(e<this.config.level)return;let i=this.config.enableTracing?this.tracer.getCurrentTrace():void 0,a=this.config.enableContext?this.context.getContext():void 0,o={level:e,message:t,timestamp:new Date,traceId:i?.traceId,parentId:i?.parentId,spanId:i?.spanId,context:a,metadata:n,error:r,tags:i?.tags};i?.metadata?.duration&&(o.duration=i.metadata.duration);let s=this.formatter.format(o);this.output(s,e)}getHttpLogLevel(e){return e?e>=500?t.ERROR:e>=400?t.WARN:t.INFO:t.INFO}};export{o as Logger};
1
+ import { LogContext } from "./context.node.mjs";
2
+ import { LogLevel } from "./types.mjs";
3
+ import { TimerManager } from "./timer.mjs";
4
+ import { Tracer } from "./tracer.node.mjs";
5
+ import { DevFormatter, ProductionFormatter } from "./formatters.mjs";
6
+
7
+ //#region src/logger.node.ts
8
+ var Logger = class Logger {
9
+ config;
10
+ formatter;
11
+ context;
12
+ tracer;
13
+ timerManager;
14
+ constructor(config) {
15
+ this.config = {
16
+ level: LogLevel.INFO,
17
+ environment: process.env.NODE_ENV || "development",
18
+ enableTracing: true,
19
+ enableTiming: true,
20
+ enableContext: true,
21
+ enableColors: true,
22
+ maxContextDepth: 10,
23
+ timestampFormat: "iso",
24
+ ...config
25
+ };
26
+ this.context = LogContext.getInstance();
27
+ this.tracer = new Tracer();
28
+ this.timerManager = new TimerManager();
29
+ this.formatter = this.config.environment === "production" ? new ProductionFormatter() : new DevFormatter(this.config.enableColors);
30
+ }
31
+ traceLog(message, metadata) {
32
+ this.log(LogLevel.TRACE, message, metadata);
33
+ }
34
+ debug(message, metadata) {
35
+ this.log(LogLevel.DEBUG, message, metadata);
36
+ }
37
+ info(message, metadata) {
38
+ this.log(LogLevel.INFO, message, metadata);
39
+ }
40
+ warn(message, metadata) {
41
+ this.log(LogLevel.WARN, message, metadata);
42
+ }
43
+ error(message, metadata, error) {
44
+ this.log(LogLevel.ERROR, message, metadata, error);
45
+ }
46
+ fatal(message, metadata, error) {
47
+ this.log(LogLevel.FATAL, message, metadata, error);
48
+ }
49
+ withContext(context, fn) {
50
+ return this.context.run(context, fn);
51
+ }
52
+ extendContext(additionalContext, fn) {
53
+ return this.context.extend(additionalContext, fn);
54
+ }
55
+ setContext(key, value) {
56
+ this.context.set(key, value);
57
+ }
58
+ getContext() {
59
+ return this.context.getContext();
60
+ }
61
+ trace = async (options, fn) => {
62
+ if (!this.config.enableTracing) return await fn();
63
+ return this.tracer.trace(options, fn);
64
+ };
65
+ getTraceId() {
66
+ return this.tracer.getCurrentTrace()?.traceId;
67
+ }
68
+ startSpan(options) {
69
+ if (!this.config.enableTracing) return null;
70
+ return this.tracer.startSpan(options);
71
+ }
72
+ finishSpan(spanId) {
73
+ if (!this.config.enableTracing) return;
74
+ return this.tracer.finishSpan(spanId);
75
+ }
76
+ addTraceMetadata(key, value) {
77
+ if (this.config.enableTracing) this.tracer.addMetadata(key, value);
78
+ }
79
+ addTraceTags(...tags) {
80
+ if (this.config.enableTracing) this.tracer.addTags(...tags);
81
+ }
82
+ startTimer(id) {
83
+ if (!this.config.enableTiming) return null;
84
+ return this.timerManager.start(id);
85
+ }
86
+ stopTimer(id) {
87
+ if (!this.config.enableTiming) return;
88
+ return this.timerManager.stop(id);
89
+ }
90
+ getTimer(id) {
91
+ return this.timerManager.get(id);
92
+ }
93
+ child(context) {
94
+ const childLogger = new Logger(this.config);
95
+ Object.entries(context).forEach(([key, value]) => {
96
+ childLogger.setContext(key, value);
97
+ });
98
+ return childLogger;
99
+ }
100
+ setLevel(level) {
101
+ this.config.level = level;
102
+ }
103
+ setFormatter(formatter) {
104
+ this.formatter = formatter;
105
+ }
106
+ async profile(operationName, fn, options) {
107
+ const timer = this.startTimer(`profile-${operationName}`);
108
+ const startTime = performance.now();
109
+ try {
110
+ const result = await this.tracer.trace({
111
+ operationType: "custom",
112
+ operationName: `profile:${operationName}`,
113
+ autoTiming: true
114
+ }, fn);
115
+ const duration = performance.now() - startTime;
116
+ timer?.stop();
117
+ const logLevel = options?.logLevel || LogLevel.DEBUG;
118
+ this.log(logLevel, `Profile: ${operationName} completed`, {
119
+ operation: operationName,
120
+ duration: `${duration.toFixed(2)}ms`,
121
+ result: options?.logResult ? result : "[result hidden]"
122
+ });
123
+ return result;
124
+ } catch (error) {
125
+ const duration = performance.now() - startTime;
126
+ timer?.stop();
127
+ this.error(`Profile: ${operationName} failed`, {
128
+ operation: operationName,
129
+ duration: `${duration.toFixed(2)}ms`,
130
+ error: error.message
131
+ }, error);
132
+ throw error;
133
+ }
134
+ }
135
+ logRequest(method, url, statusCode, duration) {
136
+ const level = this.getHttpLogLevel(statusCode);
137
+ const message = `${method.toUpperCase()} ${url}${statusCode ? ` ${statusCode}` : ""}`;
138
+ this.log(level, message, {
139
+ method,
140
+ url,
141
+ statusCode,
142
+ duration: duration ? `${duration.toFixed(2)}ms` : void 0,
143
+ type: "http_request"
144
+ });
145
+ }
146
+ async flush() {
147
+ this.timerManager.clear();
148
+ }
149
+ getStats() {
150
+ return {
151
+ activeTimers: this.timerManager.getActive().length,
152
+ activeSpans: this.tracer.getActiveSpans().length,
153
+ config: { ...this.config }
154
+ };
155
+ }
156
+ output(message, level) {
157
+ if (level >= LogLevel.ERROR) console.error(message);
158
+ else console.log(message);
159
+ }
160
+ log(level, message, metadata, error) {
161
+ if (level < this.config.level) return;
162
+ const currentTrace = this.config.enableTracing ? this.tracer.getCurrentTrace() : void 0;
163
+ const contextData = this.config.enableContext ? this.context.getContext() : void 0;
164
+ const entry = {
165
+ level,
166
+ message,
167
+ timestamp: /* @__PURE__ */ new Date(),
168
+ traceId: currentTrace?.traceId,
169
+ parentId: currentTrace?.parentId,
170
+ spanId: currentTrace?.spanId,
171
+ context: contextData,
172
+ metadata,
173
+ error,
174
+ tags: currentTrace?.tags
175
+ };
176
+ if (currentTrace?.metadata?.duration) entry.duration = currentTrace.metadata.duration;
177
+ const formatted = this.formatter.format(entry);
178
+ this.output(formatted, level);
179
+ }
180
+ getHttpLogLevel(statusCode) {
181
+ if (!statusCode) return LogLevel.INFO;
182
+ if (statusCode >= 500) return LogLevel.ERROR;
183
+ if (statusCode >= 400) return LogLevel.WARN;
184
+ return LogLevel.INFO;
185
+ }
186
+ };
187
+
188
+ //#endregion
189
+ export { Logger };
package/dist/timer.mjs CHANGED
@@ -1 +1,164 @@
1
- var e=class{id;startTime;laps=[];stopped=!1;stopTime;constructor(e){this.id=e||crypto.randomUUID(),this.startTime=performance.now()}stop(){if(this.stopped)return this.getElapsed();this.stopTime=performance.now(),this.stopped=!0;let e=this.stopTime-this.startTime;return this.laps.push({label:`stop`,time:this.stopTime,elapsed:e}),e}lap(e){if(this.stopped)return this.getElapsed();let t=performance.now(),n=t-this.startTime;return this.laps.push({label:e||`lap-${this.laps.length+1}`,time:t,elapsed:n}),n}getElapsed(){return this.stopped&&this.stopTime?this.stopTime-this.startTime:performance.now()-this.startTime}getLaps(){return[...this.laps]}getSummary(){return{id:this.id,totalTime:this.getElapsed(),isRunning:!this.stopped,laps:this.getLaps()}}reset(){this.startTime=performance.now(),this.laps=[],this.stopped=!1,this.stopTime=void 0}},t=class{timers=new Map;start(t){let n=new e(t);return this.timers.set(n.id,n),n}get(e){return this.timers.get(e)}stop(e){let t=this.timers.get(e);if(t){let n=t.stop();return this.timers.delete(e),n}}getActive(){return Array.from(this.timers.values()).filter(e=>!!e.getSummary().isRunning)}clear(){this.timers.clear()}getSummary(){return Array.from(this.timers.values()).map(e=>e.getSummary())}};async function n(t,n){let r=new e(n?.id);try{let e=await t(),i=r.stop();return n?.onComplete?.(i),{result:e,elapsed:i,timer:r}}catch(e){throw r.stop(),e}}function r(t,n){let r=new e(n?.id);try{let e=t(),i=r.stop();return n?.onComplete?.(i),{result:e,elapsed:i,timer:r}}catch(e){throw r.stop(),e}}export{e as Timer,t as TimerManager,n as timed,r as timedSync};
1
+ //#region src/timer.ts
2
+ var Timer = class {
3
+ id;
4
+ startTime;
5
+ laps = [];
6
+ stopped = false;
7
+ stopTime;
8
+ constructor(id) {
9
+ this.id = id || crypto.randomUUID();
10
+ this.startTime = performance.now();
11
+ }
12
+ /**
13
+ * Stop the timer and return elapsed time in milliseconds
14
+ */
15
+ stop() {
16
+ if (this.stopped) return this.getElapsed();
17
+ this.stopTime = performance.now();
18
+ this.stopped = true;
19
+ const elapsed = this.stopTime - this.startTime;
20
+ this.laps.push({
21
+ label: "stop",
22
+ time: this.stopTime,
23
+ elapsed
24
+ });
25
+ return elapsed;
26
+ }
27
+ /**
28
+ * Record a lap time and return elapsed time since start
29
+ */
30
+ lap(label) {
31
+ if (this.stopped) return this.getElapsed();
32
+ const now = performance.now();
33
+ const elapsed = now - this.startTime;
34
+ this.laps.push({
35
+ label: label || `lap-${this.laps.length + 1}`,
36
+ time: now,
37
+ elapsed
38
+ });
39
+ return elapsed;
40
+ }
41
+ /**
42
+ * Get elapsed time without stopping the timer
43
+ */
44
+ getElapsed() {
45
+ if (this.stopped && this.stopTime) return this.stopTime - this.startTime;
46
+ return performance.now() - this.startTime;
47
+ }
48
+ /**
49
+ * Get all recorded laps
50
+ */
51
+ getLaps() {
52
+ return [...this.laps];
53
+ }
54
+ /**
55
+ * Get timer summary with total time and laps
56
+ */
57
+ getSummary() {
58
+ return {
59
+ id: this.id,
60
+ totalTime: this.getElapsed(),
61
+ isRunning: !this.stopped,
62
+ laps: this.getLaps()
63
+ };
64
+ }
65
+ /**
66
+ * Reset the timer (starts a new timing session)
67
+ */
68
+ reset() {
69
+ this.startTime = performance.now();
70
+ this.laps = [];
71
+ this.stopped = false;
72
+ this.stopTime = void 0;
73
+ }
74
+ };
75
+ /**
76
+ * Utility class for managing multiple timers
77
+ */
78
+ var TimerManager = class {
79
+ timers = /* @__PURE__ */ new Map();
80
+ /**
81
+ * Start a new timer
82
+ */
83
+ start(id) {
84
+ const timer = new Timer(id);
85
+ this.timers.set(timer.id, timer);
86
+ return timer;
87
+ }
88
+ /**
89
+ * Get an existing timer
90
+ */
91
+ get(id) {
92
+ return this.timers.get(id);
93
+ }
94
+ /**
95
+ * Stop and remove a timer
96
+ */
97
+ stop(id) {
98
+ const timer = this.timers.get(id);
99
+ if (timer) {
100
+ const elapsed = timer.stop();
101
+ this.timers.delete(id);
102
+ return elapsed;
103
+ }
104
+ }
105
+ /**
106
+ * Get all active timers
107
+ */
108
+ getActive() {
109
+ return Array.from(this.timers.values()).filter((timer) => !timer.getSummary().isRunning === false);
110
+ }
111
+ /**
112
+ * Clear all timers
113
+ */
114
+ clear() {
115
+ this.timers.clear();
116
+ }
117
+ /**
118
+ * Get summary of all timers
119
+ */
120
+ getSummary() {
121
+ return Array.from(this.timers.values()).map((timer) => timer.getSummary());
122
+ }
123
+ };
124
+ /**
125
+ * Decorator/wrapper function to time async operations
126
+ */
127
+ async function timed(operation, options) {
128
+ const timer = new Timer(options?.id);
129
+ try {
130
+ const result = await operation();
131
+ const elapsed = timer.stop();
132
+ options?.onComplete?.(elapsed);
133
+ return {
134
+ result,
135
+ elapsed,
136
+ timer
137
+ };
138
+ } catch (error) {
139
+ timer.stop();
140
+ throw error;
141
+ }
142
+ }
143
+ /**
144
+ * Decorator/wrapper function to time synchronous operations
145
+ */
146
+ function timedSync(operation, options) {
147
+ const timer = new Timer(options?.id);
148
+ try {
149
+ const result = operation();
150
+ const elapsed = timer.stop();
151
+ options?.onComplete?.(elapsed);
152
+ return {
153
+ result,
154
+ elapsed,
155
+ timer
156
+ };
157
+ } catch (error) {
158
+ timer.stop();
159
+ throw error;
160
+ }
161
+ }
162
+
163
+ //#endregion
164
+ export { Timer, TimerManager, timed, timedSync };
@@ -1 +1,115 @@
1
- import{LogContext as e}from"./context.browser.mjs";import{Timer as t}from"./timer.mjs";var n=class{context;activeSpans=new Map;constructor(){this.context=e.getInstance()}startSpan(e){let t=this.context.getCurrentTrace(),n={traceId:t?.traceId||this.generateTraceId(),parentId:t?.spanId,spanId:this.generateSpanId(),operationType:e.operationType,operationName:e.operationName,startTime:performance.now(),metadata:{...e.metadata},tags:[...e.tags||[]]};return this.activeSpans.set(n.spanId,n),this.context.setTrace(n),n}finishSpan(e){let t=this.activeSpans.get(e);if(!t)return;let n=performance.now()-t.startTime;if(this.activeSpans.delete(e),this.context.getCurrentTrace()?.spanId===e&&t.parentId){let e=this.findSpanById(t.parentId);e&&this.context.setTrace(e)}return n}async trace(e,n){let r=this.startSpan(e),i=e.autoTiming===!1?void 0:new t(`trace-${r.spanId}`);try{let e=await n(),t=this.finishSpan(r.spanId);return i&&i.stop(),t!==void 0&&(r.metadata.duration=t),e}catch(e){r.metadata.error={name:e.name||`Unknown`,message:e.message||`Unknown error`,stack:e.stack};let t=this.finishSpan(r.spanId);throw r.metadata.duration=t,i&&i.stop(),e}}addMetadata(e,t){let n=this.context.getCurrentTrace();n&&(n.metadata[e]=t)}addTags(...e){let t=this.context.getCurrentTrace();t&&t.tags.push(...e)}getCurrentTrace(){return this.context.getCurrentTrace()}getActiveSpans(){return Array.from(this.activeSpans.values())}findSpanById(e){return this.activeSpans.get(e)}generateTraceId(){return crypto.randomUUID().replace(/-/g,``)}generateSpanId(){return crypto.randomUUID().replace(/-/g,``).substring(0,16)}};export{n as Tracer};
1
+ import { LogContext } from "./context.browser.mjs";
2
+ import { Timer } from "./timer.mjs";
3
+
4
+ //#region src/tracer.browser.ts
5
+ var Tracer = class {
6
+ context;
7
+ activeSpans = /* @__PURE__ */ new Map();
8
+ constructor() {
9
+ this.context = LogContext.getInstance();
10
+ }
11
+ /**
12
+ * Start a new trace span
13
+ */
14
+ startSpan(options) {
15
+ const parentTrace = this.context.getCurrentTrace();
16
+ const span = {
17
+ traceId: parentTrace?.traceId || this.generateTraceId(),
18
+ parentId: parentTrace?.spanId,
19
+ spanId: this.generateSpanId(),
20
+ operationType: options.operationType,
21
+ operationName: options.operationName,
22
+ startTime: performance.now(),
23
+ metadata: { ...options.metadata },
24
+ tags: [...options.tags || []]
25
+ };
26
+ this.activeSpans.set(span.spanId, span);
27
+ this.context.setTrace(span);
28
+ return span;
29
+ }
30
+ /**
31
+ * Finish a trace span
32
+ */
33
+ finishSpan(spanId) {
34
+ const span = this.activeSpans.get(spanId);
35
+ if (!span) return;
36
+ const duration = performance.now() - span.startTime;
37
+ this.activeSpans.delete(spanId);
38
+ if (this.context.getCurrentTrace()?.spanId === spanId && span.parentId) {
39
+ const parentSpan = this.findSpanById(span.parentId);
40
+ if (parentSpan) this.context.setTrace(parentSpan);
41
+ }
42
+ return duration;
43
+ }
44
+ /**
45
+ * Execute a function within a trace span
46
+ */
47
+ async trace(options, fn) {
48
+ const span = this.startSpan(options);
49
+ const timer = options.autoTiming !== false ? new Timer(`trace-${span.spanId}`) : void 0;
50
+ try {
51
+ const result = await fn();
52
+ const duration = this.finishSpan(span.spanId);
53
+ if (timer) timer.stop();
54
+ if (duration !== void 0) span.metadata.duration = duration;
55
+ return result;
56
+ } catch (error) {
57
+ span.metadata.error = {
58
+ name: error.name || "Unknown",
59
+ message: error.message || "Unknown error",
60
+ stack: error.stack
61
+ };
62
+ const duration = this.finishSpan(span.spanId);
63
+ span.metadata.duration = duration;
64
+ if (timer) timer.stop();
65
+ throw error;
66
+ }
67
+ }
68
+ /**
69
+ * Add metadata to current span
70
+ */
71
+ addMetadata(key, value) {
72
+ const currentTrace = this.context.getCurrentTrace();
73
+ if (currentTrace) currentTrace.metadata[key] = value;
74
+ }
75
+ /**
76
+ * Add tags to current span
77
+ */
78
+ addTags(...tags) {
79
+ const currentTrace = this.context.getCurrentTrace();
80
+ if (currentTrace) currentTrace.tags.push(...tags);
81
+ }
82
+ /**
83
+ * Get current trace context
84
+ */
85
+ getCurrentTrace() {
86
+ return this.context.getCurrentTrace();
87
+ }
88
+ /**
89
+ * Get all active spans
90
+ */
91
+ getActiveSpans() {
92
+ return Array.from(this.activeSpans.values());
93
+ }
94
+ /**
95
+ * Find a span by ID
96
+ */
97
+ findSpanById(spanId) {
98
+ return this.activeSpans.get(spanId);
99
+ }
100
+ /**
101
+ * Generate a unique trace ID
102
+ */
103
+ generateTraceId() {
104
+ return crypto.randomUUID().replace(/-/g, "");
105
+ }
106
+ /**
107
+ * Generate a unique span ID
108
+ */
109
+ generateSpanId() {
110
+ return crypto.randomUUID().replace(/-/g, "").substring(0, 16);
111
+ }
112
+ };
113
+
114
+ //#endregion
115
+ export { Tracer };
package/dist/tracer.mjs CHANGED
@@ -1 +1,3 @@
1
- import{Tracer as e}from"./tracer.node.mjs";export{e as Tracer};
1
+ import { Tracer } from "./tracer.node.mjs";
2
+
3
+ export { Tracer };
@@ -1 +1,115 @@
1
- import{LogContext as e}from"./context.node.mjs";import{Timer as t}from"./timer.mjs";var n=class{context;activeSpans=new Map;constructor(){this.context=e.getInstance()}startSpan(e){let t=this.context.getCurrentTrace(),n={traceId:t?.traceId||this.generateTraceId(),parentId:t?.spanId,spanId:this.generateSpanId(),operationType:e.operationType,operationName:e.operationName,startTime:performance.now(),metadata:{...e.metadata},tags:[...e.tags||[]]};return this.activeSpans.set(n.spanId,n),this.context.setTrace(n),n}finishSpan(e){let t=this.activeSpans.get(e);if(!t)return;let n=performance.now()-t.startTime;if(this.activeSpans.delete(e),this.context.getCurrentTrace()?.spanId===e&&t.parentId){let e=this.findSpanById(t.parentId);e&&this.context.setTrace(e)}return n}async trace(e,n){let r=this.startSpan(e),i=e.autoTiming===!1?void 0:new t(`trace-${r.spanId}`);try{let e=await n(),t=this.finishSpan(r.spanId);return i&&i.stop(),t!==void 0&&(r.metadata.duration=t),e}catch(e){r.metadata.error={name:e.name||`Unknown`,message:e.message||`Unknown error`,stack:e.stack};let t=this.finishSpan(r.spanId);throw r.metadata.duration=t,i&&i.stop(),e}}addMetadata(e,t){let n=this.context.getCurrentTrace();n&&(n.metadata[e]=t)}addTags(...e){let t=this.context.getCurrentTrace();t&&t.tags.push(...e)}getCurrentTrace(){return this.context.getCurrentTrace()}getActiveSpans(){return Array.from(this.activeSpans.values())}findSpanById(e){return this.activeSpans.get(e)}generateTraceId(){return crypto.randomUUID().replace(/-/g,``)}generateSpanId(){return crypto.randomUUID().replace(/-/g,``).substring(0,16)}};export{n as Tracer};
1
+ import { LogContext } from "./context.node.mjs";
2
+ import { Timer } from "./timer.mjs";
3
+
4
+ //#region src/tracer.node.ts
5
+ var Tracer = class {
6
+ context;
7
+ activeSpans = /* @__PURE__ */ new Map();
8
+ constructor() {
9
+ this.context = LogContext.getInstance();
10
+ }
11
+ /**
12
+ * Start a new trace span
13
+ */
14
+ startSpan(options) {
15
+ const parentTrace = this.context.getCurrentTrace();
16
+ const span = {
17
+ traceId: parentTrace?.traceId || this.generateTraceId(),
18
+ parentId: parentTrace?.spanId,
19
+ spanId: this.generateSpanId(),
20
+ operationType: options.operationType,
21
+ operationName: options.operationName,
22
+ startTime: performance.now(),
23
+ metadata: { ...options.metadata },
24
+ tags: [...options.tags || []]
25
+ };
26
+ this.activeSpans.set(span.spanId, span);
27
+ this.context.setTrace(span);
28
+ return span;
29
+ }
30
+ /**
31
+ * Finish a trace span
32
+ */
33
+ finishSpan(spanId) {
34
+ const span = this.activeSpans.get(spanId);
35
+ if (!span) return;
36
+ const duration = performance.now() - span.startTime;
37
+ this.activeSpans.delete(spanId);
38
+ if (this.context.getCurrentTrace()?.spanId === spanId && span.parentId) {
39
+ const parentSpan = this.findSpanById(span.parentId);
40
+ if (parentSpan) this.context.setTrace(parentSpan);
41
+ }
42
+ return duration;
43
+ }
44
+ /**
45
+ * Execute a function within a trace span
46
+ */
47
+ async trace(options, fn) {
48
+ const span = this.startSpan(options);
49
+ const timer = options.autoTiming !== false ? new Timer(`trace-${span.spanId}`) : void 0;
50
+ try {
51
+ const result = await fn();
52
+ const duration = this.finishSpan(span.spanId);
53
+ if (timer) timer.stop();
54
+ if (duration !== void 0) span.metadata.duration = duration;
55
+ return result;
56
+ } catch (error) {
57
+ span.metadata.error = {
58
+ name: error.name || "Unknown",
59
+ message: error.message || "Unknown error",
60
+ stack: error.stack
61
+ };
62
+ const duration = this.finishSpan(span.spanId);
63
+ span.metadata.duration = duration;
64
+ if (timer) timer.stop();
65
+ throw error;
66
+ }
67
+ }
68
+ /**
69
+ * Add metadata to current span
70
+ */
71
+ addMetadata(key, value) {
72
+ const currentTrace = this.context.getCurrentTrace();
73
+ if (currentTrace) currentTrace.metadata[key] = value;
74
+ }
75
+ /**
76
+ * Add tags to current span
77
+ */
78
+ addTags(...tags) {
79
+ const currentTrace = this.context.getCurrentTrace();
80
+ if (currentTrace) currentTrace.tags.push(...tags);
81
+ }
82
+ /**
83
+ * Get current trace context
84
+ */
85
+ getCurrentTrace() {
86
+ return this.context.getCurrentTrace();
87
+ }
88
+ /**
89
+ * Get all active spans
90
+ */
91
+ getActiveSpans() {
92
+ return Array.from(this.activeSpans.values());
93
+ }
94
+ /**
95
+ * Find a span by ID
96
+ */
97
+ findSpanById(spanId) {
98
+ return this.activeSpans.get(spanId);
99
+ }
100
+ /**
101
+ * Generate a unique trace ID
102
+ */
103
+ generateTraceId() {
104
+ return crypto.randomUUID().replace(/-/g, "");
105
+ }
106
+ /**
107
+ * Generate a unique span ID
108
+ */
109
+ generateSpanId() {
110
+ return crypto.randomUUID().replace(/-/g, "").substring(0, 16);
111
+ }
112
+ };
113
+
114
+ //#endregion
115
+ export { Tracer };
package/dist/types.mjs CHANGED
@@ -1 +1,13 @@
1
- let e=function(e){return e[e.TRACE=0]=`TRACE`,e[e.DEBUG=1]=`DEBUG`,e[e.INFO=2]=`INFO`,e[e.WARN=3]=`WARN`,e[e.ERROR=4]=`ERROR`,e[e.FATAL=5]=`FATAL`,e}({});export{e as LogLevel};
1
+ //#region src/types.ts
2
+ let LogLevel = /* @__PURE__ */ function(LogLevel$1) {
3
+ LogLevel$1[LogLevel$1["TRACE"] = 0] = "TRACE";
4
+ LogLevel$1[LogLevel$1["DEBUG"] = 1] = "DEBUG";
5
+ LogLevel$1[LogLevel$1["INFO"] = 2] = "INFO";
6
+ LogLevel$1[LogLevel$1["WARN"] = 3] = "WARN";
7
+ LogLevel$1[LogLevel$1["ERROR"] = 4] = "ERROR";
8
+ LogLevel$1[LogLevel$1["FATAL"] = 5] = "FATAL";
9
+ return LogLevel$1;
10
+ }({});
11
+
12
+ //#endregion
13
+ export { LogLevel };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lssm/lib.logger",
3
- "version": "0.0.0-canary-20251217062943",
3
+ "version": "0.0.0-canary-20251217072406",
4
4
  "description": "Comprehensive logging library optimized for Bun with ElysiaJS integration",
5
5
  "keywords": [
6
6
  "logging",
@@ -23,8 +23,8 @@
23
23
  "dev": "bun build:bundle --watch"
24
24
  },
25
25
  "devDependencies": {
26
- "@lssm/tool.typescript": "0.0.0-canary-20251217062943",
27
- "@lssm/tool.tsdown": "0.0.0-canary-20251217062943",
26
+ "@lssm/tool.typescript": "0.0.0-canary-20251217072406",
27
+ "@lssm/tool.tsdown": "0.0.0-canary-20251217072406",
28
28
  "tsdown": "^0.17.4",
29
29
  "typescript": "^5.9.3"
30
30
  },