Forwarding Logs from Fly.io

Stream runtime logs from any Fly.io app to BunnyLogs — either directly from your Python app using the bunnylogs handler, or at the infrastructure level using Fly.io's native log drain.

Option 1 — Python app (recommended for Python apps)

Install bunnylogs and attach it as a logging handler. Logs are shipped in a background thread so your app is never blocked.

pip install bunnylogs
import logging
from bunnylogs import BunnyLogsHandler

logger = logging.getLogger()
logger.addHandler(BunnyLogsHandler("<uuid>"))

logger.info("app started")
logger.error("something went wrong")

For Django or Flask apps on Fly.io, add the handler in your settings / app factory so it is wired up at startup:

# Django — settings.py
LOGGING = {
    "version": 1,
    "disable_existing_loggers": False,
    "handlers": {
        "bunnylogs": {
            "class": "bunnylogs.BunnyLogsHandler",
            "uuid": "<uuid>",
        }
    },
    "root": {"handlers": ["bunnylogs"], "level": "INFO"},
}

Store the UUID as a Fly.io secret rather than hard-coding it:

fly secrets set BUNNYLOGS_UUID=<uuid> --app <app-name>
import os, logging
from bunnylogs import BunnyLogsHandler

logging.getLogger().addHandler(BunnyLogsHandler(os.environ["BUNNYLOGS_UUID"]))

Option 2 — HTTP log drain (any language)

Fly.io can forward all stdout/stderr from your app to an external HTTP endpoint. Each log line is POSTed as JSON. BunnyLogs accepts JSON POSTs natively — no adapter or forwarder required.

  1. Copy your logspace UUID from the stream URL (https://bunnylogs.com/live/<uuid>).
  2. Create the drain with the Fly CLI:
fly logs ship create https://bunnylogs.com/live/<uuid> --app <app-name>

Fly.io will immediately start POSTing log entries to BunnyLogs as JSON. The message and timestamp fields are mapped automatically. The program field defaults to api — you can override it in your app's log output or by using a Vector transform (see below).

To verify the drain is active:

fly logs ship list --app <app-name>

To remove it:

fly logs ship delete <drain-id> --app <app-name>

Option 3 — Vector transform (advanced)

If you want to enrich log entries with the Fly.io app name, region, or instance ID before they reach BunnyLogs, deploy the fly-log-shipper — Fly.io's official Vector-based log forwarder. Configure an http sink in your vector.toml:

[sinks.bunnylogs]
type = "http"
inputs = ["my_transform"]
uri = "https://bunnylogs.com/live/<uuid>"
method = "post"
encoding.codec = "json"

[sinks.bunnylogs.request.headers]
Content-Type = "application/json"

In the transform step, remap fields to BunnyLogs' schema:

[transforms.my_transform]
type = "remap"
inputs = ["fly_logs"]
source = '''
  .message   = .message
  .level     = upcase(string!(.log.level)) ?? "INFO"
  .program   = .fly.app.name
  .timestamp = .timestamp
'''

Deploy notifications

To notify BunnyLogs whenever a new version is deployed, add a release_command to fly.toml:

[deploy]
  release_command = "curl -s -d 'message=Deploying $FLY_APP_NAME' -d 'level=INFO' -d 'program=fly/$FLY_APP_NAME' https://bunnylogs.com/live/<uuid>"

Or use a Dockerfile entrypoint script that POSTs a startup message before handing off to the main process:

#!/bin/sh
curl -s \
  -d "message=Started: $FLY_APP_NAME in $FLY_REGION" \
  -d "level=INFO" \
  -d "program=fly/$FLY_APP_NAME" \
  https://bunnylogs.com/live/$BUNNYLOGS_UUID
exec "$@"
Useful Fly.io environment variables
VariableValue
$FLY_APP_NAMEName of the Fly.io app
$FLY_REGIONThree-letter region code, e.g. iad, ams
$FLY_ALLOC_IDUnique ID for this VM instance
$FLY_IMAGE_REFDocker image reference for the running build
$FLY_PROCESS_GROUPProcess group name (e.g. app, worker)
Notes
  • For Python apps, Option 1 gives the richest integration — log levels, structured fields, and exception tracebacks are all forwarded correctly without any infrastructure changes.
  • The HTTP drain (Option 2) works for any language and forwards all stdout/stderr, but log level is not mapped unless you use a Vector transform.
  • Store your BunnyLogs UUID as a fly secret — never hard-code it in fly.toml or commit it to your repository.
  • Set up an Alert in BunnyLogs matching level=ERROR and program contains fly/ to get notified on errors via Slack, Telegram, or Discord.
  • If you run multiple Fly.io apps, use the same UUID and distinguish sources with the program field.