@qlover/logger
Advanced tools
| "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
@@ -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}); |
+354
-7
@@ -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 |
+6
-5
| { | ||
| "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
AI-detected possible typosquat
Supply chain riskAI has identified this package as a potential typosquat of a more popular package. This suggests that the package may be intentionally mimicking another package's name, description, or other metadata.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
116693
21.95%3291
169.53%8
-11.11%3
200%7
600%4
Infinity%