How “print” work in python?

In python print point to sys.stdout.write. In other words, when calling print, python will call sys.stdout.write(obj+’\n’) .

Let me give an example to prof that.

First I define a function named fun1 which write parameter to a file test.txt. Then make sys.stdout.write point to fun1. And try to print something.

import sys

def fun1(temp):
    with open("test.txt","a+") as file:
        file.write(temp)

sys.stdout.write=fun1
print(1)
print(2)
print(3)

Then we will find we have a new file where it’s content is 1 2 3.

How to redirect it to logging?

So we have known how print work . Then we need redirct it.

We should make stdout point to another class which overwrite write and flush method. Like that:

class LoggerWriter:
    def __init__(self, logger):
        self.logger = logger

    def write(self, message):
        self.logger.info(message)

    def flush(self):
        pass

Besides, we should save a pointer to origin stdout.

The complete code to do it ( using decorator ):

import logging
import sys
import os
import datetime

def log_prints(func):
    logger = logging.getLogger(__name__)
    if logger.hasHandlers():
        return logger

    log_file = os.path.join("./log"
                            , os.path.basename(sys.argv[0]).replace(".py", "_%s.log" \
                                                                    % datetime.datetime.now().strftime("%Y%m%d")))
    handler = logging.FileHandler(log_file)
    formatter = logging.Formatter('%(asctime)s %(funcName)-12s %(levelname)-8s %(message)s')
    handler.setFormatter(formatter)
    logger.addHandler(handler)
    logger.addHandler(logging.StreamHandler())
    logger.setLevel(logging.DEBUG)
    logger.info("%s started by %s" % (os.path.basename(sys.argv[0]), os.getlogin()))

    def wrapper(*args, **kwargs):
        import sys
        original_stdout = sys.stdout
        sys.stdout = LoggerWriter(logger)

        result = func(*args, **kwargs)

        sys.stdout = original_stdout

        return result

    return wrapper

class LoggerWriter:
    def __init__(self, logger):
        self.logger = logger

    def write(self, message):
        self.logger.info(message)

    def flush(self):
        pass