Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
45d8812
feat(create-json-log-object-data): improved handling of logged error …
mumenthalers Jan 19, 2026
c575382
feat(console-json-log-transport): expose consoleJsonLogTransport
mumenthalers Jan 19, 2026
ac173c3
feat(node-console-log-transport): expose NodeConsoleLogTransport
mumenthalers Jan 19, 2026
0739de1
style(logger): format all
mumenthalers Jan 19, 2026
7cf0790
build(release): next version [skip_build]
actions-user Jan 19, 2026
d0e6f2b
feat(create-console-logger): utility to simply create a console logge…
mumenthalers Jan 19, 2026
0c897a0
build(release): next version [skip_build]
actions-user Jan 19, 2026
f1a97c6
test(create-console-logger): test it
mumenthalers Jan 19, 2026
fd5bd12
build(release): next version [skip_build]
actions-user Jan 19, 2026
9a2d025
feat(create-console-logger): default to ConsoleJsonLogTransport when …
mumenthalers Jan 20, 2026
a29a5c4
Revert "feat(create-console-logger): default to ConsoleJsonLogTranspo…
mumenthalers Jan 20, 2026
d943d38
feat(create-console-logger): add simpleLambdaLogger
mumenthalers Jan 20, 2026
431b606
build(release): next version [skip_build]
actions-user Jan 20, 2026
7edf992
refactor(logger): deep exports for transports
mumenthalers Jan 20, 2026
7177c66
build(release): next version [skip_build]
actions-user Jan 20, 2026
27e21dd
refactor(logger): deep exports for node related stuff
mumenthalers Jan 21, 2026
2bf7660
build(release): next version [skip_build]
actions-user Jan 21, 2026
d2cde15
feat(logger): expose getJsonStringifyReplacer utility
mumenthalers Jan 21, 2026
0e312d5
build(release): next version [skip_build]
actions-user Jan 21, 2026
0db825f
feat(logger): below-level buffering for console-json logger
mumenthalers Jan 23, 2026
ee039b9
style(format): why necessary?
mumenthalers Jan 23, 2026
c07ff7a
build(release): next version [skip_build]
actions-user Jan 23, 2026
551cb23
refactor(logger): utility functions
mumenthalers Jan 23, 2026
052f4c6
refactor(logger): utility functions
mumenthalers Jan 23, 2026
8edcbb8
refactor(logger): utility functions
mumenthalers Jan 23, 2026
5df0017
build(release): next version [skip_build]
actions-user Jan 23, 2026
c688c6d
refactor(console-json-log): actually implement and test logJsObject
mumenthalers Jan 23, 2026
3575396
refactor(console-json-log): actually implement and test logJsObject
mumenthalers Jan 23, 2026
52a6fc1
build(release): next version [skip_build]
actions-user Jan 23, 2026
2feec4e
refactor(node-console-logger): better emojis
mumenthalers Feb 3, 2026
9c1fc9e
docs(console-json-log-transport): describe jsonStringifyReplacer
mumenthalers Feb 3, 2026
cf38664
build(release): next version [skip_build]
actions-user Feb 3, 2026
246d0b7
style(logger-helper): rename file
mumenthalers Feb 3, 2026
e9e7b85
docs(readme): describe usage, behavior, transports and utilities
mumenthalers Feb 3, 2026
44f04a7
build(release): next version [skip_build]
actions-user Feb 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

166 changes: 148 additions & 18 deletions packages/logger/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,159 @@

> 🎯 Target runtime: es2023 ([Node >= 20](https://node.green/#ES2023))

A simple logger to use with minimal dependencies.
By default, the logger is standalone and can be easily configured to log
messages to various transports.
A simple logger to use with @shiftcode-only dependencies.
The LoggerService is standalone and can be configured to log messages to various transports.

# Usage
## Basic Usage

```typescript
import { Logger, LogLevel, LogTransport, BaseLoggerService } from '@shiftcode/logger'
import { LogLevel, BaseLoggerService, ConsoleJsonLogTransport } from '@shiftcode/logger'

// Create a transport for logging to the console with a specific log level
const transport = new LogTransport(
LogLevel.DEBUG, // This controls the minimum log level
)
// Create a logger service with one or more transports
const loggerService = new BaseLoggerService([new ConsoleJsonLogTransport({ logLevel: LogLevel.DEBUG })])

// BaseLoggerService is used to manage loggers and their transports
const baseLoggerService = new BaseLoggerService([transport])
// Get a logger instance with a name and optional color
const logger = loggerService.getInstance('MyLogger', '#abcdef')

// Create a logger instance with a specific name and color
const logger = baseLoggerService.getInstance('MyLogger', '#abcdef')
// Use the logger
logger.debug('Debug message', { someData: 'value' })
logger.info('Info message')
logger.warn('Warning message')
logger.error('Error occurred', new Error('Something went wrong'))
```

## Intended Behavior

The Following is the intended behavior - but implementation is due to the Log Transports.
Not everything is applicable to every transport.

### Message Field

- If the first argument is a string, it becomes the `message` field
- If no string message is provided but an `Error` is passed, the error's message becomes the log message

### Error Handling

- Errors can be passed at any position in the arguments
- The first `Error` found is extracted and [formatted](./src/utils/format-error.function.ts) into the `error` field with:
- `name`: Error class name
- `location`: Code location extracted from stack trace
- `message`: Error message
- `stack`: Full stack trace
- `cause`: Recursively formatted if present

### Data Handling

- **BigInt**: Automatically converted to string for JSON serialization
- **Circular References**: Detected and replaced with `<circular reference>` placeholder (see [`getJsonStringifyReplacer`](./src/utils/get-json-stringify-replacer.function.ts))
- **Map/Set**: Serialized using the default `jsonMapSetStringifyReplacer` (can be customized)
- Remaining arguments after message and error extraction are placed in the `data` field

### Message Buffering

Log messages below the configured level are buffered (default: 50 messages).
When an `ERROR` level log occurs, all buffered messages are flushed first, providing context for the error.

## Log Transports

### [ConsoleJsonLogTransport](./src/console-json-log-transport/console-json-log.transport.ts)

**Purpose**: Structured JSON logging optimized for AWS Lambda / cloud environments.

// Logging messages at different levels
logger.debug('This is a debug message')
logger.info('This is an info message')
logger.warn('This is a warning message')
logger.error('This is an error message')
Outputs logs as JSON strings (or JS objects) that can be parsed by AWS CloudWatch and other log aggregation services.

```typescript
import { ConsoleJsonLogTransport, LogLevel } from '@shiftcode/logger'

const transport = new ConsoleJsonLogTransport({ logLevel: LogLevel.INFO })
```

See [`ConsoleJsonLogTransportConfig`](./src/console-json-log-transport/console-json-log-transport-config.ts) for all options.

**Output format**:

```json
{
"level": "INFO",
"timestamp": "2024-01-15T10:30:00.000Z",
"logger": "MyService",
"message": "Processing request",
"data": { "requestId": "abc123" }
}
```

### [NodeConsoleLogTransport](./src/node/node-console-log-transport/node-console-log.transport.ts)

**Purpose**: Human-readable colored console output for local Node.js development.

Uses colorized output with emojis for log levels and `util.inspect` for object formatting.

```typescript
import { NodeConsoleLogTransport, LogLevel } from '@shiftcode/logger/node'

const transport = new NodeConsoleLogTransport({ logLevel: LogLevel.DEBUG })
```

See [`NodeConsoleLogTransportConfig`](./src/node/node-console-log-transport/node-console-log-transport-config.ts) for all options.

**Output format**:

```
🐞 10:30:00.000 - MyService :: Debug message { requestId: 'abc123' }
ℹ️ 10:30:00.001 - MyService :: Info message
⚠️ 10:30:00.002 - MyService :: Warning message
🔥 10:30:00.003 - MyService :: Error occurred
```

## Simple Lambda Logger

For AWS Lambda functions, use the [`simpleLambdaLogger`](./src/node/simple-lambda-logger.function.ts) helper that automatically selects the appropriate transport:

- **AWS Lambda environment**: Uses `ConsoleJsonLogTransport` (JSON output)
- **Local development**: Uses `NodeConsoleLogTransport` (colored console output)

```typescript
import { simpleLambdaLogger } from '@shiftcode/logger/node'
import { LogLevel } from '@shiftcode/logger'

// Automatically detects environment and uses appropriate transport
const logger = simpleLambdaLogger('MyLambdaHandler', LogLevel.DEBUG)

export const handler = async (event: any) => {
logger.info('Processing event', { eventType: event.type })

try {
// ... your logic
logger.debug('Operation completed', { result: 'success' })
} catch (error) {
// Error is automatically formatted with stack trace
logger.error('Failed to process event', error, { eventId: event.id })
throw error
}
}
```

## Utilities

### [createJsonLogObjectData](./src/utils/create-json-log-object-data.function.ts)

Creates a structured JSON log object from log arguments. This function handles the parsing and organization of log message, error, and additional data into a standardized format.

**Behavior**:

- First string argument becomes the `message` field
- First `Error` instance is extracted and formatted into the `error` field
- If no message is provided but an error exists, the error's message is used
- Remaining arguments are placed in the `data` field

### [formatError](./src/utils/format-error.function.ts)

Formats an Error object into a loggable structure with consistent attributes including name, location, message, stack trace, and recursively formatted cause chain.

### [pushToRingBuffer](./src/utils/push-to-ring-buffer.function.ts)

Pushes an item to a ring buffer array, automatically removing the oldest entry when the buffer exceeds the specified maximum size. Used for message buffering.

### [stringToColor](./src/utils/string-to-color.function.ts)

Generates a deterministic hex color code from a string. Useful for assigning consistent colors to logger instances based on their names.
22 changes: 13 additions & 9 deletions packages/logger/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@shiftcode/logger",
"version": "3.0.4",
"version": "4.0.0-pr250.11",
"description": "logger for local and aws lambda execution",
"repository": "https://github.com/shiftcode/sc-commons-public",
"license": "UNLICENSED",
Expand All @@ -9,12 +9,16 @@
"type": "module",
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
"types": "./dist/public-api.d.ts",
"default": "./dist/public-api.js"
},
"./test/*.js": {
"types": "./dist/test/*.d.ts",
"default": "./dist/test/*.js"
"./node": {
"types": "./dist/node/public-api.d.ts",
"default": "./dist/node/public-api.js"
},
"./testing": {
"types": "./dist/testing/public-api.d.ts",
"default": "./dist/testing/public-api.js"
}
},
"scripts": {
Expand All @@ -28,18 +32,18 @@
"lint:ci": "eslint ./src ./test",
"lint:staged": "eslint --fix --cache",
"prepublish": "node ../publish-helper/dist/prepare-dist.js",
"test": "NODE_OPTIONS=\"--experimental-vm-modules --trace-warnings\" npx jest --config jest.config.js",
"test": "NODE_OPTIONS=\"--experimental-vm-modules --no-warnings\" npx jest --config jest.config.js",
"test:ci": "npm run test",
"test:watch": "npm run test -- --watch"
},
"devDependencies": {
"@shiftcode/utilities": "^4.3.1"
},
"peerDependencies": {
"@shiftcode/utilities": "^4.0.0 || ^4.0.0-pr53"
"@shiftcode/utilities": "^4.0.0"
},
"engines": {
"node": "^20.0.0 || ^22.0.0"
"node": "^22.0.0 || ^24.0.0"
},
"publishConfig": {
"directory": "dist"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { LogLevel } from '../model/log-level.enum.js'

export interface ConsoleJsonLogTransportConfig {
logLevel: LogLevel

/**
* function to alter the serialization of log messages.
* additionally, {@link getJsonStringifyReplacer} is always applied to handle circular references, bigints and Errors.
* @default {@link jsonMapSetStringifyReplacer}
*/
jsonStringifyReplacer?: (key: string, value: any) => any

/**
* Log messages below the configured level will be buffered up to this size
* and flushed when a log event with level Error occurs.
* set to 0 to disable this "below-level" buffering.
* @default 50
*/
belowLevelLogBufferSize?: number

/**
* when true, the log output will be a JS object instead of a JSON string. {@jsonStringifyReplacer} is still used.
* enable this option, when your lambda function is configured with `loggingFormat='JSON'`
* @hint when loggingFormat='JSON' is set, you should also configure `applicationLogLevelV2` with `TRACE` - otherwise you won't see all logging output.
* @default false
*/
logJsObject?: boolean
}
Loading