Stream every log line from your Linux system — kernel messages, service output, auth events — into your BunnyLogs feed in real time.
Modern Linux systems log through systemd's journal (journald)
and, on most distributions, also through rsyslog which reads from the journal.
Pick the approach that fits your setup:
| Approach | Best for |
|---|---|
| journald watcher | Any systemd-based system — Python script using the bunnylogs package |
| rsyslog omhttp | Systems already using rsyslog; native module, no scripting |
This script reads from journalctl -f -o json and forwards every new journal entry to BunnyLogs
via the bunnylogs package.
Each journal source (nginx, sshd, kernel, …) appears as a separate program in your log stream.
Works on any systemd-based distribution (Ubuntu, Debian, Fedora, Arch, etc.).
Install the package
pip install bunnylogs
Save the script as /usr/local/bin/bunnylogs-syslog.py:
#!/usr/bin/env python3
"""Forward systemd journal entries to BunnyLogs."""
import json
import logging
import subprocess
from bunnylogs import BunnyLogsHandler
UUID = "<uuid>" # replace with your logspace UUID
PRIORITY_MAP = {
0: logging.CRITICAL, # emergency
1: logging.CRITICAL, # alert
2: logging.CRITICAL, # critical
3: logging.ERROR, # error
4: logging.WARNING, # warning
5: logging.INFO, # notice
6: logging.INFO, # informational
7: logging.DEBUG, # debug
}
_loggers: dict[str, logging.Logger] = {}
def get_logger(program: str) -> logging.Logger:
if program not in _loggers:
logger = logging.getLogger(program)
logger.setLevel(logging.DEBUG)
logger.addHandler(BunnyLogsHandler(UUID))
logger.propagate = False
_loggers[program] = logger
return _loggers[program]
def main() -> None:
proc = subprocess.Popen(
["journalctl", "--follow", "--output=json", "--lines=0"],
stdout=subprocess.PIPE,
text=True,
)
for line in proc.stdout:
try:
entry = json.loads(line)
except json.JSONDecodeError:
continue
message = entry.get("MESSAGE", "")
if not message or not isinstance(message, str):
continue # skip binary/empty journal fields
priority = int(entry.get("PRIORITY", 6))
level = PRIORITY_MAP.get(priority, logging.INFO)
program = (
entry.get("SYSLOG_IDENTIFIER")
or entry.get("_COMM")
or "syslog"
)
get_logger(program).log(level, message)
if __name__ == "__main__":
main()
chmod +x /usr/local/bin/bunnylogs-syslog.py
Test it manually first (you should see new log entries appear in BunnyLogs as they arrive):
python3 /usr/local/bin/bunnylogs-syslog.py
Create /etc/systemd/system/bunnylogs-syslog.service:
[Unit]
Description=BunnyLogs syslog forwarder
After=network-online.target systemd-journald.service
Wants=network-online.target
[Service]
ExecStart=/usr/bin/python3 /usr/local/bin/bunnylogs-syslog.py
Restart=on-failure
RestartSec=10
StandardOutput=null
StandardError=journal
[Install]
WantedBy=multi-user.target
systemctl daemon-reload
systemctl enable --now bunnylogs-syslog
systemctl status bunnylogs-syslog
rsyslog's omhttp output module POSTs log messages to an HTTP endpoint natively — no
scripting required. This is the right choice if rsyslog is already your primary log daemon.
Install the omhttp module
# Debian / Ubuntu
apt install rsyslog-omhttp
# RHEL / Fedora / CentOS
dnf install rsyslog-omhttp
Create /etc/rsyslog.d/bunnylogs.conf
# Load the HTTP output module
module(load="omhttp")
# Template: JSON body that matches BunnyLogs field names
template(name="BunnyLogsJSON" type="list") {
constant(value="{")
constant(value="\"message\":") property(name="msg" format="json")
constant(value=",\"program\":") property(name="programname" format="json")
constant(value="}")
}
# Forward all messages of warning severity and above
*.warning action(
type = "omhttp"
server = "bunnylogs.com"
serverport = "443"
usehttps = "on"
restpath = "/live/<uuid>"
template = "BunnyLogsJSON"
httpcontenttype = "application/json"
action.resumeRetryCount = "3"
)
Change *.warning to *.* to forward all severity levels, or use a facility
selector like auth,authpriv.* to forward only authentication events.
Reload rsyslog
rsyslogd -N1 # syntax check
systemctl restart rsyslog
Verify
# Generate a test message — it should appear in BunnyLogs within seconds
logger -p user.warning "BunnyLogs test message from rsyslog"
Both approaches forward every journal entry by default. Common ways to narrow the feed:
journalctl flags when spawning the subprocess,
e.g. --identifier=nginx to follow only nginx messages, or
--priority=warning to skip INFO and DEBUG.
kern.*, auth.*,
*.err, etc.) or add an if filter inside the action block to
match on the program name.
program field (populated from SYSLOG_IDENTIFIER / programname)
to filter per service in the BunnyLogs dashboard — you'll see sshd, nginx,
kernel, etc. as distinct sources.--lines=0 so it only picks up new entries after it starts,
avoiding a flood of historical messages on first run.warning and above to stay within your
monthly ingest cap.Restart=on-failure); rsyslog retries via action.resumeRetryCount.program name (e.g. set SYSLOG_IDENTIFIER or
override program in the script) to distinguish them.