Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/mastra-ai/mastra/llms.txt

Use this file to discover all available pages before exploring further.

Mastra provides structured logging with automatic correlation to traces and spans, making it easy to debug issues and understand system behavior.

Overview

Mastra’s logging system:
  • Automatically correlates logs with traces and spans
  • Supports multiple log levels (debug, info, warn, error, fatal)
  • Captures structured data with each log message
  • Works with any logger that implements the LoggerContext interface

Basic Usage

Default Logger

Mastra includes a console logger by default:
import { Mastra } from '@mastra/core';

const mastra = new Mastra({
  agents: { /* ... */ },
});

// Get the logger
const logger = mastra.getLogger();

// Log messages
logger.info('Processing request', { userId: '123' });
logger.error('Failed to connect', { service: 'database', error: 'timeout' });

Log Levels

Available log levels in order of severity:
logger.debug('Debug info', { data: {...} });  // Lowest
logger.info('Info message', { status: 'ok' });
logger.warn('Warning', { threshold: 0.8 });
logger.error('Error occurred', { error: err });
logger.fatal('Critical failure', { service: 'auth' }); // Highest

Structured Logging

Adding Context

Include structured data with log messages:
logger.info('User login', {
  userId: 'user-123',
  email: 'user@example.com',
  ipAddress: '192.168.1.1',
  timestamp: new Date(),
});

logger.error('Database query failed', {
  query: 'SELECT * FROM users',
  database: 'production',
  duration: 5000,
  error: {
    message: 'Connection timeout',
    code: 'ETIMEDOUT',
  },
});

Automatic Trace Correlation

Logs automatically include trace and span IDs when logged within a traced operation:
const result = await agent.generate({
  messages: [{ role: 'user', content: 'Hello' }],
  
  onStepStart: () => {
    // This log will include traceId and spanId automatically
    logger.info('Agent step started');
  },
  
  onStepFinish: ({ result }) => {
    logger.info('Agent step completed', { 
      finishReason: result.finishReason,
    });
    // Log entry:
    // {
    //   level: 'info',
    //   message: 'Agent step completed',
    //   data: { finishReason: 'stop' },
    //   traceId: 'a1b2c3d4...',
    //   spanId: 'e5f67890...',
    //   timestamp: Date(...)
    // }
  },
});

Custom Logger

Implementing LoggerContext

Create a custom logger by implementing the LoggerContext interface:
import { LoggerContext } from '@mastra/core/observability';

class CustomLogger implements LoggerContext {
  debug(message: string, data?: Record<string, unknown>): void {
    console.log('[DEBUG]', message, data);
  }
  
  info(message: string, data?: Record<string, unknown>): void {
    console.log('[INFO]', message, data);
  }
  
  warn(message: string, data?: Record<string, unknown>): void {
    console.warn('[WARN]', message, data);
  }
  
  error(message: string, data?: Record<string, unknown>): void {
    console.error('[ERROR]', message, data);
  }
  
  fatal(message: string, data?: Record<string, unknown>): void {
    console.error('[FATAL]', message, data);
  }
}

// Use custom logger
const mastra = new Mastra({
  logger: new CustomLogger(),
  agents: { /* ... */ },
});

Winston Integration

Integrate with Winston logger:
import winston from 'winston';
import { LoggerContext, LogLevel } from '@mastra/core/observability';

class WinstonLogger implements LoggerContext {
  private logger: winston.Logger;
  
  constructor() {
    this.logger = winston.createLogger({
      level: 'info',
      format: winston.format.combine(
        winston.format.timestamp(),
        winston.format.json()
      ),
      transports: [
        new winston.transports.Console(),
        new winston.transports.File({ filename: 'mastra.log' }),
      ],
    });
  }
  
  private log(level: LogLevel, message: string, data?: Record<string, unknown>) {
    this.logger.log(level, message, data);
  }
  
  debug(message: string, data?: Record<string, unknown>): void {
    this.log('debug', message, data);
  }
  
  info(message: string, data?: Record<string, unknown>): void {
    this.log('info', message, data);
  }
  
  warn(message: string, data?: Record<string, unknown>): void {
    this.log('warn', message, data);
  }
  
  error(message: string, data?: Record<string, unknown>): void {
    this.log('error', message, data);
  }
  
  fatal(message: string, data?: Record<string, unknown>): void {
    this.log('error', message, { ...data, fatal: true });
  }
}

const mastra = new Mastra({
  logger: new WinstonLogger(),
  agents: { /* ... */ },
});

Pino Integration

Integrate with Pino logger:
import pino from 'pino';
import { LoggerContext } from '@mastra/core/observability';

class PinoLogger implements LoggerContext {
  private logger: pino.Logger;
  
  constructor() {
    this.logger = pino({
      level: 'debug',
      transport: {
        target: 'pino-pretty',
        options: { colorize: true },
      },
    });
  }
  
  debug(message: string, data?: Record<string, unknown>): void {
    this.logger.debug(data, message);
  }
  
  info(message: string, data?: Record<string, unknown>): void {
    this.logger.info(data, message);
  }
  
  warn(message: string, data?: Record<string, unknown>): void {
    this.logger.warn(data, message);
  }
  
  error(message: string, data?: Record<string, unknown>): void {
    this.logger.error(data, message);
  }
  
  fatal(message: string, data?: Record<string, unknown>): void {
    this.logger.fatal(data, message);
  }
}

const mastra = new Mastra({
  logger: new PinoLogger(),
  agents: { /* ... */ },
});

Log Format

ExportedLog Structure

Logs are exported with this structure:
interface ExportedLog {
  timestamp: Date;               // When log was emitted
  level: LogLevel;               // Log severity level
  message: string;               // Human-readable message
  data?: Record<string, unknown>; // Structured data
  traceId?: string;              // Correlated trace ID
  spanId?: string;               // Correlated span ID
  tags?: string[];               // Optional tags
  metadata?: Record<string, unknown>; // Additional metadata
}

Example Log Entry

{
  "timestamp": "2024-01-15T10:30:00.000Z",
  "level": "info",
  "message": "Agent generation completed",
  "data": {
    "agentId": "myAgent",
    "duration": 1250,
    "tokenUsage": {
      "input": 150,
      "output": 75
    }
  },
  "traceId": "a1b2c3d4e5f67890a1b2c3d4e5f67890",
  "spanId": "e5f67890a1b2c3d4",
  "tags": ["production"],
  "metadata": {
    "userId": "user-123",
    "sessionId": "session-abc"
  }
}

Best Practices

Use Appropriate Log Levels

// DEBUG - Detailed information for troubleshooting
logger.debug('Processing message', { messageId: '123', content: 'Hello' });

// INFO - General informational messages
logger.info('Request processed successfully', { userId: '123', duration: 250 });

// WARN - Warning messages that don't prevent operation
logger.warn('Rate limit approaching', { current: 95, limit: 100 });

// ERROR - Error conditions that should be investigated
logger.error('Failed to call external API', { api: 'weather', error: 'timeout' });

// FATAL - Critical errors that require immediate attention
logger.fatal('Database connection lost', { database: 'production' });

Include Relevant Context

// Good: Includes context for debugging
logger.error('Tool execution failed', {
  toolName: 'calculator',
  input: { operation: 'divide', a: 10, b: 0 },
  error: 'Division by zero',
  userId: 'user-123',
});

// Bad: Missing context
logger.error('Tool failed');

Structure Complex Data

logger.info('Model response received', {
  model: 'gpt-4',
  usage: {
    prompt: 150,
    completion: 75,
    total: 225,
  },
  timing: {
    ttft: 250,    // Time to first token
    total: 1200,
  },
  finishReason: 'stop',
});

Avoid Logging Sensitive Data

// Good: Redact sensitive information
logger.info('User authenticated', {
  userId: user.id,
  email: user.email.replace(/(.{2}).*(@.*)/, '$1***$2'), // Redact email
});

// Bad: Logging sensitive data
logger.info('User authenticated', {
  userId: user.id,
  password: user.password, // Never log passwords!
  apiKey: user.apiKey,     // Never log API keys!
});

Querying Logs

If using an observability platform, query logs via the HTTP API:
# Query logs with filters
curl "http://localhost:3000/api/logs?level=error&limit=100"

# Query logs for specific trace
curl "http://localhost:3000/api/logs?traceId=a1b2c3d4e5f67890a1b2c3d4e5f67890"

Next Steps

Tracing

Learn about OpenTelemetry tracing

Server API

Explore server routes and handlers

Build docs developers (and LLMs) love