Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

@qlover/logger

Package Overview
Dependencies
Maintainers
1
Versions
13
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@qlover/logger - npm Package Compare versions

Comparing version
0.1.1
to
0.2.0
+1
dist/index.iife.js
"use strict";var qloverLogger=(()=>{var u=Object.defineProperty;var w=Object.getOwnPropertyDescriptor;var I=Object.getOwnPropertyNames;var L=Object.prototype.hasOwnProperty;var T=(n,t)=>{for(var e in t)u(n,e,{get:t[e],enumerable:!0})},F=(n,t,e,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of I(t))!L.call(n,r)&&r!==e&&u(n,r,{get:()=>t[r],enumerable:!(o=w(t,r))||o.enumerable});return n};var y=n=>F(u({},"__esModule",{value:!0}),n);var k={};T(k,{ConsoleHandler:()=>x,LogContext:()=>s,LogEvent:()=>l,Logger:()=>g,TimestampFormatter:()=>h,defaultLevels:()=>v});var l=class{constructor(t,e,o,r){this.level=t;this.args=e;this.loggerName=o;this.context=r;this.timestamp=Date.now()}timestamp};var s=class{constructor(t){this.value=t}};var v={fatal:0,error:10,warn:20,info:30,debug:40,trace:50,log:60},g=class{constructor(t={}){this.options=t;t.name=t.name||Date.now().toString(),t.levels=t.levels||v,t.handlers=Array.isArray(t.handlers)?t.handlers:t.handlers?[t.handlers]:[]}addAppender(t){this.options.handlers.push(t)}context(t){return new s(t)}print(t,e){let{levels:o,level:r,silent:d,handlers:m}=this.options;if(d)return;let a=e.slice(-1)[0],p=e.length>1&&a instanceof s;if(a=p?a:void 0,e=p?e.slice(0,-1):e,t=a?.value?.level??t,r&&o){let i=o[r],f=o[t];if(i!=null&&f!=null&&f>i)return}let c=new l(t,e,this.options.name,a);for(let i of m)i.append(c)}log(...t){this.print("info",t)}fatal(...t){this.print("fatal",t)}error(...t){this.print("error",t)}warn(...t){this.print("warn",t)}info(...t){this.print("info",t)}debug(...t){this.print("debug",t)}trace(...t){this.print("trace",t)}};var x=class{constructor(t=null){this.formatter=t}setFormatter(t){this.formatter=t}append(t){let{level:e,args:o}=t,r=this.formatter?this.formatter.format(t):o;(console[e]||console.log)(...Array.isArray(r)?r:[r])}};var b={hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!1,timeZone:"UTC"},h=class{constructor(t={}){this.options=t}replacePrefix(t,e){return t.replace(/\{([^{}]+)\}/g,(o,r)=>e[r]||o)}format({timestamp:t,level:e,args:o,context:r,loggerName:d}){let{locale:m="zh-CN",localeOptions:a,prefixTemplate:p="[{formattedTimestamp} {level}]"}=this.options,c=r?.formatType??"datetime",i=c==="date"?"toLocaleDateString":c==="time"?"toLocaleTimeString":"toLocaleString",f=new Date(t)[i](m,{...b,...a});return[this.replacePrefix(p,{...r,timestamp:t.toString(),level:e,loggerName:d,formattedTimestamp:f,locale:m}),...o]}};return y(k);})();
+22
-10
# @qlover/logger
## 0.2.0
### Minor Changes
#### ✨ Features
- **logger:** update logger package configuration and add project setup ([0247314](https://github.com/qlover/fe-base/commit/024731473b1acb019ddb4fa8ea526e31e54de96c)) ([#451](https://github.com/qlover/fe-base/pull/451))
- Changed the main entry point in `package.json` from `index.cjs` to `index.umd.js` for better compatibility.
- Updated the homepage link in `package.json` to point directly to the logger package documentation.
- Introduced a new `project.json` file to define the logger package structure and build targets using NX.
- Modified `tsup.config.ts` to adjust output formats and enable minification, enhancing the build process for the logger package.
These changes improve the configuration and usability of the logger package within the monorepo.
- **pnpm-lock:** update dependencies and clean up unused packages ([05660ed](https://github.com/qlover/fe-base/commit/05660edbeed5dadf00537177cb749abaed45d0ae)) ([#451](https://github.com/qlover/fe-base/pull/451))
- Added `tailwindcss` and `vite` to the dependencies in `pnpm-lock.yaml` with their respective versions.
- Removed unused dependencies related to React and Vite plugins, streamlining the package management.
- Updated the build command in `packages/logger/project.json` to use `pnpm build`, enhancing the build process for the logger package.
- Included additional inputs for the build process to ensure all necessary files are considered during the build.
These changes improve dependency management and build configuration within the project.
## 0.1.1

@@ -20,3 +42,2 @@

- integrate @qlover/logger into corekit-bridge (#373)
- Added @qlover/logger as a dependency across multiple files, replacing the previous logger from @qlover/fe-corekit.

@@ -31,3 +52,2 @@ - Updated type references to LoggerInterface in Bootstrap, ApiCatchPlugin, and ApiMockPlugin.

- update ColorFormatter tests to utilize LogContext (#373)
- Modified ColorFormatter tests to use the new LogContext class for improved context handling.

@@ -40,3 +60,2 @@ - Adjusted the test setup to ensure proper formatting of color segments with the updated LogContext structure.

- enhance context handling and update ColorFormatter tests (#373)
- Refactored logger context handling to utilize a new LogContext class for better type safety and clarity.

@@ -48,3 +67,2 @@ - Updated ColorFormatter tests to use logger.context for passing context objects.

- replace ConsoleAppender with ConsoleHandler (#373)
- Updated tests and implementation to utilize ConsoleHandler instead of ConsoleAppender for improved logging functionality.

@@ -63,3 +81,2 @@ - Introduced ConsoleHandler class to manage log events and formatting.

- integrate @qlover/logger into scripts-context package (#371)
- Added @qlover/logger as a dependency, replacing the previous logger from @qlover/fe-corekit.

@@ -71,3 +88,2 @@ - Updated Shell, ScriptContext, and ScriptsLogger to utilize the new LoggerInterface from @qlover/logger.

- update logger package configuration and add mock (#371)
- Added 'logger' to the Vite alias configuration for improved module resolution.

@@ -79,3 +95,2 @@ - Updated package.json to include a 'default' export alongside 'require'.

- integrate @qlover/logger into fe-release package (#371)
- Added @qlover/logger as a dependency in package.json and pnpm-lock.yaml.

@@ -97,3 +112,2 @@ - Updated logger type references from @qlover/fe-corekit to LoggerInterface from @qlover/logger.

- restructure implementation files and remove deprecated dependencies (#371)
- Moved implementation files for ConfigSearch, Shell, and related utilities to a new 'implement' directory for better organization.

@@ -117,3 +131,2 @@ - Removed the dependency on '@qlover/fe-corekit' from pnpm-lock.yaml.

- add @qlover/logger package with ConsoleAppender and TimestampFormatter (#369)
- Introduced a new logging package, @qlover/logger, which includes a Logger class for structured logging.

@@ -125,3 +138,2 @@ - Implemented ConsoleAppender for console output and TimestampFormatter for formatted timestamps.

- enhance @qlover/logger package with new build script and documentation updates (#369)
- Added a new build script for the logger package to streamline the build process.

@@ -128,0 +140,0 @@ - Introduced an English README file for better accessibility and understanding of the logger's features and usage.

@@ -1,416 +0,1 @@

"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var index_exports = {};
__export(index_exports, {
ConsoleHandler: () => ConsoleHandler,
LogContext: () => LogContext,
LogEvent: () => LogEvent,
Logger: () => Logger,
TimestampFormatter: () => TimestampFormatter,
defaultLevels: () => defaultLevels
});
module.exports = __toCommonJS(index_exports);
// src/interface/LogEvent.ts
var LogEvent = class {
constructor(level, args, loggerName, context) {
this.level = level;
this.args = args;
this.loggerName = loggerName;
this.context = context;
this.timestamp = Date.now();
}
timestamp;
};
// src/interface/LogContext.ts
var LogContext = class {
constructor(value) {
this.value = value;
}
};
// src/Logger.ts
var defaultLevels = {
fatal: 0,
error: 10,
warn: 20,
info: 30,
debug: 40,
trace: 50,
log: 60
};
var Logger = class {
/**
* Creates a new Logger instance
*
* @param options - Configuration options for the logger
*
* @note If no name is provided, a timestamp-based name will be generated
* @note If no levels are provided, defaultLevels will be used
* @note If no handlers are provided, an empty array will be used (silent logging)
*/
constructor(options = {}) {
this.options = options;
options.name = options.name || Date.now().toString();
options.levels = options.levels || defaultLevels;
options.handlers = Array.isArray(options.handlers) ? options.handlers : options.handlers ? [options.handlers] : [];
}
/**
* Adds a new log handler to the logger
*
* Handlers are responsible for actually outputting log messages (to console, files, etc.)
* Multiple handlers can be registered to send logs to different destinations simultaneously.
*
* @override Implementation of LoggerInterface
* @param appender - Handler instance to add
*
* @example
* logger.addAppender(new ConsoleHandler());
* logger.addAppender(new FileAppender('./logs/errors.log', { level: 'error' }));
*
* @note Handlers are processed in the order they are added
* @important This method is named 'addAppender' for legacy/compatibility reasons,
* but it works with any object implementing HandlerInterface
*/
addAppender(appender) {
this.options.handlers.push(appender);
}
/**
* Creates a new LogContext instance
*
* @override
* @since 0.1.0
* @param value - Optional value to be stored in the context
* @returns A new LogContext instance with the provided value
*/
context(value) {
return new LogContext(value);
}
/**
* Internal method to process and distribute log events
*
* This method:
* 1. Checks if logging is silenced
* 2. Extracts context from arguments if present
* 3. Applies level filtering based on configured threshold
* 4. Creates a LogEvent and distributes it to all handlers
*
* @protected
* @param level - Log level name (e.g., "info", "error")
* @param args - Log message arguments (message content and optional context)
*
* @example context
* ```ts
* logger.info('message with context', logger.context({ user: 'testUser', requestId: '123' }));
* logger.info('message with context', logger.context([1,2,3]));
* logger.info('message with context', logger.context(1));
* logger.info('message with context', logger.context('1'));
* logger.info('message with context', logger.context(true));
* logger.info('message with context', logger.context());
* ```
*
* **But context only support last argument and must be a non-null object**
*
* @note Context object must be the last argument and must be a non-null object
* @note Context can override the log level via a 'level' property
* @important This method is not meant to be called directly - use the specific level methods instead
*/
print(level, args) {
const { levels, level: indexLevel, silent, handlers } = this.options;
if (silent) {
return;
}
let ctx = args.slice(-1)[0];
const hasCtx = args.length > 1 && ctx instanceof LogContext;
ctx = hasCtx ? ctx : void 0;
args = hasCtx ? args.slice(0, -1) : args;
level = ctx?.value?.level ?? level;
if (indexLevel && levels) {
const target = levels[indexLevel];
const current = levels[level];
if (target != null && current != null && current > target) {
return;
}
}
const logEvent = new LogEvent(level, args, this.options.name, ctx);
for (const handler of handlers) {
handler.append(logEvent);
}
}
/**
* Logs a message with "info" level
* Alias for info() method
*
* General purpose logging method, categorized as "info" level
*
* @param args - Message content followed by optional context object
*
* @example
* // Simple usage
* logger.log('User logged in');
*
* @example
* // With context object
* logger.log('User logged in', { userId: 123, timestamp: Date.now() });
*
* @note This method uses 'info' level internally, but appears as 'log' in default levels
*/
log(...args) {
this.print("info", args);
}
/**
* Logs a critical error message with "fatal" level
*
* Use for severe errors that lead to application termination or require immediate attention
* This is the highest severity level and will always be logged unless silent mode is enabled
*
* @param args - Message content followed by optional context object
*
* @example
* logger.fatal('Database connection failed, application cannot continue');
*
* @example
* try {
* // Critical operation
* } catch (error) {
* logger.fatal('Critical system failure', { error, stack: error.stack });
* process.exit(1);
* }
*
* @important Fatal logs typically indicate that the application cannot continue to function
*/
fatal(...args) {
this.print("fatal", args);
}
/**
* Logs an error message with "error" level
*
* Use for runtime errors, exceptions, and error conditions that don't necessarily
* cause application termination but indicate a failure
*
* @param args - Message content followed by optional context object
*
* @example
* // Simple error logging
* logger.error('Failed to process payment');
*
* @example
* // Error with exception details
* try {
* // Some operation
* } catch (err) {
* logger.error('Operation failed', {
* error: err.message,
* stack: err.stack,
* code: err.code
* });
* }
*
* @note Error logs should provide enough context to diagnose the problem
*/
error(...args) {
this.print("error", args);
}
/**
* Logs a warning message with "warn" level
*
* Use for potentially problematic situations, deprecated features usage,
* or unexpected conditions that don't cause failures but might lead to issues
*
* @param args - Message content followed by optional context object
*
* @example
* // Simple warning
* logger.warn('Deprecated API being used');
*
* @example
* // Warning with context
* logger.warn('High memory usage detected', {
* memoryUsage: process.memoryUsage().heapUsed,
* threshold: maxMemoryThreshold
* });
*
* @note Warnings shouldn't be ignored in production systems as they often indicate future problems
*/
warn(...args) {
this.print("warn", args);
}
/**
* Logs an informational message with "info" level
*
* Use for general application state, notable events in application flow,
* startup messages, configuration details, or business process completions
*
* @param args - Message content followed by optional context object
*
* @example
* // Simple info message
* logger.info('Server started on port 3000');
*
* @example
* // Info with context
* logger.info('User registration complete', {
* userId: user.id,
* email: user.email,
* registrationTime: new Date().toISOString()
* });
*
* @note Info level is typically the default level in production environments
*/
info(...args) {
this.print("info", args);
}
/**
* Logs a debug message with "debug" level
*
* Use for detailed information useful during development and troubleshooting
* Such as variable values, function calls, or internal application state
*
* @param args - Message content followed by optional context object
*
* @example
* // Simple debug message
* logger.debug('Processing request payload');
*
* @example
* // Debug with detailed context
* logger.debug('API request received', {
* method: req.method,
* path: req.path,
* params: req.params,
* query: req.query,
* headers: req.headers,
* body: req.body
* });
*
* @note Debug logs are typically disabled in production environments
* @important Debug logs can contain sensitive information, use caution in production
*/
debug(...args) {
this.print("debug", args);
}
/**
* Logs a trace message with "trace" level
*
* Use for the most detailed diagnostic information
* Such as function entry/exit points, variable transformations, or method call tracing
*
* @param args - Message content followed by optional context object
*
* @example
* // Function entry tracing
* logger.trace('Entering validateUser function', { username });
*
* @example
* // Detailed algorithmic tracing
* logger.trace('Processing array element', {
* index: i,
* value: array[i],
* transformedValue: processedValue,
* processingTime: endTime - startTime
* });
*
* @note Trace is the most verbose level and should only be enabled temporarily for debugging
* @important Trace logs can significantly impact performance and generate large volumes of data
*/
trace(...args) {
this.print("trace", args);
}
};
// src/ConsoleHandler.ts
var ConsoleHandler = class {
constructor(formatter = null) {
this.formatter = formatter;
}
/**
* Set formatter
*
* @override
* @param formatter
*/
setFormatter(formatter) {
this.formatter = formatter;
}
/**
* Append log event
*
* @override
* @param event
*/
append(event) {
const { level, args } = event;
const formattedArgs = this.formatter ? this.formatter.format(event) : args;
(console[level] || console.log)(...Array.isArray(formattedArgs) ? formattedArgs : [formattedArgs]);
}
};
// src/TimestampFormatter.ts
var defaultLocaleOptions = {
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
hour12: false,
timeZone: "UTC"
};
var TimestampFormatter = class {
constructor(options = {}) {
this.options = options;
}
replacePrefix(template, vars) {
return template.replace(/\{([^{}]+)\}/g, (match, p1) => vars[p1] || match);
}
format({ timestamp, level, args, context, loggerName }) {
const {
locale = "zh-CN",
localeOptions,
prefixTemplate = "[{formattedTimestamp} {level}]"
} = this.options;
const formatType = context?.formatType ?? "datetime";
const dateFormatMethod = formatType === "date" ? "toLocaleDateString" : formatType === "time" ? "toLocaleTimeString" : "toLocaleString";
const formattedTimestamp = new Date(timestamp)[dateFormatMethod](locale, {
...defaultLocaleOptions,
...localeOptions
});
return [
this.replacePrefix(prefixTemplate, {
...context,
timestamp: timestamp.toString(),
level,
loggerName,
formattedTimestamp,
locale
}),
...args
];
}
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
ConsoleHandler,
LogContext,
LogEvent,
Logger,
TimestampFormatter,
defaultLevels
});
//# sourceMappingURL=index.cjs.map
"use strict";var u=Object.defineProperty;var w=Object.getOwnPropertyDescriptor;var I=Object.getOwnPropertyNames;var L=Object.prototype.hasOwnProperty;var T=(n,t)=>{for(var e in t)u(n,e,{get:t[e],enumerable:!0})},F=(n,t,e,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of I(t))!L.call(n,r)&&r!==e&&u(n,r,{get:()=>t[r],enumerable:!(o=w(t,r))||o.enumerable});return n};var y=n=>F(u({},"__esModule",{value:!0}),n);var k={};T(k,{ConsoleHandler:()=>x,LogContext:()=>s,LogEvent:()=>l,Logger:()=>g,TimestampFormatter:()=>h,defaultLevels:()=>v});module.exports=y(k);var l=class{constructor(t,e,o,r){this.level=t;this.args=e;this.loggerName=o;this.context=r;this.timestamp=Date.now()}timestamp};var s=class{constructor(t){this.value=t}};var v={fatal:0,error:10,warn:20,info:30,debug:40,trace:50,log:60},g=class{constructor(t={}){this.options=t;t.name=t.name||Date.now().toString(),t.levels=t.levels||v,t.handlers=Array.isArray(t.handlers)?t.handlers:t.handlers?[t.handlers]:[]}addAppender(t){this.options.handlers.push(t)}context(t){return new s(t)}print(t,e){let{levels:o,level:r,silent:d,handlers:m}=this.options;if(d)return;let a=e.slice(-1)[0],p=e.length>1&&a instanceof s;if(a=p?a:void 0,e=p?e.slice(0,-1):e,t=a?.value?.level??t,r&&o){let i=o[r],f=o[t];if(i!=null&&f!=null&&f>i)return}let c=new l(t,e,this.options.name,a);for(let i of m)i.append(c)}log(...t){this.print("info",t)}fatal(...t){this.print("fatal",t)}error(...t){this.print("error",t)}warn(...t){this.print("warn",t)}info(...t){this.print("info",t)}debug(...t){this.print("debug",t)}trace(...t){this.print("trace",t)}};var x=class{constructor(t=null){this.formatter=t}setFormatter(t){this.formatter=t}append(t){let{level:e,args:o}=t,r=this.formatter?this.formatter.format(t):o;(console[e]||console.log)(...Array.isArray(r)?r:[r])}};var b={hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!1,timeZone:"UTC"},h=class{constructor(t={}){this.options=t}replacePrefix(t,e){return t.replace(/\{([^{}]+)\}/g,(o,r)=>e[r]||o)}format({timestamp:t,level:e,args:o,context:r,loggerName:d}){let{locale:m="zh-CN",localeOptions:a,prefixTemplate:p="[{formattedTimestamp} {level}]"}=this.options,c=r?.formatType??"datetime",i=c==="date"?"toLocaleDateString":c==="time"?"toLocaleTimeString":"toLocaleString",f=new Date(t)[i](m,{...b,...a});return[this.replacePrefix(p,{...r,timestamp:t.toString(),level:e,loggerName:d,formattedTimestamp:f,locale:m}),...o]}};0&&(module.exports={ConsoleHandler,LogContext,LogEvent,Logger,TimestampFormatter,defaultLevels});

@@ -10,2 +10,16 @@ // src/interface/LogEvent.ts

}
/**
* Timestamp when the log event was created
*
* Automatically set to the current time in milliseconds since the Unix epoch
* when the event is constructed. This ensures accurate timing information
* for each log entry.
*
* @example
* ```typescript
* const event = new LogEvent('info', ['message'], 'app');
* console.log(new Date(event.timestamp).toISOString());
* // Output: "2024-03-21T14:30:45.123Z"
* ```
*/
timestamp;

@@ -16,2 +30,95 @@ };

var LogContext = class {
/**
* Creates a new LogContext instance
*
* @param value - Optional context value of type Value
*
* The value parameter is marked as optional to support:
* - Empty contexts (no value provided)
* - Explicitly undefined values
* - Nullable types (Value | null)
*
* The value is stored as a public property to allow:
* - Direct access in formatters and handlers
* - Type-safe value extraction
* - Optional chaining support
*
* @example Basic construction
* ```typescript
* // With value
* const context = new LogContext({ userId: 123 });
* console.log(context.value?.userId); // 123
*
* // Empty context
* const empty = new LogContext();
* console.log(empty.value); // undefined
* ```
*
* @example Type-safe construction
* ```typescript
* interface UserContext {
* id: number;
* name: string;
* role?: string;
* }
*
* const context = new LogContext<UserContext>({
* id: 123,
* name: 'John',
* role: 'admin' // Optional property
* });
*
* // Type-safe access
* const userId = context.value?.id; // number | undefined
* const role = context.value?.role; // string | undefined
* ```
*
* @example Nullable context
* ```typescript
* type NullableContext = {
* sessionId: string;
* } | null;
*
* // With value
* const active = new LogContext<NullableContext>({
* sessionId: 'sess-123'
* });
*
* // With null
* const inactive = new LogContext<NullableContext>(null);
*
* // Type-safe null handling
* console.log(active.value?.sessionId); // 'sess-123'
* console.log(inactive.value?.sessionId); // undefined
* ```
*
* @example Context in logging
* ```typescript
* interface RequestContext {
* path: string;
* method: string;
* duration: number;
* }
*
* const context = new LogContext<RequestContext>({
* path: '/api/users',
* method: 'GET',
* duration: 150
* });
*
* // Using context in log messages
* logger.info('Request completed', context);
*
* // Accessing context in formatters
* class RequestFormatter implements FormatterInterface<RequestContext> {
* format(event: LogEvent<RequestContext>): string[] {
* const ctx = event.context?.value;
* return [
* ctx ? `${ctx.method} ${ctx.path} (${ctx.duration}ms)` : 'Unknown',
* ...event.args
* ];
* }
* }
* ```
*/
constructor(value) {

@@ -313,2 +420,40 @@ this.value = value;

var ConsoleHandler = class {
/**
* Creates a new ConsoleHandler instance
*
* @param formatter - Optional formatter for customizing log message format
* If not provided, raw log messages will be output
*
* @example Without formatter
* ```typescript
* const handler = new ConsoleHandler();
* // Output: Raw message without formatting
* ```
*
* @example With timestamp formatter
* ```typescript
* const handler = new ConsoleHandler(
* new TimestampFormatter({
* locale: 'zh-CN',
* prefixTemplate: '[{formattedTimestamp}] {level}:'
* })
* );
* // Output: [2024-03-21 14:30:45] INFO: Message
* ```
*
* @example With JSON formatter
* ```typescript
* const handler = new ConsoleHandler(
* new JSONFormatter({
* pretty: true,
* fields: ['timestamp', 'level', 'message']
* })
* );
* // Output: {
* // "timestamp": "2024-03-21T14:30:45.000Z",
* // "level": "INFO",
* // "message": "Application started"
* // }
* ```
*/
constructor(formatter = null) {

@@ -318,6 +463,48 @@ this.formatter = formatter;

/**
* Set formatter
* Sets or updates the formatter for this handler
*
* @override
* @param formatter
* This method allows dynamic updating of the formatter after handler creation.
* It's useful when you need to change the formatting style without creating
* a new handler instance.
*
* @override Implementation of HandlerInterface
* @param formatter - The formatter instance to use for formatting log messages
*
* @example Changing formatter at runtime
* ```typescript
* const handler = new ConsoleHandler();
* const logger = new Logger({ handlers: [handler] });
*
* // Initially no formatting
* logger.info('Plain message');
* // Output: Plain message
*
* // Switch to timestamp formatting
* handler.setFormatter(new TimestampFormatter());
* logger.info('Formatted message');
* // Output: [2024-03-21 14:30:45 INFO] Formatted message
*
* // Switch to JSON formatting
* handler.setFormatter(new JSONFormatter());
* logger.info('JSON message');
* // Output: {"timestamp":"2024-03-21T14:30:45.000Z","level":"INFO","message":"JSON message"}
* ```
*
* @example Conditional formatting
* ```typescript
* const handler = new ConsoleHandler();
* const logger = new Logger({ handlers: [handler] });
*
* if (process.env.NODE_ENV === 'development') {
* // Use pretty formatting in development
* handler.setFormatter(new TimestampFormatter({
* prefixTemplate: '[{formattedTimestamp}] {level}:'
* }));
* } else {
* // Use JSON formatting in production
* handler.setFormatter(new JSONFormatter({
* fields: ['timestamp', 'level', 'message', 'metadata']
* }));
* }
* ```
*/

@@ -328,6 +515,92 @@ setFormatter(formatter) {

/**
* Append log event
* Processes and outputs a log event to the console
*
* @override
* @param event
* This method:
* 1. Extracts level and arguments from the event
* 2. Applies formatting if a formatter is set
* 3. Selects appropriate console method based on level
* 4. Outputs the formatted message to the console
*
* @override Implementation of HandlerInterface
* @param event - The log event to process and output
*
* @example Basic event handling
* ```typescript
* const handler = new ConsoleHandler();
*
* // Simple message
* handler.append({
* level: 'info',
* args: ['Application started'],
* timestamp: Date.now(),
* loggerName: 'app'
* });
* // Console output: Application started
*
* // Message with context
* handler.append({
* level: 'error',
* args: [
* 'Database connection failed',
* { host: 'localhost', port: 5432, error: 'Connection refused' }
* ],
* timestamp: Date.now(),
* loggerName: 'db'
* });
* // Console output: Database connection failed { host: 'localhost', ... }
* ```
*
* @example Formatted event handling
* ```typescript
* const handler = new ConsoleHandler(
* new TimestampFormatter({
* prefixTemplate: '[{formattedTimestamp}] {level}:'
* })
* );
*
* handler.append({
* level: 'warn',
* args: ['High memory usage', { usage: '85%' }],
* timestamp: Date.now(),
* loggerName: 'system'
* });
* // Console output: [2024-03-21 14:30:45] WARN: High memory usage { usage: '85%' }
* ```
*
* @example Level-specific console methods
* ```typescript
* const handler = new ConsoleHandler();
*
* // Uses console.error()
* handler.append({
* level: 'error',
* args: ['Critical error'],
* timestamp: Date.now(),
* loggerName: 'app'
* });
*
* // Uses console.warn()
* handler.append({
* level: 'warn',
* args: ['Deprecated feature used'],
* timestamp: Date.now(),
* loggerName: 'app'
* });
*
* // Uses console.debug()
* handler.append({
* level: 'debug',
* args: ['Processing request'],
* timestamp: Date.now(),
* loggerName: 'app'
* });
*
* // Unknown level falls back to console.log()
* handler.append({
* level: 'custom',
* args: ['Custom message'],
* timestamp: Date.now(),
* loggerName: 'app'
* });
* ```
*/

@@ -350,8 +623,83 @@ append(event) {

var TimestampFormatter = class {
/**
* Creates a new TimestampFormatter instance
*
* @param options - Configuration options for the formatter
*
* @example
* ```typescript
* const formatter = new TimestampFormatter({
* locale: 'zh-CN',
* prefixTemplate: '[{formattedTimestamp}] {level}:'
* });
* ```
*/
constructor(options = {}) {
this.options = options;
}
/**
* Replaces template variables in the prefix string with actual values
*
* This internal method handles the variable substitution in prefix templates,
* replacing placeholders like {timestamp} with their corresponding values.
*
* @param template - The template string containing variables in curly braces
* @param vars - Object containing variable names and their values
* @returns The template string with all variables replaced
*
* @example Internal usage
* ```typescript
* const vars = {
* timestamp: '1679395845000',
* level: 'INFO',
* formattedTimestamp: '2024-03-21 14:30:45'
* };
*
* // Template: "[{formattedTimestamp}] {level}"
* // Result: "[2024-03-21 14:30:45] INFO"
* const result = this.replacePrefix(template, vars);
* ```
*
* @protected
*/
replacePrefix(template, vars) {
return template.replace(/\{([^{}]+)\}/g, (match, p1) => vars[p1] || match);
}
/**
* Formats a log event by adding a timestamp prefix
*
* This method implements the FormatterInterface.format method. It:
* 1. Extracts format type from context (if provided)
* 2. Formats the timestamp according to locale and options
* 3. Builds the prefix using the template
* 4. Returns the formatted log entry
*
* @param event - The log event to format
* @param event.timestamp - Event timestamp in milliseconds
* @param event.level - Log level (e.g., INFO, ERROR)
* @param event.args - Original log message arguments
* @param event.context - Optional context with format customization
* @param event.loggerName - Name of the logger instance
*
* @returns Array containing the formatted prefix followed by original arguments
*
* @example Internal processing
* ```typescript
* // Input event:
* {
* timestamp: 1679395845000,
* level: 'INFO',
* args: ['User logged in', { userId: 123 }],
* context: { formatType: 'datetime' },
* loggerName: 'UserService'
* }
*
* // Output array:
* [
* '[2024-03-21 14:30:45 INFO]',
* 'User logged in',
* { userId: 123 }
* ]
* ```
*/
format({ timestamp, level, args, context, loggerName }) {

@@ -390,2 +738,1 @@ const {

};
//# sourceMappingURL=index.js.map
{
"name": "@qlover/logger",
"version": "0.1.1",
"version": "0.2.0",
"type": "module",
"private": false,
"main": "./dist/index.cjs",
"main": "./dist/index.umd.js",
"module": "./dist/index.js",

@@ -14,3 +14,3 @@ "types": "./dist/index.d.ts",

"import": "./dist/index.js",
"require": "./dist/index.cjs"
"require": "./dist/index.umd.js"
}

@@ -30,3 +30,3 @@ },

},
"homepage": "https://github.com/qlover/fe-base#readme",
"homepage": "https://github.com/qlover/fe-base/tree/master/packages/logger#readme",
"keywords": [

@@ -43,4 +43,5 @@ "logger",

"scripts": {
"build": "tsup"
"build": "tsup",
"build:docs": "fe-code2md -p src -g docs --formatOutput prettier --removePrefix"
}
}
{"version":3,"sources":["../src/index.ts","../src/interface/LogEvent.ts","../src/interface/LogContext.ts","../src/Logger.ts","../src/ConsoleHandler.ts","../src/TimestampFormatter.ts"],"sourcesContent":["export * from './Logger';\nexport * from './ConsoleHandler';\nexport * from './TimestampFormatter';\nexport * from './interface/LoggerInterface';\nexport * from './interface/HandlerInterface';\nexport * from './interface/FormatterInterface';\nexport * from './interface/LogEvent';\nexport * from './interface/LogContext';","import { LogContext } from \"./LogContext\";\n\nexport class LogEvent<Ctx = unknown> {\n public timestamp: number;\n\n constructor(\n public level: string,\n public args: unknown[],\n public loggerName: string,\n public context?: LogContext<Ctx>\n ) {\n this.timestamp = Date.now();\n }\n}\n","export class LogContext<Value> {\n constructor(public value?: Value) {}\n}\n","import { LoggerInterface } from './interface/LoggerInterface';\nimport { HandlerInterface } from './interface/HandlerInterface';\nimport { LogEvent } from './interface/LogEvent';\nimport { LogContext } from './interface/LogContext';\n\n/**\n * Default log levels with their priorities (lower number = higher priority)\n *\n * This defines the standard hierarchy of logging levels:\n * - fatal (0): System is unusable, application crashes\n * - error (1): Error events that might still allow the application to continue running\n * - warn (2): Potentially harmful situations that don't cause application failure\n * - info (3): Informational messages highlighting application progress\n * - debug (4): Detailed information useful for debugging\n * - trace (5): Most granular information for very detailed diagnostics\n * - log (6): General purpose logging (alias for info)\n *\n * @type {Object.<string, number>}\n */\nexport const defaultLevels = {\n fatal: 0,\n error: 10,\n warn: 20,\n info: 30,\n debug: 40,\n trace: 50,\n log: 60\n};\n\n/**\n * Configuration options for the Logger\n */\nexport type LoggerOptions = {\n /**\n * Silent mode - when true, no logs will be output regardless of level\n * Useful for completely disabling logging in production or test environments\n * without changing the code.\n *\n * @default false\n */\n silent?: boolean;\n\n /**\n * Custom log levels with numeric priority values\n * Lower numbers indicate higher priority levels (0 is highest priority)\n *\n * You can define your own custom levels or override the default ones.\n *\n * @important When defining custom levels, ensure consistency across your application\n * @default defaultLevels\n * @example\n * {\n * critical: 0,\n * serious: 1,\n * important: 2,\n * normal: 3,\n * verbose: 4\n * }\n */\n levels?: Record<string, number>;\n\n /**\n * Current log level threshold\n * Only logs with a level priority <= this level's priority will be processed\n *\n * @important Setting level to \"info\" means info, warn, error, and fatal logs will be output,\n * while debug and trace will be filtered out\n * @example \"info\" - Will output info, warn, error, and fatal logs\n * @example \"debug\" - Will output all logs except trace\n */\n level?: string;\n\n /**\n * Logger instance identifier\n * Used to identify the source of log messages, especially useful when using multiple loggers\n *\n * @default Date.now().toString()\n * @example \"api-server\", \"payment-process\", \"user-service\"\n */\n name?: string;\n\n /**\n * Log handlers that process and output the log events\n * Can be a single handler or an array of handlers\n *\n * Handlers determine how and where logs are output (console, file, network, etc.)\n *\n * @example [new ConsoleHandler(), new FileAppender('./logs/app.log')]\n */\n handlers?: HandlerInterface | HandlerInterface[];\n};\n\n/**\n * Main Logger class that implements the LoggerInterface\n * Processes log events and distributes them to registered handlers\n *\n * This class follows a flexible logging architecture where:\n * 1. Log events are created based on severity level\n * 2. Events are filtered according to configured level thresholds\n * 3. Approved events are passed to handlers for formatting and output\n *\n * @implements {LoggerInterface}\n * @example\n * // Basic usage\n * const logger = new Logger({ level: 'info' });\n * logger.addAppender(new ConsoleHandler());\n * logger.info('Application started');\n *\n * @example\n * // Advanced usage with context\n * logger.error('Payment failed', {\n * userId: 123,\n * amount: 50.25,\n * currency: 'USD',\n * error: new Error('Insufficient funds')\n * });\n */\nexport class Logger implements LoggerInterface {\n /**\n * Creates a new Logger instance\n *\n * @param options - Configuration options for the logger\n *\n * @note If no name is provided, a timestamp-based name will be generated\n * @note If no levels are provided, defaultLevels will be used\n * @note If no handlers are provided, an empty array will be used (silent logging)\n */\n constructor(protected options: LoggerOptions = {}) {\n options.name = options.name || Date.now().toString();\n options.levels = options.levels || defaultLevels;\n\n options.handlers = Array.isArray(options.handlers)\n ? options.handlers\n : options.handlers\n ? [options.handlers]\n : [];\n }\n\n /**\n * Adds a new log handler to the logger\n *\n * Handlers are responsible for actually outputting log messages (to console, files, etc.)\n * Multiple handlers can be registered to send logs to different destinations simultaneously.\n *\n * @override Implementation of LoggerInterface\n * @param appender - Handler instance to add\n *\n * @example\n * logger.addAppender(new ConsoleHandler());\n * logger.addAppender(new FileAppender('./logs/errors.log', { level: 'error' }));\n *\n * @note Handlers are processed in the order they are added\n * @important This method is named 'addAppender' for legacy/compatibility reasons,\n * but it works with any object implementing HandlerInterface\n */\n addAppender(appender: HandlerInterface): void {\n (this.options.handlers as HandlerInterface[]).push(appender);\n }\n\n /**\n * Creates a new LogContext instance\n *\n * @override\n * @since 0.1.0\n * @param value - Optional value to be stored in the context\n * @returns A new LogContext instance with the provided value\n */\n context<Value>(value?: Value): LogContext<Value> {\n return new LogContext(value);\n }\n\n /**\n * Internal method to process and distribute log events\n *\n * This method:\n * 1. Checks if logging is silenced\n * 2. Extracts context from arguments if present\n * 3. Applies level filtering based on configured threshold\n * 4. Creates a LogEvent and distributes it to all handlers\n *\n * @protected\n * @param level - Log level name (e.g., \"info\", \"error\")\n * @param args - Log message arguments (message content and optional context)\n *\n * @example context\n * ```ts\n * logger.info('message with context', logger.context({ user: 'testUser', requestId: '123' }));\n * logger.info('message with context', logger.context([1,2,3]));\n * logger.info('message with context', logger.context(1));\n * logger.info('message with context', logger.context('1'));\n * logger.info('message with context', logger.context(true));\n * logger.info('message with context', logger.context());\n * ```\n *\n * **But context only support last argument and must be a non-null object**\n *\n * @note Context object must be the last argument and must be a non-null object\n * @note Context can override the log level via a 'level' property\n * @important This method is not meant to be called directly - use the specific level methods instead\n */\n protected print(level: string, args: unknown[]): void {\n const { levels, level: indexLevel, silent, handlers } = this.options;\n\n // Skip logging if in silent mode\n if (silent) {\n return;\n }\n\n // Extract context object from arguments if present\n let ctx = args.slice(-1)[0] as LogContext<unknown> | undefined;\n const hasCtx = args.length > 1 && ctx instanceof LogContext;\n ctx = hasCtx ? ctx : undefined;\n args = hasCtx ? args.slice(0, -1) : args;\n\n // Allow level override from context, if a plain object is provided\n level = (ctx?.value as { level?: string })?.level ?? level;\n\n // Apply level filtering based on configured threshold\n if (indexLevel && levels) {\n const target = levels[indexLevel!];\n const current = levels[level];\n if (target != null && current != null && current > target) {\n return;\n }\n }\n\n // Create and distribute log event to all handlers\n const logEvent = new LogEvent(level, args, this.options.name!, ctx);\n\n for (const handler of handlers as HandlerInterface[]) {\n handler.append(logEvent);\n }\n }\n\n /**\n * Logs a message with \"info\" level\n * Alias for info() method\n *\n * General purpose logging method, categorized as \"info\" level\n *\n * @param args - Message content followed by optional context object\n *\n * @example\n * // Simple usage\n * logger.log('User logged in');\n *\n * @example\n * // With context object\n * logger.log('User logged in', { userId: 123, timestamp: Date.now() });\n *\n * @note This method uses 'info' level internally, but appears as 'log' in default levels\n */\n log(...args: unknown[]): void {\n this.print('info', args);\n }\n\n /**\n * Logs a critical error message with \"fatal\" level\n *\n * Use for severe errors that lead to application termination or require immediate attention\n * This is the highest severity level and will always be logged unless silent mode is enabled\n *\n * @param args - Message content followed by optional context object\n *\n * @example\n * logger.fatal('Database connection failed, application cannot continue');\n *\n * @example\n * try {\n * // Critical operation\n * } catch (error) {\n * logger.fatal('Critical system failure', { error, stack: error.stack });\n * process.exit(1);\n * }\n *\n * @important Fatal logs typically indicate that the application cannot continue to function\n */\n fatal(...args: unknown[]): void {\n this.print('fatal', args);\n }\n\n /**\n * Logs an error message with \"error\" level\n *\n * Use for runtime errors, exceptions, and error conditions that don't necessarily\n * cause application termination but indicate a failure\n *\n * @param args - Message content followed by optional context object\n *\n * @example\n * // Simple error logging\n * logger.error('Failed to process payment');\n *\n * @example\n * // Error with exception details\n * try {\n * // Some operation\n * } catch (err) {\n * logger.error('Operation failed', {\n * error: err.message,\n * stack: err.stack,\n * code: err.code\n * });\n * }\n *\n * @note Error logs should provide enough context to diagnose the problem\n */\n error(...args: unknown[]): void {\n this.print('error', args);\n }\n\n /**\n * Logs a warning message with \"warn\" level\n *\n * Use for potentially problematic situations, deprecated features usage,\n * or unexpected conditions that don't cause failures but might lead to issues\n *\n * @param args - Message content followed by optional context object\n *\n * @example\n * // Simple warning\n * logger.warn('Deprecated API being used');\n *\n * @example\n * // Warning with context\n * logger.warn('High memory usage detected', {\n * memoryUsage: process.memoryUsage().heapUsed,\n * threshold: maxMemoryThreshold\n * });\n *\n * @note Warnings shouldn't be ignored in production systems as they often indicate future problems\n */\n warn(...args: unknown[]): void {\n this.print('warn', args);\n }\n\n /**\n * Logs an informational message with \"info\" level\n *\n * Use for general application state, notable events in application flow,\n * startup messages, configuration details, or business process completions\n *\n * @param args - Message content followed by optional context object\n *\n * @example\n * // Simple info message\n * logger.info('Server started on port 3000');\n *\n * @example\n * // Info with context\n * logger.info('User registration complete', {\n * userId: user.id,\n * email: user.email,\n * registrationTime: new Date().toISOString()\n * });\n *\n * @note Info level is typically the default level in production environments\n */\n info(...args: unknown[]): void {\n this.print('info', args);\n }\n\n /**\n * Logs a debug message with \"debug\" level\n *\n * Use for detailed information useful during development and troubleshooting\n * Such as variable values, function calls, or internal application state\n *\n * @param args - Message content followed by optional context object\n *\n * @example\n * // Simple debug message\n * logger.debug('Processing request payload');\n *\n * @example\n * // Debug with detailed context\n * logger.debug('API request received', {\n * method: req.method,\n * path: req.path,\n * params: req.params,\n * query: req.query,\n * headers: req.headers,\n * body: req.body\n * });\n *\n * @note Debug logs are typically disabled in production environments\n * @important Debug logs can contain sensitive information, use caution in production\n */\n debug(...args: unknown[]): void {\n this.print('debug', args);\n }\n\n /**\n * Logs a trace message with \"trace\" level\n *\n * Use for the most detailed diagnostic information\n * Such as function entry/exit points, variable transformations, or method call tracing\n *\n * @param args - Message content followed by optional context object\n *\n * @example\n * // Function entry tracing\n * logger.trace('Entering validateUser function', { username });\n *\n * @example\n * // Detailed algorithmic tracing\n * logger.trace('Processing array element', {\n * index: i,\n * value: array[i],\n * transformedValue: processedValue,\n * processingTime: endTime - startTime\n * });\n *\n * @note Trace is the most verbose level and should only be enabled temporarily for debugging\n * @important Trace logs can significantly impact performance and generate large volumes of data\n */\n trace(...args: unknown[]): void {\n this.print('trace', args);\n }\n}\n","import { HandlerInterface } from './interface/HandlerInterface';\nimport { FormatterInterface } from './interface/FormatterInterface';\nimport { LogEvent } from './interface/LogEvent';\n\nexport class ConsoleHandler implements HandlerInterface {\n constructor(protected formatter: FormatterInterface | null = null) {}\n\n /**\n * Set formatter\n *\n * @override\n * @param formatter\n */\n setFormatter(formatter: FormatterInterface): void {\n this.formatter = formatter;\n }\n\n /**\n * Append log event\n *\n * @override\n * @param event\n */\n append(event: LogEvent): void {\n const { level, args } = event;\n\n const formattedArgs = this.formatter ? this.formatter.format(event) : args;\n\n (\n console[level as 'log' | 'error' | 'warn' | 'info' | 'debug' | 'trace'] ||\n console.log\n )(...(Array.isArray(formattedArgs) ? formattedArgs : [formattedArgs]));\n }\n}\n","import type { FormatterInterface } from './interface/FormatterInterface';\nimport { LogEvent } from './interface/LogEvent';\n\nexport type DateFormatType = 'date' | 'time' | 'datetime';\n\nexport interface TimestampFormatterContext {\n /**\n * The format type to use for the timestamp.\n * @default 'datetime'\n */\n formatType?: DateFormatType;\n}\n\nexport type TimestampFormatterOptions = {\n /**\n * The locale to use for the timestamp.\n * @default 'zh-CN'\n */\n locale?: string;\n\n /**\n * The template to use for the prefix.\n *\n * support variables:\n * - timestamp\n * - formattedTimestamp\n * - level\n * - loggerName\n * - locale\n * - TimestampFormatterContext\n *\n * @default '[{formattedTimestamp} {level}]'\n */\n prefixTemplate?: string;\n\n localeOptions?: Intl.DateTimeFormatOptions;\n};\n\nconst defaultLocaleOptions: Intl.DateTimeFormatOptions = {\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n hour12: false,\n timeZone: 'UTC'\n};\n\nexport class TimestampFormatter implements FormatterInterface {\n constructor(protected readonly options: TimestampFormatterOptions = {}) {}\n\n protected replacePrefix(\n template: string,\n vars: Record<string, string>\n ): string {\n return template.replace(/\\{([^{}]+)\\}/g, (match, p1) => vars[p1] || match);\n }\n\n format({ timestamp, level, args, context, loggerName }: LogEvent): unknown[] {\n const {\n locale = 'zh-CN',\n localeOptions,\n prefixTemplate = '[{formattedTimestamp} {level}]'\n } = this.options;\n\n const formatType =\n (context as TimestampFormatterContext)?.formatType ?? 'datetime';\n\n const dateFormatMethod =\n formatType === 'date'\n ? 'toLocaleDateString'\n : formatType === 'time'\n ? 'toLocaleTimeString'\n : 'toLocaleString';\n\n const formattedTimestamp = new Date(timestamp)[dateFormatMethod](locale, {\n ...defaultLocaleOptions,\n ...localeOptions\n });\n\n return [\n this.replacePrefix(prefixTemplate, {\n ...(context as TimestampFormatterContext),\n timestamp: timestamp.toString(),\n level,\n loggerName,\n formattedTimestamp,\n locale\n }),\n ...args\n ];\n }\n}\n"],"mappings":"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","names":[]}
{"version":3,"sources":["../src/interface/LogEvent.ts","../src/interface/LogContext.ts","../src/Logger.ts","../src/ConsoleHandler.ts","../src/TimestampFormatter.ts"],"sourcesContent":["import { LogContext } from \"./LogContext\";\n\nexport class LogEvent<Ctx = unknown> {\n public timestamp: number;\n\n constructor(\n public level: string,\n public args: unknown[],\n public loggerName: string,\n public context?: LogContext<Ctx>\n ) {\n this.timestamp = Date.now();\n }\n}\n","export class LogContext<Value> {\n constructor(public value?: Value) {}\n}\n","import { LoggerInterface } from './interface/LoggerInterface';\nimport { HandlerInterface } from './interface/HandlerInterface';\nimport { LogEvent } from './interface/LogEvent';\nimport { LogContext } from './interface/LogContext';\n\n/**\n * Default log levels with their priorities (lower number = higher priority)\n *\n * This defines the standard hierarchy of logging levels:\n * - fatal (0): System is unusable, application crashes\n * - error (1): Error events that might still allow the application to continue running\n * - warn (2): Potentially harmful situations that don't cause application failure\n * - info (3): Informational messages highlighting application progress\n * - debug (4): Detailed information useful for debugging\n * - trace (5): Most granular information for very detailed diagnostics\n * - log (6): General purpose logging (alias for info)\n *\n * @type {Object.<string, number>}\n */\nexport const defaultLevels = {\n fatal: 0,\n error: 10,\n warn: 20,\n info: 30,\n debug: 40,\n trace: 50,\n log: 60\n};\n\n/**\n * Configuration options for the Logger\n */\nexport type LoggerOptions = {\n /**\n * Silent mode - when true, no logs will be output regardless of level\n * Useful for completely disabling logging in production or test environments\n * without changing the code.\n *\n * @default false\n */\n silent?: boolean;\n\n /**\n * Custom log levels with numeric priority values\n * Lower numbers indicate higher priority levels (0 is highest priority)\n *\n * You can define your own custom levels or override the default ones.\n *\n * @important When defining custom levels, ensure consistency across your application\n * @default defaultLevels\n * @example\n * {\n * critical: 0,\n * serious: 1,\n * important: 2,\n * normal: 3,\n * verbose: 4\n * }\n */\n levels?: Record<string, number>;\n\n /**\n * Current log level threshold\n * Only logs with a level priority <= this level's priority will be processed\n *\n * @important Setting level to \"info\" means info, warn, error, and fatal logs will be output,\n * while debug and trace will be filtered out\n * @example \"info\" - Will output info, warn, error, and fatal logs\n * @example \"debug\" - Will output all logs except trace\n */\n level?: string;\n\n /**\n * Logger instance identifier\n * Used to identify the source of log messages, especially useful when using multiple loggers\n *\n * @default Date.now().toString()\n * @example \"api-server\", \"payment-process\", \"user-service\"\n */\n name?: string;\n\n /**\n * Log handlers that process and output the log events\n * Can be a single handler or an array of handlers\n *\n * Handlers determine how and where logs are output (console, file, network, etc.)\n *\n * @example [new ConsoleHandler(), new FileAppender('./logs/app.log')]\n */\n handlers?: HandlerInterface | HandlerInterface[];\n};\n\n/**\n * Main Logger class that implements the LoggerInterface\n * Processes log events and distributes them to registered handlers\n *\n * This class follows a flexible logging architecture where:\n * 1. Log events are created based on severity level\n * 2. Events are filtered according to configured level thresholds\n * 3. Approved events are passed to handlers for formatting and output\n *\n * @implements {LoggerInterface}\n * @example\n * // Basic usage\n * const logger = new Logger({ level: 'info' });\n * logger.addAppender(new ConsoleHandler());\n * logger.info('Application started');\n *\n * @example\n * // Advanced usage with context\n * logger.error('Payment failed', {\n * userId: 123,\n * amount: 50.25,\n * currency: 'USD',\n * error: new Error('Insufficient funds')\n * });\n */\nexport class Logger implements LoggerInterface {\n /**\n * Creates a new Logger instance\n *\n * @param options - Configuration options for the logger\n *\n * @note If no name is provided, a timestamp-based name will be generated\n * @note If no levels are provided, defaultLevels will be used\n * @note If no handlers are provided, an empty array will be used (silent logging)\n */\n constructor(protected options: LoggerOptions = {}) {\n options.name = options.name || Date.now().toString();\n options.levels = options.levels || defaultLevels;\n\n options.handlers = Array.isArray(options.handlers)\n ? options.handlers\n : options.handlers\n ? [options.handlers]\n : [];\n }\n\n /**\n * Adds a new log handler to the logger\n *\n * Handlers are responsible for actually outputting log messages (to console, files, etc.)\n * Multiple handlers can be registered to send logs to different destinations simultaneously.\n *\n * @override Implementation of LoggerInterface\n * @param appender - Handler instance to add\n *\n * @example\n * logger.addAppender(new ConsoleHandler());\n * logger.addAppender(new FileAppender('./logs/errors.log', { level: 'error' }));\n *\n * @note Handlers are processed in the order they are added\n * @important This method is named 'addAppender' for legacy/compatibility reasons,\n * but it works with any object implementing HandlerInterface\n */\n addAppender(appender: HandlerInterface): void {\n (this.options.handlers as HandlerInterface[]).push(appender);\n }\n\n /**\n * Creates a new LogContext instance\n *\n * @override\n * @since 0.1.0\n * @param value - Optional value to be stored in the context\n * @returns A new LogContext instance with the provided value\n */\n context<Value>(value?: Value): LogContext<Value> {\n return new LogContext(value);\n }\n\n /**\n * Internal method to process and distribute log events\n *\n * This method:\n * 1. Checks if logging is silenced\n * 2. Extracts context from arguments if present\n * 3. Applies level filtering based on configured threshold\n * 4. Creates a LogEvent and distributes it to all handlers\n *\n * @protected\n * @param level - Log level name (e.g., \"info\", \"error\")\n * @param args - Log message arguments (message content and optional context)\n *\n * @example context\n * ```ts\n * logger.info('message with context', logger.context({ user: 'testUser', requestId: '123' }));\n * logger.info('message with context', logger.context([1,2,3]));\n * logger.info('message with context', logger.context(1));\n * logger.info('message with context', logger.context('1'));\n * logger.info('message with context', logger.context(true));\n * logger.info('message with context', logger.context());\n * ```\n *\n * **But context only support last argument and must be a non-null object**\n *\n * @note Context object must be the last argument and must be a non-null object\n * @note Context can override the log level via a 'level' property\n * @important This method is not meant to be called directly - use the specific level methods instead\n */\n protected print(level: string, args: unknown[]): void {\n const { levels, level: indexLevel, silent, handlers } = this.options;\n\n // Skip logging if in silent mode\n if (silent) {\n return;\n }\n\n // Extract context object from arguments if present\n let ctx = args.slice(-1)[0] as LogContext<unknown> | undefined;\n const hasCtx = args.length > 1 && ctx instanceof LogContext;\n ctx = hasCtx ? ctx : undefined;\n args = hasCtx ? args.slice(0, -1) : args;\n\n // Allow level override from context, if a plain object is provided\n level = (ctx?.value as { level?: string })?.level ?? level;\n\n // Apply level filtering based on configured threshold\n if (indexLevel && levels) {\n const target = levels[indexLevel!];\n const current = levels[level];\n if (target != null && current != null && current > target) {\n return;\n }\n }\n\n // Create and distribute log event to all handlers\n const logEvent = new LogEvent(level, args, this.options.name!, ctx);\n\n for (const handler of handlers as HandlerInterface[]) {\n handler.append(logEvent);\n }\n }\n\n /**\n * Logs a message with \"info\" level\n * Alias for info() method\n *\n * General purpose logging method, categorized as \"info\" level\n *\n * @param args - Message content followed by optional context object\n *\n * @example\n * // Simple usage\n * logger.log('User logged in');\n *\n * @example\n * // With context object\n * logger.log('User logged in', { userId: 123, timestamp: Date.now() });\n *\n * @note This method uses 'info' level internally, but appears as 'log' in default levels\n */\n log(...args: unknown[]): void {\n this.print('info', args);\n }\n\n /**\n * Logs a critical error message with \"fatal\" level\n *\n * Use for severe errors that lead to application termination or require immediate attention\n * This is the highest severity level and will always be logged unless silent mode is enabled\n *\n * @param args - Message content followed by optional context object\n *\n * @example\n * logger.fatal('Database connection failed, application cannot continue');\n *\n * @example\n * try {\n * // Critical operation\n * } catch (error) {\n * logger.fatal('Critical system failure', { error, stack: error.stack });\n * process.exit(1);\n * }\n *\n * @important Fatal logs typically indicate that the application cannot continue to function\n */\n fatal(...args: unknown[]): void {\n this.print('fatal', args);\n }\n\n /**\n * Logs an error message with \"error\" level\n *\n * Use for runtime errors, exceptions, and error conditions that don't necessarily\n * cause application termination but indicate a failure\n *\n * @param args - Message content followed by optional context object\n *\n * @example\n * // Simple error logging\n * logger.error('Failed to process payment');\n *\n * @example\n * // Error with exception details\n * try {\n * // Some operation\n * } catch (err) {\n * logger.error('Operation failed', {\n * error: err.message,\n * stack: err.stack,\n * code: err.code\n * });\n * }\n *\n * @note Error logs should provide enough context to diagnose the problem\n */\n error(...args: unknown[]): void {\n this.print('error', args);\n }\n\n /**\n * Logs a warning message with \"warn\" level\n *\n * Use for potentially problematic situations, deprecated features usage,\n * or unexpected conditions that don't cause failures but might lead to issues\n *\n * @param args - Message content followed by optional context object\n *\n * @example\n * // Simple warning\n * logger.warn('Deprecated API being used');\n *\n * @example\n * // Warning with context\n * logger.warn('High memory usage detected', {\n * memoryUsage: process.memoryUsage().heapUsed,\n * threshold: maxMemoryThreshold\n * });\n *\n * @note Warnings shouldn't be ignored in production systems as they often indicate future problems\n */\n warn(...args: unknown[]): void {\n this.print('warn', args);\n }\n\n /**\n * Logs an informational message with \"info\" level\n *\n * Use for general application state, notable events in application flow,\n * startup messages, configuration details, or business process completions\n *\n * @param args - Message content followed by optional context object\n *\n * @example\n * // Simple info message\n * logger.info('Server started on port 3000');\n *\n * @example\n * // Info with context\n * logger.info('User registration complete', {\n * userId: user.id,\n * email: user.email,\n * registrationTime: new Date().toISOString()\n * });\n *\n * @note Info level is typically the default level in production environments\n */\n info(...args: unknown[]): void {\n this.print('info', args);\n }\n\n /**\n * Logs a debug message with \"debug\" level\n *\n * Use for detailed information useful during development and troubleshooting\n * Such as variable values, function calls, or internal application state\n *\n * @param args - Message content followed by optional context object\n *\n * @example\n * // Simple debug message\n * logger.debug('Processing request payload');\n *\n * @example\n * // Debug with detailed context\n * logger.debug('API request received', {\n * method: req.method,\n * path: req.path,\n * params: req.params,\n * query: req.query,\n * headers: req.headers,\n * body: req.body\n * });\n *\n * @note Debug logs are typically disabled in production environments\n * @important Debug logs can contain sensitive information, use caution in production\n */\n debug(...args: unknown[]): void {\n this.print('debug', args);\n }\n\n /**\n * Logs a trace message with \"trace\" level\n *\n * Use for the most detailed diagnostic information\n * Such as function entry/exit points, variable transformations, or method call tracing\n *\n * @param args - Message content followed by optional context object\n *\n * @example\n * // Function entry tracing\n * logger.trace('Entering validateUser function', { username });\n *\n * @example\n * // Detailed algorithmic tracing\n * logger.trace('Processing array element', {\n * index: i,\n * value: array[i],\n * transformedValue: processedValue,\n * processingTime: endTime - startTime\n * });\n *\n * @note Trace is the most verbose level and should only be enabled temporarily for debugging\n * @important Trace logs can significantly impact performance and generate large volumes of data\n */\n trace(...args: unknown[]): void {\n this.print('trace', args);\n }\n}\n","import { HandlerInterface } from './interface/HandlerInterface';\nimport { FormatterInterface } from './interface/FormatterInterface';\nimport { LogEvent } from './interface/LogEvent';\n\nexport class ConsoleHandler implements HandlerInterface {\n constructor(protected formatter: FormatterInterface | null = null) {}\n\n /**\n * Set formatter\n *\n * @override\n * @param formatter\n */\n setFormatter(formatter: FormatterInterface): void {\n this.formatter = formatter;\n }\n\n /**\n * Append log event\n *\n * @override\n * @param event\n */\n append(event: LogEvent): void {\n const { level, args } = event;\n\n const formattedArgs = this.formatter ? this.formatter.format(event) : args;\n\n (\n console[level as 'log' | 'error' | 'warn' | 'info' | 'debug' | 'trace'] ||\n console.log\n )(...(Array.isArray(formattedArgs) ? formattedArgs : [formattedArgs]));\n }\n}\n","import type { FormatterInterface } from './interface/FormatterInterface';\nimport { LogEvent } from './interface/LogEvent';\n\nexport type DateFormatType = 'date' | 'time' | 'datetime';\n\nexport interface TimestampFormatterContext {\n /**\n * The format type to use for the timestamp.\n * @default 'datetime'\n */\n formatType?: DateFormatType;\n}\n\nexport type TimestampFormatterOptions = {\n /**\n * The locale to use for the timestamp.\n * @default 'zh-CN'\n */\n locale?: string;\n\n /**\n * The template to use for the prefix.\n *\n * support variables:\n * - timestamp\n * - formattedTimestamp\n * - level\n * - loggerName\n * - locale\n * - TimestampFormatterContext\n *\n * @default '[{formattedTimestamp} {level}]'\n */\n prefixTemplate?: string;\n\n localeOptions?: Intl.DateTimeFormatOptions;\n};\n\nconst defaultLocaleOptions: Intl.DateTimeFormatOptions = {\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n hour12: false,\n timeZone: 'UTC'\n};\n\nexport class TimestampFormatter implements FormatterInterface {\n constructor(protected readonly options: TimestampFormatterOptions = {}) {}\n\n protected replacePrefix(\n template: string,\n vars: Record<string, string>\n ): string {\n return template.replace(/\\{([^{}]+)\\}/g, (match, p1) => vars[p1] || match);\n }\n\n format({ timestamp, level, args, context, loggerName }: LogEvent): unknown[] {\n const {\n locale = 'zh-CN',\n localeOptions,\n prefixTemplate = '[{formattedTimestamp} {level}]'\n } = this.options;\n\n const formatType =\n (context as TimestampFormatterContext)?.formatType ?? 'datetime';\n\n const dateFormatMethod =\n formatType === 'date'\n ? 'toLocaleDateString'\n : formatType === 'time'\n ? 'toLocaleTimeString'\n : 'toLocaleString';\n\n const formattedTimestamp = new Date(timestamp)[dateFormatMethod](locale, {\n ...defaultLocaleOptions,\n ...localeOptions\n });\n\n return [\n this.replacePrefix(prefixTemplate, {\n ...(context as TimestampFormatterContext),\n timestamp: timestamp.toString(),\n level,\n loggerName,\n formattedTimestamp,\n locale\n }),\n ...args\n ];\n }\n}\n"],"mappings":"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","names":[]}

Sorry, the diff of this file is too big to display