Python syslog: Send Logs to Unix

Published on: August 26, 2026
Reading time: 5 minutes
Stack of cut logs covered in snow, showcasing a cold winter texture and woody elements.

The syslog module sends messages directly to the Unix system logger. Instead of managing its own file, an application hands events to the system daemon, which can filter, rotate, forward, retain, and integrate them with tools such as journald or rsyslog.

This interface is useful for small services, startup scripts, administration tools, and components that need system logging without configuring the full logging framework. Larger applications usually benefit from logging.handlers.SysLogHandler.

Availability

syslog is available on Unix but not WASI or iOS. Facilities and options depend on the platform’s syslog.h.

try:
    import syslog
except ImportError:
    syslog = None

On Windows, use Event Log, a file handler, or an appropriate remote logging transport.

Send a message

import syslog

syslog.syslog("Processing started")

Without an explicit priority, the level is LOG_INFO. If openlog() has not been called, the module opens the log automatically with default values.

Priorities

Severity levels from highest to lowest include LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_ERR, LOG_WARNING, LOG_NOTICE, LOG_INFO, and LOG_DEBUG.

syslog.syslog(syslog.LOG_WARNING, "Queue near limit")
syslog.syslog(syslog.LOG_ERR, "Failed to store result")

Do not label every failure critical. Inflated severity makes genuine emergencies harder to find.

Facilities

A facility categorizes the source, including LOG_USER, LOG_DAEMON, LOG_AUTH, LOG_MAIL, and LOG_LOCAL0 through LOG_LOCAL7.

syslog.openlog(
    ident="my-service",
    logoption=syslog.LOG_PID,
    facility=syslog.LOG_DAEMON,
)

Use a local facility only when server policy reserves it for the application.

Encode a facility in priority

Combine a facility and level with bitwise OR.

priority = syslog.LOG_LOCAL0 | syslog.LOG_NOTICE
syslog.syslog(priority, "Configuration reloaded")

When no facility is encoded, the value from openlog() is used.

Identification

ident is prepended to messages. By default it comes from sys.argv[0] without leading path components.

Choose a stable short identifier. Do not include user data, temporary paths, tokens, or other secrets.

LOG_PID

LOG_PID adds the process ID, which helps distinguish workers.

syslog.openlog("worker", syslog.LOG_PID, syslog.LOG_DAEMON)

PIDs are reused. Add a request or job correlation ID when durable tracing is required.

Other options

LOG_NDELAY opens the connection immediately. LOG_PERROR, when available, also writes to stderr. LOG_CONS may try the console after logger failure.

Options such as LOG_NOWAIT and LOG_ODELAY are platform-dependent. Check with hasattr().

Close and reset

closelog() closes the connection and resets internal values. The next syslog() call opens again with defaults.

try:
    syslog.openlog("job", syslog.LOG_PID, syslog.LOG_USER)
    syslog.syslog("Started")
finally:
    syslog.closelog()

Long-running applications do not need to open and close for every event.

Priority masks

setlogmask() filters levels before sending.

previous = syslog.setlogmask(syslog.LOG_UPTO(syslog.LOG_INFO))
try:
    syslog.syslog(syslog.LOG_DEBUG, "Filtered")
    syslog.syslog(syslog.LOG_INFO, "Sent")
finally:
    syslog.setlogmask(previous)

LOG_MASK() selects one level and LOG_UPTO() all levels up to a threshold.

Prevent log injection

Untrusted values may contain newlines, tabs, and control characters that imitate separate entries.

def safe_log_value(value):
    return str(value).replace("\r", "\\r").replace("\n", "\\n")

syslog.syslog(syslog.LOG_INFO, f"user={safe_log_value(user)}")

Also enforce length limits and redact secrets.

Structured messages

Classic syslog receives text. A compact JSON object or key-value format can preserve structure.

import json

message = json.dumps(
    {"event": "login", "result": "failure", "ip": ip},
    ensure_ascii=False,
    separators=(",", ":"),
)
syslog.syslog(syslog.LOG_WARNING, message)

Confirm that the downstream pipeline preserves the JSON payload.

Message size

Daemons, Unix sockets, and forwarders may truncate large messages. Do not send a huge stack trace as one entry.

Summarize the event, include a correlation ID, and store detailed diagnostics in a suitable system.

Encoding

The Python API accepts str. Actual encoding and invalid-character behavior depend on the system implementation.

Use valid Unicode and test non-ASCII text in production. Legacy systems may need ASCII-compatible escaping.

Failure handling

System logging is designed to be simple, but it can still fail because of configuration, permissions, or a missing socket. Decide whether logging failure should affect the main task.

try:
    syslog.syslog(syslog.LOG_ERR, message)
except OSError:
    write_safe_fallback(message)

The fallback must not recursively call the same syslog path.

Secrets

Never log passwords, access tokens, cookies, private keys, full connection strings, payment data, or confidential content. System logs are often accessible to operators and forwarded to third-party infrastructure.

Personal data

Minimize IP addresses, emails, and user identifiers. Apply retention and access policies that match the stated purpose.

Subinterpreters

Since Python 3.12, openlog() and closelog() may only be called in the main interpreter. A subinterpreter may use syslog() only after the main interpreter has opened the log; otherwise it raises RuntimeError.

New facilities

Python 3.13 adds constants such as LOG_FTP, LOG_NETINFO, LOG_REMOTEAUTH, LOG_INSTALL, LOG_RAS, and LOG_LAUNCHD when the platform defines them.

Auditing

syslog(), openlog(), closelog(), and setlogmask() raise auditing events. Restricted environments may observe or block logging.

syslog or logging?

The native module is direct and Unix-specific. Python’s logging framework provides filters, formatters, handlers, hierarchy, and easier testing.

For larger software, configure logging.handlers.SysLogHandler. It can also communicate with a remote server, while the native module uses the local syslog library.

SysLogHandler

import logging
from logging.handlers import SysLogHandler

logger = logging.getLogger("app")
handler = SysLogHandler(address="/dev/log")
logger.addHandler(handler)
logger.warning("Queue near limit")

The socket path varies by platform. Test it instead of assuming /dev/log.

journald

On systemd systems, syslog messages may appear in the journal. Native structured journal fields require a journald-specific library; text syslog does not become structured automatically.

Containers

Containers often work best when applications write structured logs to stdout or stderr and let the runtime collect them. A syslog socket may not exist.

Do not mount the host’s /dev/log without evaluating operational and security consequences.

Fork

After fork, the child inherits state. Reopen with an appropriate ident if parent and child represent different components.

Avoid complex work between fork and exec in a multithreaded application.

Rate limiting

An error loop can flood syslog, consume disk, and hide useful events. Apply sampling, aggregation, or rate limits.

if count % 100 == 1:
    syslog.syslog(syslog.LOG_WARNING, f"repeated_error count={count}")

Correlation

Include opaque request, job, or session IDs without embedding sensitive data. This helps join events without relying on exact ordering.

Local verification

Send a uniquely identifiable test message and inspect the platform tool, such as journalctl or a file under /var/log. The destination depends on daemon configuration.

Automated tests

Unit tests should not depend on the host’s global syslog. Wrap the send operation and replace it with a fake. Use a dedicated daemon or container for integration tests.

Common mistakes

Common failures include logging secrets, allowing user newlines, inflating severity, assuming facilities exist, sending huge messages, depending on /dev/log inside containers, sharing global state between components, and using native syslog where logging would be easier to test.

Conclusion

syslog is a simple bridge between Python and the Unix system logger. Use a stable ident, honest priorities, bounded and sanitized content, and a non-recursive fallback.

For complex applications, consider SysLogHandler or structured stdout. Consult the official syslog documentation and syslog(3).

Share:

Facebook
WhatsApp
Twitter
LinkedIn

Article content

    Related articles

    High-resolution close-up of a CPU processor, RAM sticks, and a hard drive, showcasing modern computer hardware.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python resource: CPU and Memory Limits

    Learn Python resource to measure CPU, peak memory, page faults, and set limits for files, processes, descriptors, and address space

    Ler mais

    Tempo de leitura: 5 minutos
    26/08/2026
    A developer typing code on a laptop with a Python book beside in an office.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python pty: Automate Unix Terminals

    Learn Python pty to run and test interactive programs, control pseudo-terminals, handle EOF, resize, signals, timeouts, and cleanup.

    Ler mais

    Tempo de leitura: 5 minutos
    25/08/2026
    Close-up of hands typing on a laptop keyboard, Python book in sight, coding in progress.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python tty: Raw and Cbreak Modes

    Learn Python tty to use raw and cbreak modes, read keys, parse sequences, handle Unicode, and safely restore Unix terminals.

    Ler mais

    Tempo de leitura: 5 minutos
    25/08/2026
    Detailed view of programming code in a dark theme on a computer screen.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python termios: Safe Terminal Control

    Learn Python termios for canonical mode, echo, key reads, baud rate, queues, window size, and safe restoration of POSIX terminals.

    Ler mais

    Tempo de leitura: 5 minutos
    25/08/2026
    Side view of contemplating female assistant in casual style standing near shelves and choosing file with documents
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python fcntl: File Locks and Control

    Learn Python fcntl for file locks, descriptor flags, ioctl, pipes, and Unix control while avoiding invalid buffers and memory corruption.

    Ler mais

    Tempo de leitura: 5 minutos
    25/08/2026
    A developer typing code on a laptop with a Python book beside in an office.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python readline: History and Autocomplete

    Learn Python readline for command history, tab completion, line editing, GNU Readline, libedit, and safer interactive terminal prompts.

    Ler mais

    Tempo de leitura: 5 minutos
    25/08/2026