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

    Server rack representing connection load balancing with Python SO_REUSEPORT_LB
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    SO_REUSEPORT_LB: Balance Connections Across Workers

    Learn Python SO_REUSEPORT_LB to distribute connections across multiple workers with safe testing, portability, and graceful shutdown.

    Ler mais

    Tempo de leitura: 5 minutos
    11/10/2026
    Python asynchronous code on a laptop for inspect.markcoroutinefunction
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    markcoroutinefunction: Detect Async Wrappers

    Learn inspect.markcoroutinefunction in Python to identify async wrappers, integrate frameworks, and avoid incorrect coroutine detection.

    Ler mais

    Tempo de leitura: 5 minutos
    10/10/2026
    Python code for traversing folders and files with Path.walk
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Path.walk: Traverse Directories Safely

    Learn Python Path.walk to traverse directories, filter files, handle errors, and control directory-tree processing safely.

    Ler mais

    Tempo de leitura: 5 minutos
    10/10/2026
    Python process debugging in a terminal with source code
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    pdb -p: Debug Running Python Processes

    Learn how to attach pdb to a running Python process, inspect stacks, and diagnose hangs safely.

    Ler mais

    Tempo de leitura: 6 minutos
    09/10/2026
    Python programming code for exact fractions
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    fractions.from_number: Convert Numbers to Fractions

    Learn Python fractions.from_number for exact rational conversion, float and Decimal handling, approximation, validation, and safe arithmetic.

    Ler mais

    Tempo de leitura: 4 minutos
    09/10/2026
    Developer configuring a Python HTTPS server and TLS certificate
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    HTTPSServer: Build a Local HTTPS Server in Python

    Learn Python HTTPSServer for local HTTPS services, TLS certificates, threaded handling, testing, and practical security limits.

    Ler mais

    Tempo de leitura: 4 minutos
    08/10/2026