Skip to main content

Logging Configuration

Caddy provides zero-allocation, high-performance structured logging using Zap. Logs can be customized with different outputs, encoders, and filters.

Default Logging

By default, Caddy logs to stderr at INFO level:
2024/01/15 10:30:00.123 [INFO] http.log.access handled request

Log Configuration

Custom Log Output

{
  "logging": {
    "logs": {
      "default": {
        "writer": {
          "output": "file",
          "filename": "/var/log/caddy/access.log"
        },
        "encoder": {
          "format": "json"
        },
        "level": "INFO"
      }
    }
  }
}

Log Levels

Available log levels (from most to least verbose):
  • DEBUG - Detailed debugging information
  • INFO - General informational messages (default)
  • WARN - Warning messages
  • ERROR - Error messages
  • PANIC - Panic messages (causes panic)
  • FATAL - Fatal messages (causes exit)
{
    log {
        level DEBUG
    }
}
Use environment variables for dynamic log levels: level {$LOG_LEVEL}

Log Encoders

JSON Encoder

Structured JSON output:
{
  "level": "info",
  "ts": 1705318200.123,
  "logger": "http.log.access",
  "msg": "handled request",
  "request": {
    "method": "GET",
    "uri": "/index.html",
    "proto": "HTTP/2.0"
  },
  "duration": 0.123,
  "size": 4096,
  "status": 200
}

Console Encoder

Human-readable output:
2024-01-15T10:30:00.123Z  INFO  http.log.access  handled request

Custom Format

{
  "encoder": {
    "format": "console",
    "time_format": "2006/01/02 15:04:05.000",
    "level_format": "color",
    "message_key": "msg",
    "time_key": "ts"
  }
}

Log Writers

File Writer

{
  "writer": {
    "output": "file",
    "filename": "/var/log/caddy/access.log",
    "roll": true,
    "roll_size_mb": 100,
    "roll_keep": 10,
    "roll_keep_days": 90
  }
}

Network Writer

Send logs over the network:
{
  "writer": {
    "output": "net",
    "address": "localhost:5140",
    "dial_timeout": "10s"
  }
}

Standard Streams

{
    log {
        output stdout  # or stderr (default)
    }
}

Discard

Disable logging:
{
    log {
        output discard
    }
}

Log Filtering

Include Specific Modules

Only log from specific modules:
{
  "logs": {
    "admin_only": {
      "include": ["admin.api", "admin"]
    }
  }
}

Exclude Modules

Filter out specific modules:
{
  "logs": {
    "no_access": {
      "exclude": ["http.log.access"]
    }
  }
}

Complex Filtering

Combine include and exclude:
{
  "logs": {
    "http_without_access": {
      "include": ["http"],
      "exclude": ["http.log.access"],
      "level": "WARN"
    }
  }
}
When both include and exclude are set, longer namespaces have priority. The lists must be mutually exclusive superset/subset pairs.

HTTP Access Logs

Configure access logs per site:
{
  "apps": {
    "http": {
      "servers": {
        "srv0": {
          "logs": {
            "logger_names": {
              "example.com": "example_log"
            }
          }
        }
      }
    }
  },
  "logging": {
    "logs": {
      "example_log": {
        "writer": {
          "output": "file",
          "filename": "/var/log/caddy/example.com.log"
        },
        "encoder": {
          "format": "json"
        }
      }
    }
  }
}

Access Log Fields

Customize which fields to log:
example.com {
    log {
        format filter {
            wrap json
            fields {
                request>remote_ip ip
                request>proto delete
                common_log delete
            }
        }
    }
}

Sampling

Reduce log volume on high-traffic servers:
{
  "logging": {
    "logs": {
      "default": {
        "sampling": {
          "interval": "1s",
          "first": 100,
          "thereafter": 100
        }
      }
    }
  }
}
Sampling logs the first N entries per interval, then 1 in M thereafter. This drastically reduces log volume while preserving representative samples.

Caller Information

Include file and line numbers in logs:
{
  "logs": {
    "debug_log": {
      "level": "DEBUG",
      "with_caller": true,
      "with_caller_skip": 0,
      "with_stacktrace": "ERROR"
    }
  }
}

Multiple Logs

Configure different logs for different purposes:
{
    # Access logs
    log access {
        include http.log.access
        output file /var/log/caddy/access.log {
            roll_size 100mb
            roll_keep 10
        }
        format json
    }
    
    # Error logs only
    log errors {
        include http
        exclude http.log.access
        output file /var/log/caddy/errors.log {
            roll_size 10mb
            roll_keep 5
        }
        level ERROR
        format json
    }
    
    # Admin logs
    log admin {
        include admin
        output file /var/log/caddy/admin.log
        level INFO
    }
}

Sink Log

Configure the sink for stdlib logger output:
{
  "logging": {
    "sink": {
      "writer": {
        "output": "file",
        "filename": "/var/log/caddy/sink.log"
      }
    }
  }
}
The sink captures logs from Go’s standard library logger, used by dependencies not built specifically for Caddy.

Complete Example

{
    # Default log (stderr, console format for development)
    log {
        output stdout
        format console {
            time_format "2006/01/02 15:04:05"
            level_format color
        }
        level DEBUG
    }
    
    # Production access logs
    log access {
        include http.log.access
        output file /var/log/caddy/access.log {
            roll_size 100mb
            roll_keep 10
            roll_keep_days 90
        }
        format json
        level INFO
    }
    
    # Error logs with stack traces
    log errors {
        include http
        exclude http.log.access
        output file /var/log/caddy/errors.log {
            roll_size 10mb
            roll_keep 5
        }
        format json
        level ERROR
        with_stacktrace ERROR
    }
    
    # Admin API logs
    log admin {
        include admin
        output file /var/log/caddy/admin.log
        format json
    }
}

# Per-site access logging
example.com {
    log {
        output file /var/log/caddy/sites/example.com.log {
            roll_size 50mb
            roll_keep 7
        }
        format json
    }
    
    reverse_proxy backend:8080
}

Log Module Names

Common logger names for filtering:
  • http - All HTTP-related logs
  • http.log.access - HTTP access logs
  • http.handlers.* - HTTP handler logs
  • http.handlers.reverse_proxy - Reverse proxy logs
  • http.handlers.file_server - File server logs
  • admin - Admin endpoint logs
  • admin.api - Admin API logs
  • tls - TLS/certificate logs
  • tls.issuance - Certificate issuance logs

Best Practices

1
Logging Guidelines
2
  • Use JSON in production - Easier to parse and analyze
  • Implement log rotation - Prevent disk space issues
  • Set appropriate levels - DEBUG for development, INFO for production
  • Filter by module - Separate access logs from errors
  • Enable sampling - On high-traffic servers to reduce volume
  • Monitor log sizes - Set up alerts for unusual growth
  • Verbose logging (DEBUG level) can impact performance and generate large volumes of logs. Use sparingly in production.

    Build docs developers (and LLMs) love