Skip to content

LogWard LogWard

LogWard is an open-source, self-hosted log management tool.

🛠 Installation

Default Port: 3000

homelab/docker/logward

task up
docker compose up

âš™ Config

homelab/docker/logward/.env

--8<-- "logward/.env.tmpl"
homelab/docker/logward/compose.yaml
--8<-- "logward/compose.yaml"

📒 Logging

To enable automatic log collection from other Docker containers:

  1. Generate API Key: Log in to LogWard, go to Project Settings, and create an API Key.
  2. Update Config: Add the API key to your .env file.

    FLUENT_BIT_API_KEY=lp_your_api_key_here
    
  3. Create Config Files: Ensure the following configuration files exist in your docker/logward directory.

    fluent-bit.conf
    # Fluent Bit Configuration for LogWard
    
    [SERVICE]
        # Flush logs every 5 seconds
        Flush        5
        # Run in foreground
        Daemon       Off
        # Log level (error, warning, info, debug, trace)
        Log_Level    info
        # Parsers configuration file
        Parsers_File /fluent-bit/etc/parsers.conf
    
    # =============================================================================
    # INPUT - Docker Container Logs
    # =============================================================================
    [INPUT]
        Name              tail
        Path              /var/lib/docker/containers/*/*.log
        Parser            docker
        Tag               docker.*
        Refresh_Interval  5
        Mem_Buf_Limit     5MB
        Skip_Long_Lines   On
        Path_Key          filepath
    
    # =============================================================================
    # FILTER - Parse and Enrich
    # =============================================================================
    # Extract container metadata (name, id, image)
    [FILTER]
        Name                parser
        Match               docker.*
        Key_Name            log
        Parser              docker_json
        Reserve_Data        On
        Preserve_Key        On
    
    # Add required fields for LogWard API
    [FILTER]
        Name                modify
        Match               docker.*
        # Set default level if not present
        Add                 level info
        # Rename 'log' field to 'message'
        Rename              log message
        # Set service name from container_name
        Copy                container_name service
    
    # Remove unnecessary fields to reduce log size
    [FILTER]
        Name                record_modifier
        Match               docker.*
        Remove_key          stream
        Remove_key          filepath
        Remove_key          container_name
    
    # =============================================================================
    # OUTPUT - Send to LogWard
    # =============================================================================
    [OUTPUT]
        Name                http
        Match               docker.*
        Host                ${LOGWARD_API_HOST}
        Port                8080
        URI                 /api/v1/ingest/single
        Format              json_lines
        Header              X-API-Key ${LOGWARD_API_KEY}
        Header              Content-Type application/json
        # Date/time settings
        Json_date_key       time
        Json_date_format    iso8601
        # Retry settings
        Retry_Limit         3
        # TLS (disable for internal Docker network)
        tls                 Off
    
    parsers.conf
    # Fluent Bit Parsers Configuration
    
    # Parser for Docker JSON logs
    [PARSER]
        Name        docker_json
        Format      json
        Time_Key    time
        Time_Format %Y-%m-%dT%H:%M:%S.%L%z
        Time_Keep   On
    
    # Parser for Docker container logs
    [PARSER]
        Name        docker
        Format      json
        Time_Key    time
        Time_Format %Y-%m-%dT%H:%M:%S.%L%z
        Time_Keep   On
    
    extract_container_id.lua
    -- Extract container ID from Docker log file path
    -- Path format: /var/lib/docker/containers/<container_id>/<container_id>-json.log
    
    function extract_container_id(tag, timestamp, record)
        local filepath = record["filepath"]
    
        if filepath == nil then
            return 0, timestamp, record
        end
    
        -- Extract container ID from path
        -- Example: /var/lib/docker/containers/abc123.../abc123...-json.log
        local container_id = filepath:match("/var/lib/docker/containers/([^/]+)/")
    
        if container_id then
            record["container_id"] = container_id
            record["container_short_id"] = container_id:sub(1, 12)
        end
    
        -- Return code: 1 = modified and keep, 0 = no change
        return 1, timestamp, record
    end
    
    wrap_logs.lua
    -- Dummy file if not provided
    function wrap_logs(tag, timestamp, record)
        return 0, timestamp, record
    end
    
  4. Enable Logging: Start the stack with the logging profile.

    task up-logging
    
    docker compose --profile logging up -d
    

Integrations

CLI (curl)

You can send a single log entry to LogWard using curl.

curl -X POST https://logward.l.nicholaswilde.io/api/v1/ingest/single \
  -H "X-API-Key: lp_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "service": "my-script",
    "level": "info",
    "message": "This is a test log message",
    "timestamp": "'"$(date -u +'%Y-%m-%dT%H:%M:%SZ')"'"
  }'

:material-proxmox: Proxmox (rsyslog)

To forward logs from a Proxmox node (or any Debian-based system) to LogWard via syslog:

  1. Install rsyslog (if not already installed):

    apt update && apt install rsyslog -y
    
  2. Create configuration file:

    /etc/rsyslog.d/50-logward.conf

    # Forward all logs to LogWard via TCP
    *.* @@YOUR_LOGWARD_IP:514
    

    Note: Use @@ for TCP (recommended) or @ for UDP.

  3. Restart rsyslog:

    systemctl restart rsyslog
    

Raspberry Pi

If you are running on a Raspberry Pi, the standard Fluent Bit docker image might not work because it requires a page size of 4k. The Raspberry Pi kernel often uses a page size of 16k.

To check your page size, run:

getconf PAGESIZE

If the output is 16384, you must generate a custom Fluent Bit docker image with jemalloc support disabled.

task build
docker build -t fluent-bit-16k:latest .

Ensure that your compose.yaml is using the custom image:

image: fluent-bit-16k:latest

Traefik

homelab/pve/traefik/conf.d/logward.yaml
--8<-- "traefik/conf.d/logward.yaml"

🔧 Troubleshooting

If you are experiencing issues with log collection, follow these steps:

  1. Verify Fluent Bit is running:

    docker compose ps fluent-bit
    
  2. Check Fluent Bit logs:

    docker compose logs fluent-bit
    
  3. Test connectivity:

    Verify you can reach LogWard's Fluent Bit port (514) from your source device.

    nc -zv YOUR_LOGWARD_IP 514
    
  4. Verify API Key:

    Ensure FLUENT_BIT_API_KEY is correctly set in your .env file.

  5. Test Syslog Manually:

    Send a test message to verify the pipeline.

    echo "<14>Test syslog message from terminal" | nc -u -w1 YOUR_LOGWARD_IP 514
    
    echo "<14>Test syslog message from terminal" | nc -w1 YOUR_LOGWARD_IP 514
    

Task List

--8<-- "logward/task-list.txt"

🔗 References