Home > database >  Python: I am printing to console and file at the same time, but getting double prints when adding te
Python: I am printing to console and file at the same time, but getting double prints when adding te

Time:03-19

I want to print to console and a file at the same time. Following the examples in Stackoverflow question I managed to get it working with:

class DoublePrint(object):
    def __init__(self, filename):
        self.stream = sys.stdout
        self.logfile = open(filename, 'w')   # File for logging

    def __enter__(self):
        sys.stdout = self

    def __exit__(self, exc_type, exc_value, traceback):
        sys.stdout = self.orig_stdout
        self.logfile.close()

    def write(self, data):
        self.stream.write(data)
        self.logfile.write(data)
        self.flush()

    def flush(self):
        self.stream.flush()
        self.logfile.flush()

print("Only console 1")

with DoublePrint('pyLog.log'):
    print("To both console and file")

print("Only console 2")

This prints to console:

Only console 1
To both console and file
Only console 2

And in the file "pyLog.log":

To both console and file

This is exactly what I want.

However, when I try to add a timestamp to data in the write-method, I get double prints of timestamp. And I don't understand why this is, and how to make it right.

def write(self, data):
    output = subprocess.run(["date", " %H:%M:%S"], capture_output=True, text=True)
    toprint = output.stdout.strip()   data
    self.stream.write( toprint )
    self.logfile.write( toprint )
    self.flush()

Produces the following output in the console:

Only console 1
17:23:09To both console and file17:23:09
Only console 2

Why do I get the time in the end too? And how do I avoid it?

CodePudding user response:

The issue comes from the fact that print calls write on sys.output twice, once with data="To both console and file", once with data="\n", which explains the observed behavior. If you want to automatically add dates, you should instead keep track of if a date has already been inserted in this line.

By the way, in python 3 (which I assume you are using, since it's one of the tags) you don't need to explicitly inherit from object. You can simply write

class DoublePrinter:
      [...]

CodePudding user response:

Here's a way to do it, building on the answer by @BlackBeans (which pointed out that print() calls write() twice: once for its argument and a second time for '\n') and substituting platform independent Python logic to print the date:

import sys
import subprocess
import datetime
class DoublePrint:
    def __init__(self, filename):
        self.stream = sys.stdout
        self.logfile = open(filename, 'w')   # File for logging

    def __enter__(self):
        sys.stdout = self

    def __exit__(self, exc_type, exc_value, traceback):
        #sys.stdout = self.orig_stdout
        sys.stdout = self.stream
        self.logfile.close()

    def writex(self, data):
        self.stream.write(data)
        self.logfile.write(data)
        self.flush()

    def write(self, data):
        '''
        output = subprocess.run(["date", " %H:%M:%S"], capture_output=True, text=True)
        toprint = output.stdout.strip()   data
        '''
        toprint = data if data == '\n' else datetime.datetime.now().strftime("%H:%M:%S ")   data
        self.stream.write( toprint )
        self.logfile.write( toprint )
        self.flush()

    def flush(self):
        self.stream.flush()
        self.logfile.flush()

print("Only console 1")

with DoublePrint('pyLog.log'):
    print("To both console and file")

print("Only console 2")

Output:

Only console 1
13:26:19 To both console and file
Only console 2
  • Related