#744·tqdm

How to create a progress bar to a file instead of sys.stderr, using the logging module?

Author: evandrocoanCreated May 13, 2019Updated Sep 8, 2026
Labelsquestion/docs ‽
  • I have visited the [source website], and in particular read the [known issues]
  • I have searched through the [issue tracker] for duplicates
  • I have mentioned version numbers, operating system and environment, where applicable:
    python
    import tqdm, sys
    print(tqdm.__version__, sys.version, sys.platform)
    # 4.23.4 3.7.2 (default, Jan  2 2019, 17:07:39) [MSC v.1915 64 bit (AMD64)] win32 

This example works fine for a stream handler to sys.stderr:

python
import sys
import tqdm
import time
import logging

class DummyTqdmFile(object):
    file = None

    def __init__(self, file):
        self.file = file

    def write(self, x):
        # Avoid print() second call (useless \n)
        if len( x.rstrip() ) > 0:
            tqdm.tqdm.write( x, file=self.file, end='' )

    def flush(self):
        return getattr( self.file, "flush", lambda: None )()

if __name__ == "__main__":
  logging.basicConfig(level=logging.DEBUG, stream=DummyTqdmFile(sys.stderr))

  log = logging.getLogger(__name__)
  log.info("loop")
  # for x in tqdm.trange(1, 101, mininterval=10):
  for x in tqdm.trange(1, 10):
    time.sleep(1.2)
    if not x % 5:
      log.debug("in loop %d\nnew line" % x)
  log.info("done")

But, what if I am logging to a file like /var/log/myfile.log?

If I change the logger setup line to this:

python
logging.basicConfig(level=logging.DEBUG, filename='myfile.log')

The progress bar is printed to the sys.stderr, not in the file myfile.log.

I tried this variation:

python
import sys
import tqdm
import time
import logging

class DummyTqdmFile(object):
    file = None

    def __init__(self, file):
        self.file = file

    def write(self, x):
        # Avoid print() second call (useless \n)
        if len( x.rstrip() ) > 0:
            tqdm.tqdm.write( x, file=self.file, end='' )

    def flush(self):
        return getattr( self.file, "flush", lambda: None )()

if __name__ == "__main__":
  logging.basicConfig(level=logging.DEBUG, filename='myfile.log')
  log = logging.getLogger(__name__)
  logging.root.handlers[0].stream = DummyTqdmFile(logging.root.handlers[0].stream)

  log.info("loop")
  # for x in tqdm.trange(1, 101, mininterval=10):
  for x in tqdm.trange(1, 10, file=logging.root.handlers[0].stream):
    time.sleep(1.2)
    if not x % 5:
      log.debug("in loop %d\nnew line" % x)
  log.info("done")

It almost worked right, running it, it outputs this to the file:

INFO:__main__:loop

  0%|          | 0/9 [00:00<?, ?it/s]
 11%|#         | 1/9 [00:01<00:09,  1.20s/it]
 22%|##        | 2/9 [00:02<00:08,  1.20s/it]
 33%|###       | 3/9 [00:03<00:07,  1.20s/it]
 44%|####      | 4/9 [00:04<00:06,  1.20s/it]DEBUG:__main__:in loop 5
new line

 56%|#####     | 5/9 [00:06<00:04,  1.20s/it]
 67%|######    | 6/9 [00:07<00:03,  1.20s/it]
 78%|#######   | 7/9 [00:08<00:02,  1.20s/it]
 89%|########  | 8/9 [00:09<00:01,  1.20s/it]
100%|##########| 9/9 [00:10<00:00,  1.20s/it]INFO:__main__:done

But, it is missing a new line after each progress bar, i.e., it should output this:

INFO:__main__:loop

  0%|          | 0/9 [00:00<?, ?it/s]
 11%|#         | 1/9 [00:01<00:09,  1.20s/it]
 22%|##        | 2/9 [00:02<00:08,  1.20s/it]
 33%|###       | 3/9 [00:03<00:07,  1.20s/it]
 44%|####      | 4/9 [00:04<00:06,  1.20s/it]
DEBUG:__main__:in loop 5
new line

 56%|#####     | 5/9 [00:06<00:04,  1.20s/it]
 67%|######    | 6/9 [00:07<00:03,  1.20s/it]
 78%|#######   | 7/9 [00:08<00:02,  1.20s/it]
 89%|########  | 8/9 [00:09<00:01,  1.20s/it]
100%|##########| 9/9 [00:10<00:00,  1.20s/it]
INFO:__main__:done