8

I have a program using the logging module and the print statement. The logging is to inform the user what the program is doing, for example

logging.info("downloading HTML")
time.sleep(1)
logging.info("parsing HTML")
time.sleep(1)
print "the result"

at the end the output on the screen (mixing stdout and stderr) will be:

INFO:downloading HTML
INFO:parsing HTML
the result

I want to hide the last logging output when the next logging output is displayed or when the print is called. For example, start the program, you will see:

INFO:download HTML

wait one seconds, the next info "parsing HTML" will replace the previous "downloading HTML", so on the screen you will see only:

INFO:parsing HTML

and nothing else before, then wait one second, I want to see on the screen only:

"the result"

I want this feauture only when logging on the stderr, and not when logging to a file for example, there I want to see all the logging outputs.

Is it possible?

Ruggero Turra
  • 16,929
  • 16
  • 85
  • 141
  • Does not make much sense since such a behavior can only be handled (if ever) through the console handler. Since the logging call is delegated to a list of registered handler there is no generic way to do this. You want misuse the logging module here. –  Aug 16 '12 at 09:57
  • Nope, writing to standard output is a one way street, there's no way to take back what you have written. You could, however, set your terminal to display one line only. – Kien Truong Aug 16 '12 at 10:03
  • @Dikei: you are right, but you can change what is printed on the screen, for example using `'\r'` – Ruggero Turra Aug 16 '12 at 10:07
  • @Maulwurfn: new handler? Sorry, I'm not expert – Ruggero Turra Aug 16 '12 at 10:08
  • You might want to look into [curses](https://duckduckgo.com/?q=python+curses). I have no experience with it, but I've heard about it in a related question. – BrtH Aug 16 '12 at 10:20
  • Or look at [this](http://stackoverflow.com/a/3160819/1248554) or [this](http://stackoverflow.com/a/3173338/1248554) – BrtH Aug 16 '12 at 10:25
  • @BrtH, Yeah, seems like you could write a custom `Handler` that clears the line before printing the next logging message. Though the others are right that this probably isn't the thing to use `logging` for. – Silas Ray Aug 16 '12 at 11:11
  • thank you, but the point is to integrate everythings using the `logging` module – Ruggero Turra Aug 16 '12 at 11:30
  • Hence my comment about using a custom `Handler`. I'll try to put up an answer when I have more time. – Silas Ray Aug 16 '12 at 12:01

1 Answers1

14

On unix-like terminals, you can try prepending ANSI escape sequences to the text;

import time
import sys

print 'this is a text',
sys.stdout.flush()

time.sleep(1)
print '\x1b[80D'+'\x1b[K'+'Second text',
sys.stdout.flush()

The character '\x1b' is the escape character. The first sequence moves the cursor up to 80 positions to the left. The second clears the line.

You need the comma at the end of the print statement to prevent it from going to the second line. Then you need to flush the stdout stream otherwise the text won't appear.

Edit: For combinging this with logging, wrap it in a simple function:

def mylog(text):
    logging.info(text)
    print '\x1b[80D' + '\x1b[K'+ text,
    sys.stdout.flush()

EDIT 2: Integrating this into the standard logging;

import logging
# create console handler
ch = logging.StreamHandler()
# create formatter
formatter = logging.Formatter('\x1b[80D\x1b[1A\x1b[K%(message)s')
# add formatter to console handler
ch.setFormatter(formatter)
# add console handler to logger
logger.addHandler(ch)

Since the logging module seems to add newlines by itself, I've added an ANSI sequense (\x1b[1A) to go up one line.

Also see the logging howto for more information.

Roland Smith
  • 42,427
  • 3
  • 64
  • 94
  • thank you, but the point is that I want to integrate it into the `logging` module – Ruggero Turra Aug 16 '12 at 15:13
  • mmm, yes, I'm able to do that, the point is that I want to integrate it using the logging module, suppose I'm using advanced feautures like formatters, custom levels, ... in addition the first line of your function in useless, you can remove it, you're not using the `logging` module. Finally I don't want to change my code, only define a new logger class – Ruggero Turra Aug 19 '12 at 21:03
  • You only have to add a new formatter to the stream handler. See edit 2. – Roland Smith Aug 20 '12 at 10:03