Logging utilities that work well with tqdm
Project description
Features
Supported libraries: tqdm, vLLM.
Cleanly store tqdm progress bar in human readable format.
2026-06-27 16:42:16,279 root INFO Processing item 0
2026-06-27 16:42:16,310 root INFO Processing item 1
2026-06-27 16:42:16,310 __main__ INFO tqdm[Processing] done: 2/2 (100.0%), elapsed 0.1s, 32.77 it/s, ETA 0.0s
2026-06-27 16:42:16,331 root INFO Nested step outer=0 inner=0
2026-06-27 16:42:16,373 __main__ INFO tqdm[Inner 0] done: 3/3 (100.0%), elapsed 0.1s, 48.82 it/s, ETA 0.0s
2026-06-27 16:42:16,373 root INFO Completed outer=0
2026-06-27 16:42:16,393 root INFO Nested step outer=1 inner=0
2026-06-27 16:42:16,434 __main__ INFO tqdm[Inner 1] done: 3/3 (100.0%), elapsed 0.1s, 49.61 it/s, ETA 0.0s
2026-06-27 16:42:16,435 root INFO Completed outer=1
2026-06-27 16:42:16,436 __main__ INFO tqdm[Outer] progress: 2/2 (100.0%), elapsed 0.1s, 16.04 it/s, ETA 0.0s
2026-06-27 16:42:16,436 __main__ INFO tqdm[Outer] done: 2/2 (100.0%), elapsed 0.1s, 16.04 it/s, ETA 0.0s
Find out where the logger is called
2026-06-27 16:42:16,470 examples.otherfile INFO Processing item 0
2026-06-27 16:42:16,501 examples.otherfile INFO Processing item 1
2026-06-27 16:42:16,501 examples.otherfile INFO tqdm[Processing items] done: 2/2 (100.0%), elapsed 0.1s, 32.98 it/s, ETA 0.0s
Only print and store log from specific logger (if do setup_logger(name="specific logger"))
2026-06-27 16:42:16,439 test_logger2 INFO Logger2 info message
2026-06-27 16:42:16,439 test_logger2 INFO with multiple lines
2026-06-27 16:42:16,439 test_logger2 INFO and should be logged properly.
Installation
pip install logging-tee
Usage
Run an existing Python program without modifying it
After installing the package, launch a Python command through logging-tee:
logging-tee python demo.py
This creates a timestamped log such as 20260714-153045.log in the current
directory. The launcher configures logging before the target Python program
starts, and captures stdout, stderr, standard logging records, and tqdm
progress snapshots. The target program's exit status is preserved.
Use --log-file to choose the destination and --level to set the minimum
stored logging level:
logging-tee --log-file logs/demo.log --level DEBUG python demo.py --option value
Executable shell scripts are supported too. Shell output is recorded, and any Python process the script starts inherits the logging setup:
logging-tee --log-file output_cli.log --level DEBUG ./examples/bash_cli.sh --random-arg test
For direct Python commands, the launcher configures logging before the program is imported or executed.
Configure logging from Python
Basic usage
import logging
from argparse import ArgumentParser
from logging_tee import setup_logger
if __name__ == "__main__":
setup_logger(log_file="output.log", level=logging.DEBUG)
logger = logging.getLogger()
logger.info("hello world")
Advanced usage
import logging
from tqdm import tqdm
import time
from argparse import ArgumentParser
from logging_tee import setup_logger
from .otherfile import do_something_with_progress, cause_exception
if __name__ == "__main__":
setup_logger(log_file="output.log", level=logging.DEBUG)
logger = logging.getLogger()
logger2 = logging.getLogger("test_logger2")
parser = ArgumentParser(description="Demonstration of logging_tee features.")
parser.add_argument("--random-arg", type=str, help="A random argument for demonstration purposes.")
args = parser.parse_args()
logger.info("Random argument received: %s", args.random_arg)
# demonstrate tqdm pbar
total = 17
batch_size = 16
pbar = tqdm(total=total, desc="Overall Progress")
for i in range(0, total, batch_size):
time.sleep(2)
pbar.update(batch_size)
pbar.close()
# demonstrate tqdm pbar with dynamic postfix
additional_info = 2
pbar = tqdm(range(3), total=3, desc="Outer Progress")
for i in pbar:
time.sleep(2)
additional_info *= 2
pbar.set_postfix({
"additional_info": f"{additional_info}",
"more_info": f"{additional_info * 2}",
})
# demonstrate nested tqdm pbar
for i in tqdm(
range(2),
desc="Processing",
):
time.sleep(2)
logger.info("Processing item %d", i)
for outer_idx in tqdm(
range(2),
desc="Outer",
):
time.sleep(2)
for inner_idx in tqdm(
range(3),
desc=f"Inner {outer_idx}",
):
time.sleep(2)
if inner_idx % 5 == 0:
print(f"Nested step outer={outer_idx} inner={inner_idx}")
logger.info(f"Completed outer={outer_idx}")
# demonstrate logging with multiple lines
print("from print statement")
print("multiple lines\nfrom print statement 2")
logger.debug("Single line")
logger.debug("Multiple lines:\nnext line")
logger.debug("Another single line")
logger.debug("Multiple lines:\n%s", "next line\nnext line 2")
logger.warning("Warning message\nwith multiple lines\nand should be logged properly.")
logger.error("Error message\nwith multiple lines\nand should be logged properly.")
# demonstrate using a second logger
logger2.info("Logger2 info message\nwith multiple lines\nand should be logged properly.")
# demonstrate running logger in other file
do_something_with_progress()
cause_exception()
output.log
2026-07-14 22:26:43,586 root INFO Random argument received: test
2026-07-14 22:26:45,591 __main__ INFO tqdm[Overall Progress] progress: 16/17 (94.1%), elapsed 2.0s, 7.99 it/s, ETA 0.1s
2026-07-14 22:26:47,593 __main__ INFO tqdm[Overall Progress] progress: 17/17 (100.0%), elapsed 4.0s, 7.99 it/s, ETA 0.0s
2026-07-14 22:26:47,593 __main__ INFO tqdm[Overall Progress] done: 17/17 (100.0%), elapsed 4.0s, 7.99 it/s, ETA 0.0s
2026-07-14 22:26:49,597 __main__ INFO tqdm[Outer Progress] progress: 1/3 (33.3%), elapsed 2.0s, 0.50 it/s, ETA 4.0s, additional_info=4, more_info=8
2026-07-14 22:26:51,601 __main__ INFO tqdm[Outer Progress] progress: 2/3 (66.7%), elapsed 4.0s, 0.50 it/s, ETA 2.0s, additional_info=8, more_info=16
2026-07-14 22:26:53,604 __main__ INFO tqdm[Outer Progress] progress: 3/3 (100.0%), elapsed 6.0s, 0.50 it/s, ETA 0.0s, additional_info=16, more_info=32
2026-07-14 22:26:53,605 __main__ INFO tqdm[Outer Progress] done: 3/3 (100.0%), elapsed 6.0s, 0.50 it/s, ETA 0.0s, additional_info=16, more_info=32
2026-07-14 22:26:55,609 root INFO Processing item 0
2026-07-14 22:26:55,610 __main__ INFO tqdm[Processing] progress: 1/2 (50.0%), elapsed 2.0s, 0.50 it/s, ETA 2.0s
2026-07-14 22:26:57,613 root INFO Processing item 1
2026-07-14 22:26:57,614 __main__ INFO tqdm[Processing] progress: 2/2 (100.0%), elapsed 4.0s, 0.50 it/s, ETA 0.0s
2026-07-14 22:26:57,615 __main__ INFO tqdm[Processing] done: 2/2 (100.0%), elapsed 4.0s, 0.50 it/s, ETA 0.0s
2026-07-14 22:27:01,618 root INFO Nested step outer=0 inner=0
2026-07-14 22:27:01,619 __main__ INFO tqdm[Inner 0] progress: 1/3 (33.3%), elapsed 2.0s, 0.50 it/s, ETA 4.0s
2026-07-14 22:27:03,622 __main__ INFO tqdm[Inner 0] progress: 2/3 (66.7%), elapsed 4.0s, 0.50 it/s, ETA 2.0s
2026-07-14 22:27:05,625 __main__ INFO tqdm[Inner 0] progress: 3/3 (100.0%), elapsed 6.0s, 0.50 it/s, ETA 0.0s
2026-07-14 22:27:05,626 __main__ INFO tqdm[Inner 0] done: 3/3 (100.0%), elapsed 6.0s, 0.50 it/s, ETA 0.0s
2026-07-14 22:27:05,626 root INFO Completed outer=0
2026-07-14 22:27:05,626 __main__ INFO tqdm[Outer] progress: 1/2 (50.0%), elapsed 8.0s, 0.12 it/s, ETA 8.0s
2026-07-14 22:27:09,632 root INFO Nested step outer=1 inner=0
2026-07-14 22:27:09,633 __main__ INFO tqdm[Inner 1] progress: 1/3 (33.3%), elapsed 2.0s, 0.50 it/s, ETA 4.0s
2026-07-14 22:27:11,636 __main__ INFO tqdm[Inner 1] progress: 2/3 (66.7%), elapsed 4.0s, 0.50 it/s, ETA 2.0s
2026-07-14 22:27:13,638 __main__ INFO tqdm[Inner 1] progress: 3/3 (100.0%), elapsed 6.0s, 0.50 it/s, ETA 0.0s
2026-07-14 22:27:13,639 __main__ INFO tqdm[Inner 1] done: 3/3 (100.0%), elapsed 6.0s, 0.50 it/s, ETA 0.0s
2026-07-14 22:27:13,640 root INFO Completed outer=1
2026-07-14 22:27:13,641 __main__ INFO tqdm[Outer] progress: 2/2 (100.0%), elapsed 16.0s, 0.12 it/s, ETA 0.0s
2026-07-14 22:27:13,641 __main__ INFO tqdm[Outer] done: 2/2 (100.0%), elapsed 16.0s, 0.12 it/s, ETA 0.0s
2026-07-14 22:27:13,642 root INFO from print statement
2026-07-14 22:27:13,642 root INFO multiple lines
2026-07-14 22:27:13,642 root INFO from print statement 2
2026-07-14 22:27:13,643 root DEBUG Single line
2026-07-14 22:27:13,643 root DEBUG Multiple lines:
2026-07-14 22:27:13,643 root DEBUG next line
2026-07-14 22:27:13,643 root DEBUG Another single line
2026-07-14 22:27:13,643 root DEBUG Multiple lines:
2026-07-14 22:27:13,643 root DEBUG next line
2026-07-14 22:27:13,643 root DEBUG next line 2
2026-07-14 22:27:13,644 root WARNING Warning message
2026-07-14 22:27:13,644 root WARNING with multiple lines
2026-07-14 22:27:13,644 root WARNING and should be logged properly.
2026-07-14 22:27:13,644 root ERROR Error message
2026-07-14 22:27:13,644 root ERROR with multiple lines
2026-07-14 22:27:13,644 root ERROR and should be logged properly.
2026-07-14 22:27:13,644 test_logger2 INFO Logger2 info message
2026-07-14 22:27:13,644 test_logger2 INFO with multiple lines
2026-07-14 22:27:13,644 test_logger2 INFO and should be logged properly.
2026-07-14 22:27:13,675 examples.otherfile INFO Processing item 0
2026-07-14 22:27:13,706 examples.otherfile INFO Processing item 1
2026-07-14 22:27:13,707 examples.otherfile INFO tqdm[Processing items] done: 2/2 (100.0%), elapsed 0.1s, 32.28 it/s, ETA 0.0s
2026-07-14 22:27:13,708 root ERROR Uncaught exception
2026-07-14 22:27:13,708 root ERROR Traceback (most recent call last):
2026-07-14 22:27:13,708 root ERROR File "/home/npu-tao/micromamba/envs/multihop/lib/python3.10/runpy.py", line 196, in _run_module_as_main
2026-07-14 22:27:13,708 root ERROR return _run_code(code, main_globals, None,
2026-07-14 22:27:13,708 root ERROR File "/home/npu-tao/micromamba/envs/multihop/lib/python3.10/runpy.py", line 86, in _run_code
2026-07-14 22:27:13,708 root ERROR exec(code, run_globals)
2026-07-14 22:27:13,708 root ERROR File "/media/npu-tao/disk4T/jason/logging-tee/examples/demo.py", line 77, in <module>
2026-07-14 22:27:13,708 root ERROR cause_exception()
2026-07-14 22:27:13,708 root ERROR File "/media/npu-tao/disk4T/jason/logging-tee/examples/otherfile.py", line 13, in cause_exception
2026-07-14 22:27:13,708 root ERROR raise ValueError("This is an error message\nwith multiple lines\nand should be logged properly.")
2026-07-14 22:27:13,708 root ERROR ValueError: This is an error message
2026-07-14 22:27:13,708 root ERROR with multiple lines
2026-07-14 22:27:13,708 root ERROR and should be logged properly.
Contributing
Increase version in pyproject.toml file.
Modify the src folder.
If using logging_tee in other repository
export PYTHONPATH=<path-to-folder>/src:$PYTHONPATH
python -c "import logging_tee; print(logging_tee)"
If using logging_tee in this repository
export PYTHONPATH=src/:$PYTHONPATH
python -c "import logging_tee; print(logging_tee)"
Run the test
python -m pytest tests -s
Build the package
python -m pip install build
python -m build
pip install dist/*.whl
python -c "import logging_tee; print(logging_tee)"
Upload to TestPyPI first
python -m pip install twine
python -m twine upload --repository testpypi dist/*
python -m pip install --index-url https://test.pypi.org/simple logging-tee
Upload to PyPi
python -m twine upload dist/*
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file logging_tee-1.0.12.tar.gz.
File metadata
- Download URL: logging_tee-1.0.12.tar.gz
- Upload date:
- Size: 18.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6193c0868a5593644b5a53181f3c3fd4e43f2c7656ee9d39a8ff7b6fbde074e8
|
|
| MD5 |
0aaf2d78bf7d452fd36045fb3e5f3c10
|
|
| BLAKE2b-256 |
2bc645ae985d9338f0d1a9b7bdbcc11fe4f65f6ccb3fd3ce6868e5516923cdbf
|
Provenance
The following attestation bundles were made for logging_tee-1.0.12.tar.gz:
Publisher:
pypi.yml on jasonrichdarmawan/logging-tee
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
logging_tee-1.0.12.tar.gz -
Subject digest:
6193c0868a5593644b5a53181f3c3fd4e43f2c7656ee9d39a8ff7b6fbde074e8 - Sigstore transparency entry: 2185053954
- Sigstore integration time:
-
Permalink:
jasonrichdarmawan/logging-tee@98d23d864e21915a4f53dfa344d9aa5dbb37f0fa -
Branch / Tag:
refs/tags/v1.0.12 - Owner: https://github.com/jasonrichdarmawan
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi.yml@98d23d864e21915a4f53dfa344d9aa5dbb37f0fa -
Trigger Event:
release
-
Statement type:
File details
Details for the file logging_tee-1.0.12-py3-none-any.whl.
File metadata
- Download URL: logging_tee-1.0.12-py3-none-any.whl
- Upload date:
- Size: 13.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
021f78c74af775b122eb26109b0ca0d1a2a994146cbbc4dd35118e6551d08198
|
|
| MD5 |
71cd29c202d0d147648205b84145659a
|
|
| BLAKE2b-256 |
2b862850e6043df9d22ef26fb41c1965b399d6502a1ad84a600c79cfa0ec4fc9
|
Provenance
The following attestation bundles were made for logging_tee-1.0.12-py3-none-any.whl:
Publisher:
pypi.yml on jasonrichdarmawan/logging-tee
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
logging_tee-1.0.12-py3-none-any.whl -
Subject digest:
021f78c74af775b122eb26109b0ca0d1a2a994146cbbc4dd35118e6551d08198 - Sigstore transparency entry: 2185054163
- Sigstore integration time:
-
Permalink:
jasonrichdarmawan/logging-tee@98d23d864e21915a4f53dfa344d9aa5dbb37f0fa -
Branch / Tag:
refs/tags/v1.0.12 - Owner: https://github.com/jasonrichdarmawan
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi.yml@98d23d864e21915a4f53dfa344d9aa5dbb37f0fa -
Trigger Event:
release
-
Statement type: