Overview
The createLogger() function from @agentlib/logger creates a middleware that provides structured logging for the agent execution lifecycle. It logs events across all scopes (run, step, tool) with optional timing measurements.
createLogger()
Create a logger middleware instance.
import { createLogger } from '@agentlib/logger'
const logger = createLogger ( config )
agent . use ( logger )
Optional configuration object for the logger. Minimum log level to emit. One of: 'debug', 'info', 'warn', 'error', 'silent'.
Which middleware scopes to log. If not specified, all scopes are logged. Available scopes:
'run:before' - Before agent run starts
'run:after' - After agent run completes
'step:before' - Before reasoning step
'step:after' - After reasoning step
'tool:before' - Before tool execution
'tool:after' - After tool execution
Custom transport function for handling log entries. Defaults to structured console output. Function signature: (entry: LogEntry) => void
Whether to measure and log duration per scope pair (e.g., before → after).
prefix
string
default: "'[agentlib]'"
Prefix prepended to all log output when using the default transport.
Types
LogEntry
Structure of a log entry passed to the transport function.
Log level: 'debug', 'info', 'warn', 'error', or 'silent'.
The middleware scope that generated this log entry.
ISO timestamp when the log entry was created.
The user input for the current agent run.
Name of the tool being executed (for tool:* scopes).
Execution duration in milliseconds (only present in :after scopes when timing is enabled).
Additional metadata:
For tool:before: { args: Record<string, unknown> }
For tool:after: { result: unknown }
LogTransport
Custom transport function type.
type LogTransport = ( entry : LogEntry ) => void
Examples
Basic Usage
import { defineAgent } from '@agentlib/core'
import { createLogger } from '@agentlib/logger'
import { openai } from '@agentlib/openai'
const agent = defineAgent ({
name: 'assistant' ,
model: openai ( 'gpt-4' ),
})
// Add logger middleware
agent . use ( createLogger ())
const result = await agent . run ( 'Hello!' )
Output:
[agentlib] [2024-03-15T10:30:00.000Z] [INFO] scope=run:before
[agentlib] [2024-03-15T10:30:02.345Z] [INFO] scope=run:after duration=2345ms
Debug Mode
Log all events including steps and tools:
agent . use ( createLogger ({
level: 'debug' ,
timing: true
}))
Output:
[agentlib] [2024-03-15T10:30:00.000Z] [INFO] scope=run:before
[agentlib] [2024-03-15T10:30:00.100Z] [DEBUG] scope=step:before
[agentlib] [2024-03-15T10:30:00.200Z] [DEBUG] scope=tool:before tool=search_web {"args":{"query":"AI news"}}
[agentlib] [2024-03-15T10:30:01.500Z] [DEBUG] scope=tool:after tool=search_web duration=1300ms {"result":"..."}
[agentlib] [2024-03-15T10:30:01.600Z] [DEBUG] scope=step:after duration=1500ms
[agentlib] [2024-03-15T10:30:02.000Z] [INFO] scope=run:after duration=2000ms
Scope Filtering
Only log specific scopes:
agent . use ( createLogger ({
scopes: [ 'run:before' , 'run:after' , 'tool:before' , 'tool:after' ],
level: 'info' ,
}))
Custom Transport
Integrate with external logging services:
import { createLogger } from '@agentlib/logger'
import winston from 'winston'
const winstonLogger = winston . createLogger ({
transports: [ new winston . transports . File ({ filename: 'agent.log' })],
})
agent . use ( createLogger ({
transport : ( entry ) => {
winstonLogger . log ({
level: entry . level ,
message: ` ${ entry . scope } ${ entry . tool || '' } ` ,
metadata: {
timestamp: entry . timestamp ,
duration: entry . durationMs ,
... entry . meta ,
},
})
},
}))
JSON Transport
Output structured JSON logs:
agent . use ( createLogger ({
transport : ( entry ) => {
console . log ( JSON . stringify ({
timestamp: entry . timestamp ,
level: entry . level ,
scope: entry . scope ,
tool: entry . tool ,
duration: entry . durationMs ,
input: entry . agentInput ?. substring ( 0 , 50 ),
... entry . meta ,
}))
},
}))
Output:
{ "timestamp" : "2024-03-15T10:30:00.000Z" , "level" : "info" , "scope" : "run:before" , "input" : "Hello!" }
{ "timestamp" : "2024-03-15T10:30:02.345Z" , "level" : "info" , "scope" : "run:after" , "duration" : 2345 , "input" : "Hello!" }
Development vs Production
Use different configurations based on environment:
const loggerConfig = process . env . NODE_ENV === 'production'
? { level: 'warn' as const , timing: false }
: { level: 'debug' as const , timing: true }
agent . use ( createLogger ( loggerConfig ))
Silent Mode
Disable all logging:
agent . use ( createLogger ({ level: 'silent' }))
Log Levels
Levels are ranked by severity:
debug - Most verbose; includes all scopes
info - Run-level events (default)
warn - Warnings only
error - Errors only
silent - No logging
Default scope-to-level mapping:
run:before, run:after → info
step:before, step:after → debug
tool:before, tool:after → debug
Timing
When timing: true (default), the logger measures execution duration by pairing :before and :after scopes:
run:before → run:after: Total execution time
step:before → step:after: Individual step duration
tool:before → tool:after: Tool execution time
Duration is reported in the :after scope as durationMs.
Best Practices
Use appropriate log levels : Set level: 'debug' for development and 'warn' or 'error' for production.
Filter scopes : If you only care about tool execution, filter to ['tool:before', 'tool:after'].
Custom transports : Integrate with your existing logging infrastructure using the transport option.
Performance : Disable timing in production if microsecond precision isn’t needed.
Structured logging : Use JSON transports for machine-readable logs that can be easily indexed and searched.