Skip to main content

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)
config
LoggerMiddlewareConfig
Optional configuration object for the logger.

Types

LogEntry

Structure of a log entry passed to the transport function.
level
LogLevel
required
Log level: 'debug', 'info', 'warn', 'error', or 'silent'.
scope
MiddlewareScope
required
The middleware scope that generated this log entry.
timestamp
string
required
ISO timestamp when the log entry was created.
agentInput
string
The user input for the current agent run.
tool
string
Name of the tool being executed (for tool:* scopes).
durationMs
number
Execution duration in milliseconds (only present in :after scopes when timing is enabled).
meta
Record<string, unknown>
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:
  1. debug - Most verbose; includes all scopes
  2. info - Run-level events (default)
  3. warn - Warnings only
  4. error - Errors only
  5. silent - No logging
Default scope-to-level mapping:
  • run:before, run:afterinfo
  • step:before, step:afterdebug
  • tool:before, tool:afterdebug

Timing

When timing: true (default), the logger measures execution duration by pairing :before and :after scopes:
  • run:beforerun:after: Total execution time
  • step:beforestep:after: Individual step duration
  • tool:beforetool:after: Tool execution time
Duration is reported in the :after scope as durationMs.

Best Practices

  1. Use appropriate log levels: Set level: 'debug' for development and 'warn' or 'error' for production.
  2. Filter scopes: If you only care about tool execution, filter to ['tool:before', 'tool:after'].
  3. Custom transports: Integrate with your existing logging infrastructure using the transport option.
  4. Performance: Disable timing in production if microsecond precision isn’t needed.
  5. Structured logging: Use JSON transports for machine-readable logs that can be easily indexed and searched.

Build docs developers (and LLMs) love