{"id":192,"library":"loguru","title":"Loguru Python Logging","description":"Simple Python logging library. Current version: 0.7.3 (Mar 2026). One global logger — no instantiation needed, just import. Default sink is stderr (not stdout). diagnose=True is the DEFAULT — shows variable values in tracebacks — leaks sensitive data in production. Must call logger.remove() before reconfiguring. Library authors must never call logger.add() — use logger.disable() instead. enqueue=True requires logger.complete() on shutdown to flush queued messages.","status":"active","version":"0.7.3","language":"python","source_language":"en","source_url":"https://github.com/Delgan/loguru","tags":["loguru","logging","python","observability"],"install":[{"cmd":"pip install loguru","lang":"bash","label":"Python"}],"dependencies":[],"imports":[{"note":"Default handler (id=0) outputs to stderr. Call logger.remove() or logger.remove(0) before adding sinks to avoid duplicate output. diagnose=True is the default — always set diagnose=False in production.","wrong":"from loguru import logger\n\n# Wrong: adding new sink without removing default\n# Now logs go to BOTH stderr AND your new sink\nlogger.add('app.log')  # default stderr sink still active\n\n# Wrong: diagnose=True (default) in production leaks variable values\nlogger.add('prod.log', diagnose=True)  # exposes sensitive data in tracebacks","symbol":"basic usage + reconfigure","correct":"import sys\nfrom loguru import logger\n\n# Remove default stderr handler before reconfiguring\nlogger.remove()\n\n# Add stdout handler with INFO level\nlogger.add(\n    sys.stdout,\n    level='INFO',\n    format='{time:YYYY-MM-DD HH:mm:ss} | {level} | {name}:{line} | {message}',\n    diagnose=False,   # IMPORTANT: disable in production — prevents variable leak\n    backtrace=True\n)\n\n# Add file sink with rotation\nlogger.add(\n    'logs/app.log',\n    level='DEBUG',\n    rotation='10 MB',\n    retention='7 days',\n    compression='zip',\n    diagnose=False,\n    serialize=False\n)\n\nlogger.info('App started')\nlogger.debug('Debug message')\nlogger.warning('Watch out')\n\n# Exception catching\ntry:\n    1 / 0\nexcept Exception:\n    logger.exception('Division failed')"},{"note":"Libraries must call logger.disable(__name__) and never call logger.add(). Application code enables library logging with logger.enable('library_name') if desired.","wrong":"# Wrong in a library — forces logging config on app developer\nfrom loguru import logger\nlogger.add('library.log')  # pollutes app's logging","symbol":"library usage","correct":"# In a library — NEVER call logger.add()\nfrom loguru import logger\n\n# Disable by default — let app developer enable if they want\nlogger.disable(__name__)\n\ndef my_library_function():\n    logger.debug('Library internal log')  # no-op unless enabled by app"}],"quickstart":{"code":"# pip install loguru\nimport sys\nfrom loguru import logger\n\n# Reconfigure: remove default stderr, add stdout + file\nlogger.remove()\nlogger.add(sys.stdout, level='INFO', diagnose=False)\nlogger.add('app.log', level='DEBUG', rotation='50 MB', diagnose=False)\n\n# Basic logging\nlogger.debug('Debug message')\nlogger.info('Server started on port 8000')\nlogger.warning('Low disk space')\nlogger.error('Connection failed')\nlogger.critical('Database unreachable')\n\n# Exception logging with full traceback\ntry:\n    result = 1 / 0\nexcept ZeroDivisionError:\n    logger.exception('Calculation failed')  # logs traceback automatically\n\n# Catch decorator\n@logger.catch\ndef risky_function(x):\n    return 100 / x\n\nrisky_function(0)  # caught and logged automatically\n\n# Structured context with bind()\nrequest_logger = logger.bind(request_id='req-123', user_id='usr-456')\nrequest_logger.info('Processing payment')\n\n# JSON output for log aggregators\nlogger.add('app.json', serialize=True, diagnose=False)\n\n# Async / multiprocess safe\nlogger.add('async.log', enqueue=True, diagnose=False)\n# On shutdown:\nimport asyncio\nasyncio.run(logger.complete())  # flush queued messages","lang":"python","description":"Loguru — reconfigure, file rotation, exception catching, structured context."},"warnings":[{"fix":"Always set diagnose=False in production: logger.add('prod.log', diagnose=False)","message":"diagnose=True is the DEFAULT for all sinks. It displays variable values in exception tracebacks — leaks passwords, tokens, PII in production logs.","severity":"breaking","affected_versions":"all"},{"fix":"Call logger.remove() before logger.add() to remove the default stderr handler.","message":"Default sink outputs to stderr, not stdout. Many developers expect stdout. Adding a new sink without calling logger.remove() causes duplicate log output.","severity":"gotcha","affected_versions":"all"},{"fix":"In library code: logger.disable(__name__). In app code: logger.enable('library_name') to see library logs.","message":"Library authors must never call logger.add(). Call logger.disable(__name__) instead. Calling add() in a library forces logging config on every downstream application.","severity":"gotcha","affected_versions":"all"},{"fix":"await logger.complete() in async code, or asyncio.run(logger.complete()) at shutdown.","message":"enqueue=True (multiprocess/async safe) requires logger.complete() on shutdown. Without it, buffered messages in the queue are lost when the process exits.","severity":"gotcha","affected_versions":"all"},{"fix":"Use string names: logger.log('INFO', 'message') not logger.log(20, 'message')","message":"Passing integer log levels to logger.log() displays as anonymous level ('Level 20') instead of level name. Loguru identifies levels by name, not number.","severity":"gotcha","affected_versions":"all"},{"fix":"handler_id = logger.add(...); logger.remove(handler_id) to remove specific sink.","message":"logger.add() returns a handler ID integer. logger.remove() requires this ID to remove a specific handler. Calling logger.remove() with no args removes ALL handlers.","severity":"gotcha","affected_versions":"all"}],"env_vars":null,"last_verified":"2026-05-12T09:56:16.977Z","next_check":"2026-06-25T00:00:00.000Z","problems":[{"fix":"Run `pip install loguru` in your terminal.","cause":"The Loguru library has not been installed in the active Python environment.","error":"ModuleNotFoundError: No module named 'loguru'"},{"fix":"Explicitly set `diagnose=False` when adding sinks in production: `logger.add('file.log', diagnose=False)`.","cause":"The default `diagnose=True` parameter for sinks in Loguru includes local variable values in exception tracebacks, which can expose sensitive information in production environments.","error":"Sensitive data leakage in production logs due to diagnose=True"},{"fix":"Call `logger.remove()` (optionally with the handler ID, e.g., `logger.remove(0)` for the default handler) before `logger.add()` to prevent duplicate handlers. For multiprocessing, wrap logger configuration in `if __name__ == '__main__':`.","cause":"The logger is being configured multiple times by repeatedly calling `logger.add()` without first calling `logger.remove()`, or by running configuration code in a multiprocessing environment without proper `if __name__ == '__main__':` guards.","error":"Logs are duplicated"},{"fix":"Escape literal curly braces in f-strings with double braces (`{{` and `}}`) or pass the data as separate arguments to Loguru's logging methods if they are intended for structured logging.","cause":"Loguru's message formatting uses `str.format()` semantics for positional and keyword arguments, which can conflict with f-strings that contain unescaped curly braces not intended as format placeholders.","error":"KeyError: 'some_key' or ValueError: Single '{' encountered in format string when logging f-strings"},{"fix":"Configure Loguru to use a lambda function as the sink to dynamically retrieve `sys.stderr` or `sys.stdout` (e.g., `logger.add(lambda m: sys.stderr.write(m))`), or ensure the logger is re-initialized if the standard streams might be replaced.","cause":"Another library, IDE, or environment tool has replaced or closed `sys.stderr` or `sys.stdout` while Loguru was still attempting to write to it.","error":"ValueError: I/O operation error on closed file"}],"ecosystem":"pypi","meta_description":null,"install_score":80,"install_tag":"verified","quickstart_score":0,"quickstart_tag":"stale","pypi_latest":null,"install_checks":{"last_tested":"2026-05-12","tag":"verified","tag_description":"installs cleanly on critical runtimes, fast import, recently tested","results":[{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0,"disk_size":"18.2M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0,"disk_size":"19M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0,"disk_size":"20.1M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0,"disk_size":"21M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0,"disk_size":"12.0M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0,"disk_size":"13M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0,"disk_size":"11.6M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0,"disk_size":"12M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0,"disk_size":"17.7M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0,"disk_size":"18M"}]},"quickstart_checks":{"last_tested":"2026-04-23","tag":"stale","tag_description":"widespread failures or data too old to trust","results":[{"runtime":"python:3.10-alpine","exit_code":1},{"runtime":"python:3.10-slim","exit_code":1},{"runtime":"python:3.11-alpine","exit_code":1},{"runtime":"python:3.11-slim","exit_code":1},{"runtime":"python:3.12-alpine","exit_code":1},{"runtime":"python:3.12-slim","exit_code":1},{"runtime":"python:3.13-alpine","exit_code":1},{"runtime":"python:3.13-slim","exit_code":1},{"runtime":"python:3.9-alpine","exit_code":1},{"runtime":"python:3.9-slim","exit_code":1}]}}