Vanilla TypeScript Logger with multiple output channels
npm install @tsjam/loggerVanilla TypeScript Logger
Not opinionated ts Logger with Multiple output channels 🍰
Useful for parallel console output & remote monitoring 👩🚀





Advantages:
- appId (distinguish log between multiple app instances)
- timestamps (milliseconds matter)
- hashtags (tag child loggers, find and filter certain logs super-fast)
- multiple channels output (add ur own output: e.g. parallel console output & remote monitoring)
- metadata (for all log entries per appId or per call e.g. { userId: 007 })
- buffering (useful for crash reporting)
- fully customizable (use your own log format)
- fair Errors serialization into string (check JSON.stringify(new Error('Oops')); // {})
- sanitization of sensitive fields (perf optimized, Logs.sanitize({ password: 'ABC' }))
- safe stringify payload at any moment (Logs.stringify(data))
- trim stack to number of lines or fully cut (use config { trimStack: 2 })
- zero third-party dependencies
Output example: [app161125][2024-01-21T18:33:02.981Z][info][#user] Logged In: { username: Bob, password: '*' }
```
npm install @tsjam/logger
---
ConsoleOutput is the default output channel. Specify Ur own ones if needed...
`typescript
import { jamLogger } from '@tsjam/logger';
jamLogger.info('Hello Logger!');
// [app161125][2024-01-21T18:33:02.981Z][info] Hello Logger!
`
Tag child loggers to easily filter logs by tags.
`typescript
const logger = jamLogger.tagged('user'); // child logger with added tags
logger.info('Greetings for', { name: 'Bob' });
// [app161125][2024-01-21T18:33:02.981Z][info][#user] Greetings for { name: 'Bob' }
`
`typescriptioApp${Date.now()}
const logger = JamLogger.create({
appId: ,`
channels: [...defaultOutputChannels / { out: MyKibanaOutput } /], // default is ConsoleOutput
});
const aiLogger = logger.tagged('ai'); // child logger with #ai tag
`typescript
const myOutput: LogOutput = {
write: ({ appId, date, level, message, data, context }: LogEntry) => {
// Format raw log entry and send it anywhere U wish
},
};
const logger = JamLogger.create({
channels: [...defaultOutputChannels, { out: myOutput }, { out: myKibanaOutput }],
});
`
Use simplistic BufferOutput to buffer logs for any crash reporting or remote monitoring.flush
Do not forget to after report is sent.
`typescript`
const logBuffer = new BufferOutput(2000);
const logger = JamLogger.create({
channels: [...defaultOutputChannels, { out: logBuffer }],
});
Metadata is especially useful for remote reporting & monitoring.
`typescript
import { JamLogger } from '@tsjam/logger';
const logger = JamLogger.create({
metadata: { userId: '007' }, // use it however U wish in ur output channel next to log entry
});
//...
JamLogger.updateMeta(logger.appId, { userId: '456' }); // update metadata
logger.info('Lets Play 🦑');
// [app1737064023840][2025-01-16T21:47:03.840Z][info] Lets Play 🦑
// meta: {"userId":"456"}
`
Pass additional meta per call.
`typescript`
const logger = JamLogger.create({
metadata: { userId: '007' }, // use it however U wish in ur output channel next to log entry
});
logger.info('Whats Up?', LogMeta.bake({ drink: 'dry martini 🍸' }));
// [app170723][2025-01-16T23:10:56.102Z][info] Whats Up?
// meta: { "userId": "007", "drink": "dry martini 🍸" }
`typescript`
jamLogger.debug('Logged in', Loges.sanitize({ name: 'Bob', password: 'ABC' }));
// [app170723][2024-02-06T16:47:56.398Z][debug] Logged in { name: 'Bob', password: '*' }
Note: to always sanitize sensitive fields use sanitizeSensitiveTranslator config option.
Yet it's more perf optimized to sanitize only when needed.
Stack is shown on Error payloads (similar to console.log);
`typescript`
jamLogger.warn('Oops!', new Error('Something went wrong'));
// [app170723][2024-02-06T17:02:00.108Z][warn] Oops Error: Something went wrong
// at Object.
// at Promise.then.completed (...tsjam-logger/node_modules/jest-circus/build/utils.js:298:28)
// ...
Hide stack on Error payloads for specified levels
`typescript
const logger = JamLogger.create({ errorStackLevel: LogLevel.Error }); // default WARN
logger.warn('Oops!', new Error('Something went wrong'));
// [app170723][2024-02-06T17:02:00.108Z][warn] Oops Error: Something went wrong
`
Trim stack to few lines
`typescript`
const logger = JamLogger.create({ trimStack: 2 });
logger.warn('Oops!', new Error('Spoiled the milk!'));
// [app170723][2024-02-06T17:13:59.496Z][warn] Oops! Spoiled the milk! Stack:
// at Object.
// ...
Note: it's also possible to trim the stack to specified depth via trimStack
---
There are some built-in translators for log data u could use while baking ur own logger:
- jsonStringifyTranslator – safely stringify log data Logs.stringify(data)stringifyErrorStackTranslator
- – fairly serialize Error correctly Logs.stringifyError(error)sanitizeSensitiveTranslator
- - sanitize sensitive fields defaults: ['password', 'token', 'secret', 'sessionId']`
Note: These translators applied either to a Single log call or to All logs by default, U could add Ur own too.
Note: U could add custom translator if U need one for all channels transformation.
Otherwise, it's recommended to process raw logEntry in Ur particular output channel.
---
@tsjam/logger is MIT licensed
---
@seeAlso