Logduo
Logging, console output, and file management for Python scripts and interactive sessions.
Simple by default, configurable for advanced logging workflows.
Platform: Tested on macOS, Windows, and Ubuntu.
Key Capabilities
- Manages output directories and log files
- Supports ANSI-styled and Rich console output while preserving readable plain-text logs
- Provides extensive
help()documentation and actionable error messages - Validates arguments to all Logduo methods and functions to prevent unexpected behavior
- Safely prunes old run directories containing a Logduo marker file
- Generates optional session artifacts:
config_table.txt,config.json - Captures JSONL event streams
- Creates dedicated log files via
new_logger() - Creates advanced pass-through Loguru sinks via
new_loguru_sink() - Creates custom logging labels via
new_level() - Supports nested scripts via
log.join()andrun() - Reports files created during the logging session in console and log footers
Quick Start (in script or interactive session)
from logduo import log
log("hello world")
log.warning("warning message")
If a message is logged before log.configure() is called, the logging session starts automatically using Logduo defaults and pyproject.toml settings.
Key default settings:
console_verbosity = 3andlog_verbosity = 3- All messages (including TRACE and DEBUG) are sent to both the console and the main log file.
console_prefix = "level"andlog_prefix = "timestamp"- Console messages show the logging level without a timestamp.
- Log-file messages include the timestamp and logging level.
- Set
console_prefix="timestamp"to include timestamps in console output, orconsole_prefix="off"to omit the prefix entirely.
log_file_mode = "write"- Existing log files are overwritten.
- Set
log_file_mode="append"to preserve existing contents. - Set
log_file_mode="timestamped"to add a timestamp to the filename.
log_dir_path = "auto"- The
logsdirectory is placed in the project root if identified; otherwise, in the current working directory.
- The
log_file_layout = "run"- Logs are created in timestamped run directories.
keep = "off"- Previous run directories are not pruned automatically.
- If
keepis set to a positive integern, the newestnLogduo-marked run directories are kept and older run directories are pruned.
write_config_table = Trueconfig_table.txtis written with configuration values, descriptions, and allowed values.
Example Output
logging started: 2026-07-20 10:10:28
running script : main.py
pruned run directories: 1 (keep=3)
| INFO | hello world
───────────────────────────────────────────────────────
logging ended : 2026-07-20 10:10:28 (duration 00 sec)
script path : temp_project/main.py
output directory: temp_project/logs/main/run_2026_07_20__10_10_28
files created this logging session in output directory:
config_table.txt
main.log
Configure (Optional)
Recommendation: Place regularly used configuration settings in pyproject.toml under [tool.logduo]
from pathlib import Path
from logduo import log
my_log_dir = Path("/absolute/path/to/my_log_dir")
log.configure(log_dir_path=my_log_dir, keep=3)
log("hello world")
Export Logduo Docs
Export bundled documentation and example scripts to a local logduo_docs/ directory:
log.export_logduo_docs()
Exported files include:
README.txtexamples/first_script.pyexamples/console_rendering.pyexamples/data_analysis.pyexamples/math_report_notation.pyexamples/nested_parent_script.pyexamples/nested_child_script.py
Help
-
Help is available for all Logduo methods and functions (displays in console only):
help(log.configure) -
Help includes examples, argument descriptions, and usage notes.
Typical Workflows
-
Debug session: By default,
log.debug()includes the calling filename and line number at the start of each message.-
Disable source information with
log.configure(show_debug_source=False). -
Debug messages are displayed when the corresponding verbosity setting is 3. Both
console_verbosityandlog_verbositydefault to 3.from logduo import log log.debug(f"made it here: var = {var}")
-
-
Create additional log files for dedicated output. Messages logged with
repare recorded in report.log and optionally mirrored to the console and/or main log file.rep = log.new_logger("report", to_console=True, to_main_log=False) rep("Question 1 answer:") -
Use the output directory to save plots, CSVs, reports, and other generated files
myplot_output_path = log.output_dir_path / "myplot.png" -
Close the session explicitly in interactive sessions. Logging sessions in scripts are closed automatically at interpreter shutdown, with best-effort cleanup during abnormal shutdown. Explicit
log.close()is still supported.log.close()
Logduo Methods and Functions
-
Manage session:
log.configure()log.close()log.join()
-
Log levels:
log()orlog.info()log.trace()log.debug()log.success()log.warning()log.error()log.critical()log.exception()# ERROR + Traceback
-
Create custom log label:
log.new_level()# Maps a custom display label to an existing severity level; default severity = "INFO"
-
Create additional output:
log.new_logger()# Logduo-managed extra log filelog.new_loguru_sink()# Advanced Loguru sinklog.export_logduo_docs()
-
Access paths:
log.output_dir_pathlog.main_log_file_path
-
Utility function:
run()# Execute child script or importable module in a parent script or an interactive session.- Import with:
from logduo import run
Behavior
Prefixes
-
One prefix per log event.
-
Console and log files have independent prefix settings:
console_prefix,log_prefixoff→ No prefix. Wrapped lines align flush left.level→ Prefix shows level. Wrapped lines align under message.timestamp→ Prefix shows timestamp and level. Wrapped lines align under message.source→ Prefix shows timestamp, level, and source. Wrapped lines align under source.
-
Example console output:
console_prefix="source",show_pid_in_console=True,console_wrap_width=8016:30:40.371 | WARNING | example_2.py:382 - (15408:i1) Logduo is designed for data scientists, researchers, students, and Python developers who want readable console output, organized log files, and minimal logging setup.
Message Rendering
- Strings without
\n: Displayed inline with the prefix.- Console: Wrapped (displayed line width =
console_wrap_width). - Log files: Wrapped only if
log_wrap_widthis set to a positive integer. Default is"off".
- Console: Wrapped (displayed line width =
- Strings containing
\n: Displayed as block flush left below prefix. Line breaks are honored.-
This preserves the full available line width for tables, panels, JSON, tracebacks, and other structured content.
-
Use manual indenting or Rich
Paddingif indent behavior is desired:indent = " " * 13 log( f"{indent}Step 1: Load data\n" f"{indent}Step 2: Clean data\n" )
-
- ANSI-styled strings and Rich
Textobjects are rendered on the console and written as plain text in log files. - Other Rich objects, such as
Panel, are rendered on the console but displayed as placeholders in log files.- For more examples, use
log.export_logduo_docs()and seeconsole_rendering.py.
- For more examples, use
Log File Name and Location
- Log file name:
- Custom
log_file_name:log.configure(log_file_name="my_name.ext") - Default
log_file_name: calling script stem +.log- If the calling script is my_file.py: default
log_file_name→my_file.log - If no calling script is found, as expected in interactive sessions: default
log_file_name→session.log
- If the calling script is my_file.py: default
- Custom
- Location of log directory:
- Custom
log_dir_path:log.configure(log_dir_path=my_log_dir) - Default
log_dir_path:- If pyproject.toml is not detected:
log_dir_path= current working directory / "logs" - If pyproject.toml is detected:
log_dir_path= parent directory of pyproject.toml / "logs"
- If pyproject.toml is not detected:
- Custom
- Location of log file: set by
log_file_layout:"flat","script", or"run"(default)- flat:
log_dir_path/log_file_name - script:
log_dir_path/script_stem/log_file_name - run:
log_dir_path/script_stem/run_yyyy_mm_dd__hh_mm_ss/log_file_name
- flat:
Note:
- If no calling script is found,
script_stemis set to"session"whenlog_file_layout="script"or"run" - If
log_file_pathis provided, it specifies the complete log file pathlog_file_pathoverrideslog_file_layout,log_dir_path, andlog_file_namelog_file_pathdoes not overridelog_file_mode("write","append", or"timestamped")log.output_dir_pathis set to the parent oflog_file_path
Loguru Integration
-
Logduo uses Loguru as its underlying file-sink engine.
-
The following Loguru sink options can be passed through
log.configure():rotation: start a new log file when a size/time rule is met. Example:rotation="10 MB"orrotation="1 week". Userotation="off"for no rotation (default ="off").retention: remove older rotated log files when a retention rule is met. Example:retention="14 days"orretention=5. This applies to rotated files, not to Logduo run-directory pruning (default ="off").compression: compress rotated log files. Example:compression="zip". This applies to rotated files, not the active log file (default ="off").enqueue: write logs through a background queue. Useful for thread/process safety (default =True).catch: catch logging errors instead of letting them crash the program (default =True).backtrace: show extended traceback context for exceptions (default =False).diagnose: include extra variable/context information in exception tracebacks (default =False).
-
Logduo performs message formatting, wrapping, routing, session management, and Rich integration before messages reach Loguru.
-
Use
log.new_logger()when you want a normal Logduo-managed extra log file. -
Use
log.new_loguru_sink()when you want direct Loguru control, such as:- using custom Loguru filters
- adding extra Loguru sinks
- sending selected events to separate destinations
- passing options directly to
logger.add()
-
Sinks added with
log.new_loguru_sink()are advanced pass-through sinks. Logduo manages their creation and session lifecycle, but messages sent directly through Loguru bypass normal Logduo formatting, wrapping, routing, headers, and footers.
Console compatibility
- Logduo supports modern Unicode-capable terminals on Windows, macOS, and Linux.
- Some older or restricted terminals may not display every Rich character correctly.
- Log files are always written as UTF-8.
Quality Assurance
Logduo is validated using:
- pytest, with over 90% coverage on over 600 individual tests
- Ruff
- mypy
- Vulture
Release files for logduo 0.1.4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| logduo-0.1.4.tar.gz | 117.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| logduo-0.1.4-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 260.9 kB
Release files / logduo-0.1.4.tar.gz
| Download URL | logduo-0.1.4.tar.gz |
|---|---|
| Size | 117.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
26fb85013e74973d410f983e41c1843f55b460c34b362629c2c8ff3d020ad812
|
|
BLAKE2b-256 checksum How to use checksums |
c067b54c92fdfe8f31ab0de33c0152a0453926472ce38d546a0118f0b5a05544
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.5
|
Release files / logduo-0.1.4-py3-none-any.whl
| Download URL | logduo-0.1.4-py3-none-any.whl |
|---|---|
| Size | 143.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1b52af1f377ee5c2f127ba811830a088a6db1cee30167c88298f1580c69c0383
|
|
BLAKE2b-256 checksum How to use checksums |
8e017036747582a0a91c5ea0e63352027e5ba6d350391dcda6de7d698c3deab9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.5
|