Gathering detailed insights and metrics for ps-chronicle
Gathering detailed insights and metrics for ps-chronicle
Gathering detailed insights and metrics for ps-chronicle
Gathering detailed insights and metrics for ps-chronicle
npm install ps-chronicle
Typescript
Module System
Node Version
NPM Version
Cumulative downloads
Total Downloads
1
2
A robust, extensible logger for Node.js, built on top of Winston. Designed for eGain PS and multi-tenant applications, with support for JSON and simple log formats, custom log levels, and per-request context.
2024-06-01T17:45:23.123Z
)LogFormat.SIMPLE
.setLogLevel()
1npm install ps-chronicle
This package supports both CommonJS (require
) and ESM (import
) usage out of the box. Node.js and modern bundlers will automatically use the correct build for your environment.
1// In Node.js or legacy projects 2const { PsChronicleLogger, LogLevel, LogFormat } = require('ps-chronicle');
1// In ESM projects or with "type": "module" 2import { PsChronicleLogger, LogLevel, LogFormat } from 'ps-chronicle';
1const { PsChronicleLogger, LogLevel, LogFormat } = require('ps-chronicle');
or (ESM):
1import { PsChronicleLogger, LogLevel, LogFormat } from 'ps-chronicle';
1const logger = new PsChronicleLogger({ 2 fileName: 'myfile.js', // Optional: will be included in log output 3 logLevel: LogLevel.INFO, // Optional: default is LogLevel.DEBUG 4 format: LogFormat.JSON, // Optional: 'json' (default) or 'simple' 5 sensitiveKeys: ['password', 'token', 'secret', 'apiKey', 'authorization'], // Optional: customize redacted fields (merged with defaults, case-insensitive) 6 colorize: true, // Optional: enable colorized console output (only applies to LogFormat.SIMPLE) 7 redactionString: '***' // Optional: string to use for redacted fields (default: ***) 8}); 9// Note: If you use colorize: true with LogFormat.JSON, colorization will be ignored and a warning will be shown.
1logger.setRequestId(context.awsRequestId); // e.g., from AWS Lambda context.awsRequestId
2logger.setCustomerName('TMXXXX'); // Set the customer/tenant name
3logger.setMethodName('myFunction()'); // Set the current method name
Note: Global context (customerName, requestId) is set via instance methods. These values are shared across all logger instances.
1logger.log(LogLevel.INFO, 'Informational message', { foo: 'bar' }); 2logger.log(LogLevel.ERROR, 'Error occurred', { error: new Error('Something went wrong') });
If your function is async (e.g., AWS Lambda), ensure all logs are flushed before exit:
1await logger.waitForLogger();
You can enable colorized log output in the console for easier reading during development or debugging. This is especially useful with LogFormat.SIMPLE
.
Note: The colorize
option only applies to LogFormat.SIMPLE
. If you use colorize: true
with LogFormat.JSON
, colorization will be ignored and a warning will be shown.
Example:
1const logger = new PsChronicleLogger({ 2 fileName: 'color-demo.js', 3 logLevel: LogLevel.DEBUG, 4 format: LogFormat.SIMPLE, // Use SIMPLE for colorized output 5 colorize: true 6}); 7 8logger.log(LogLevel.INFO, 'This is an info message'); 9logger.log(LogLevel.WARN, 'This is a warning'); 10logger.log(LogLevel.ERROR, 'This is an error'); 11logger.log(LogLevel.DEBUG, 'This is a debug message');
LogFormat.JSON
, colorization is ignored.You can easily log operation durations and memory usage to monitor and optimize your application's performance.
1const start = logger.startTimer();
2// ... your code ...
3logger.logPerformance('DB query', start);
1await logger.measurePerformance('fetchData', async () => { 2 await fetchData(); 3});
1logger.logMemoryUsage('After processing');
Use cases:
When you log an error object, the logger will automatically serialize it to include only the most relevant fields:
name
, message
, stack
, status
, code
, and any primitive custom fields[Object]
or [Array]
Example:
1try { 2 // ... 3} catch (err) { 4 logger.log(LogLevel.ERROR, 'API call failed', { error: err }); 5}
Output:
1{ 2 "level": "error", 3 "message": "API call failed", 4 "xadditionalInfo": { 5 "error": { 6 "name": "Error", 7 "message": "Something went wrong", 8 "stack": "...", 9 "status": 500, 10 "code": "E_API_FAIL", 11 "details": "[Object]" 12 } 13 }, 14 "timestamp": "2024-06-01T17:45:23.123Z" 15}
You can change the log level at runtime for a logger instance:
1logger.setLogLevel(LogLevel.ERROR); // Only log errors and above from now on 2logger.setLogLevel(LogLevel.DEBUG); // Log everything from debug and above
You can automatically redact sensitive fields (such as password
, token
, secret
, apiKey
, authorization
) from your log output. By default, these fields are redacted as ***
, but you can customize the string using the redactionString
option in the constructor. Custom keys are merged with the defaults, and redaction is case-insensitive.
Example:
1const logger = new PsChronicleLogger({ 2 fileName: 'example2.js', 3 logLevel: LogLevel.INFO, 4 format: LogFormat.JSON, 5 sensitiveKeys: ['Authorization', 'PASSWORD'], // Custom keys (case-insensitive, merged with defaults) 6 redactionString: '***' // Optional: string to use for redacted fields (default: ***) 7}); 8 9logger.log(LogLevel.INFO, 'Logging user data', { 10 username: 'alice', 11 password: 'supersecret', 12 token: 'abc123', 13 Authorization: 'Bearer xyz', 14 profile: { 15 apiKey: 'my-api-key', 16 nested: { secret: 'hidden', PASSWORD: 'another' } 17 } 18});
Output:
1{ 2 "level": "info", 3 "message": "Logging user data", 4 "xadditionalInfo": { 5 "username": "alice", 6 "password": "***", 7 "token": "***", 8 "Authorization": "***", 9 "profile": { 10 "apiKey": "***", 11 "nested": { "secret": "***", "PASSWORD": "***" } 12 } 13 }, 14 "timestamp": "2024-06-01T17:45:23.123Z" 15}
redactionString
option is optional. If not provided, the default is ***
.timestamp
field is always in ISO 8601 (24-hour) format.1new PsChronicleLogger(options)
options.fileName
(string, optional): File name to include in logsoptions.logLevel
(LogLevel, optional): Minimum log level (default: DEBUG)options.format
(LogFormat, optional): Log output format (default: JSON)options.transports
(array, optional): Custom Winston transportsoptions.sensitiveKeys
(array, optional): List of sensitive keys to redact from log output (merged with defaults, case-insensitive)options.colorize
(boolean, optional): Enable colorized console output (for development/debugging)options.redactionString
(string, optional): String to use for redacted sensitive fields (default: ***)setRequestId(requestId: string)
setCustomerName(customerName: string)
setMethodName(methodName: string)
log(level: LogLevel, message: string, ...meta: object[])
waitForLogger(): Promise<void>
startTimer(): number
— Start a timer for performance measurementlogPerformance(operation: string, startTime: number, extraMeta?: object)
— Log the duration of an operationmeasurePerformance(operation: string, fn: () => Promise<T>, extraMeta?: object)
— Measure and log the duration of an async functionlogMemoryUsage(label?: string)
— Log current memory usagesetLogLevel(level: LogLevel)
— Dynamically change the log level for this logger instancegetLogLevel(): LogLevel
— Get the current log levelisLevelEnabled(level: LogLevel): boolean
— Check if a log level is enabledgetMethodName(): string
— Get the current method namegetCustomerName(): string | undefined
— Get the global customer namegetRequestId(): string | undefined
— Get the global request IDLogLevel
: ERROR
, WS_PAYLOAD
, INFO
, WARN
, DEBUG
LogFormat
: JSON
, SIMPLE
If you have expensive computations for log metadata, you can avoid unnecessary work by checking if a log level is enabled before building the log message. Use the isLevelEnabled(level)
method:
1if (logger.isLevelEnabled(LogLevel.DEBUG)) { 2 logger.log(LogLevel.DEBUG, 'Debug info', expensiveMeta()); 3}
This ensures that expensive work is only performed if the log will actually be emitted at the current log level.
You can set customerName
and requestId
globally for all logger instances using the instance methods:
1logger.setCustomerName('AcmeCorp'); 2logger.setRequestId('req-123');
The log
method always places additional metadata under the xadditionalInfo
key. The structure depends on what you pass:
xadditionalInfo
:
1logger.log(LogLevel.INFO, 'User info', { userId: 123, name: 'Alice' }); 2// { ..., "xadditionalInfo": { "userId": 123, "name": "Alice" } }
{ '0': [value] }
under xadditionalInfo
:
1logger.log(LogLevel.INFO, 'Document retrieved', 'Document retrieved successfully'); 2// { ..., "xadditionalInfo": { "0": ["Document retrieved successfully"] } }
{ '0': [array of values] }
under xadditionalInfo
:
1logger.log(LogLevel.INFO, 'IDs', 'a', 'b', 'c'); 2// { ..., "xadditionalInfo": { "0": ["a", "b", "c"] } }
0
field under xadditionalInfo
:
1logger.log(LogLevel.INFO, 'User info', { userId: 123 }, 'extra1', 42); 2// { ..., "xadditionalInfo": { "userId": 123, "0": ["extra1", 42] } }
This makes it easy to log any kind of metadata without worrying about how to wrap your values.
ISC
No vulnerabilities found.
No security vulnerabilities found.
Last Day
0%
NaN
Compared to previous day
Last Week
0%
NaN
Compared to previous week
Last Month
0%
NaN
Compared to previous month
Last Year
0%
NaN
Compared to previous year