1

Можно ли как-то записать в файл все, что выводится в консоль? Знаю про существование модуля logging, но у меня слишком много print, чтобы переделывать все под logging

3 Answers3

3

Мне больше по душе вариант с заменой sys.stdout на свою реализацию, которая будет делать всё что нужно. Вот допиленный вариант с enSO:

import sys


class Tee(object):
    def __init__(self, name, mode):
        self.file = open(name, mode)
        self.stdout = sys.stdout

    def __del__(self):
        self.close()

    def write(self, data):
        self.stdout.write(data)
        self.file.write(data)

    def flush(self):
        self.stdout.flush()
        self.file.flush()

    def close(self):
        if sys.stdout is self:
            sys.stdout = self.stdout
        self.file.close()


sys.stdout = Tee('log.txt', 'a')

И никаких замен print на printer не надо :)

andreymal
  • 13,178
3

Как насчет пойти по пути наименьшего сопротивления и воспользоваться стандартными средствами в лице модуля logging?

Если раздражает DEBUG в сообщении, нужно из formatter убрать строку %(levelname)-8s

А чтобы и дальше пользоваться print'ом, сделать простую замену (как правильно подметил в комментарии andreymal, при выводе с другими аргументами, а не только с самим сообщением, могут возникнуть проблемы):

import logging
import sys

def get_logger(name=file, file='log.txt', encoding='utf-8'): log = logging.getLogger(name) log.setLevel(logging.DEBUG)

formatter = logging.Formatter('[%(asctime)s] %(filename)s:%(lineno)d %(levelname)-8s %(message)s')

fh = logging.FileHandler(file, encoding=encoding)
fh.setFormatter(formatter)
log.addHandler(fh)

sh = logging.StreamHandler(stream=sys.stdout)
sh.setFormatter(formatter)
log.addHandler(sh)

return log


log = get_logger() print = log.debug

Обходное решение надуманной проблемы несоответствия аргументов print и debug.

Приятным "побочным" эффектом будет возможность просто писать print()

print = lambda text="": log.debug(text)

if name == 'main': log.debug('foo') log.debug('bar')

print('')
print('foo')
print('bar')

Консоль:

[2017-08-27 03:41:29,929] FOO_TEST_TEST.py:32 DEBUG    foo
[2017-08-27 03:41:29,929] FOO_TEST_TEST.py:33 DEBUG    bar
[2017-08-27 03:41:29,929] FOO_TEST_TEST.py:35 DEBUG    
[2017-08-27 03:41:29,929] FOO_TEST_TEST.py:36 DEBUG    foo
[2017-08-27 03:41:29,929] FOO_TEST_TEST.py:37 DEBUG    bar
gil9red
  • 77,085
  • У print и log.debug разные аргументы, можно случайно прострелить ногу – andreymal Aug 26 '17 at 22:46
  • @andreymal, ну не нужно так пугать :) максимум что случится -- что-то не выведется или при попытке вывести будет ошибка, что закономерно -- не естественный ведь способ :) – gil9red Aug 26 '17 at 23:08
  • А потом побегут сюда же с вопросом "аааааа почему принт сломался", забыв, что принт заменён где-то в начале файла :) – andreymal Aug 27 '17 at 09:15
  • @andreymal по такой логике можно людям вообще рекомендовать не программировать, а то вдруг ошибутся. :) – Nick Volynkin Aug 27 '17 at 16:13
1

Осуществил с помощью

def printer(printing):
    log_file = open("log.txt", "a")
    print(str(datetime.now())+ ' ' + str(printing))
    log_file.write(str(datetime.now()) + ' ' + str(printing) + '\n')
    log_file.close()
    return printer

И заменил все print на printer

  • 2
    а можно было не заменять, а просто написать: print = printer и дальше пользоваться print :) – gil9red Aug 26 '17 at 22:39
  • 2
    @gil9red: можно даже printer не писать: from exterminate import AltPrint # $ pip install exterminate (обратите внимание: текст отправляется в gizoogle). – jfs Aug 27 '17 at 21:43
  • @jfs, судя по примерам какая-то дикая библиотека :) И судя по коду текст отправляется в gizoogle только чтобы сделать перевод на язык Далеков – gil9red Aug 28 '17 at 03:33
  • @gil9red если это не ясно, в моём комментарии не хватает смайлика ;) – jfs Aug 28 '17 at 03:36
  • @jfs, согласен, прикольная библиотека :) – gil9red Aug 28 '17 at 04:09