Найти - Пользователи
Полная версия: Одновременный вывод в консоль и в файл
Начало » Python для новичков » Одновременный вывод в консоль и в файл
1 2
admiral

doza_and
1 Чем этот велосипед лучше модуля logging?
Тем, что он не корректно работает в PyScripter, точнее PyScripter криво работает с ним. Я уже к этой среде разработки привык, и для данной задачи мне достаточно просто дублирования консоли в лог-файл. Больше ничего не требуется.
doza_and
2. Зачем при каждой записи делается проверка?
А как еще убедиться, что файловой переменной соответствует файл? А вдруг не удалось в самом начале файл создать?
Предложите свой вариант, я для этого и выложил эту функцию на всеобщее обозрение.
doza_and
Как
logfile.flush()
повлияет на производительность вашей системы записи логов?
Вот этот момент меня тоже смущает пока. Приложение может работать часами и, если не сохранять в файл, то оно будет потиху отжирать оперативу.
Еще вопрос, если приложение остановиться по исключению, например при нажатии ctrl+c - в лог запишутся все не сохраненные данные?
doza_and
4. Почему вы заловили все Exception и вместо них вывели сообщения в консоль (которой часто у приложения просто нет или ее не видно)?
У меня только консоль, и она всегда видна.
doza_and
5. Как приведенный скрипт решает поставленную вами задачу об одновременном выводе в консоль и файл?
Пока работает отлично. С загрузкой процессора при данном варианте пока не выяснял.

Еще раз повторю, я не профессиональный программист, и не откажусь от вариантов как можно улучшить эту функцию
bw
Я тоже подискутирую, с вашего позволения :-).

2. Зачем logfile is None? А почему нет, какие ещё варианты? С точки зрения снижения производительности тут нет никакого существенного снижения, особенно на фоне операций `strftime`, выполнения print и записи в stdout и в файл. Да и с учётом выбранного условного объёма в 10000 записей, который ни о чём эта операция никак не может повлиять ни на общую производительность приложения, ни даже на отдельно взятую функцию логирования.
Другой аргумент за такой подход, это включение всего функционала по логированию в одну функцию, а не размазывание по нескольким: открытие, логирование, закрытие :-). Если бы использовался класс, то открытие файла можно было бы вынести в отдельный приватный метод или в __init__ экземпляра и выполнять его один раз при создании экземпляра. А как иначе выполнить инкапсуляцию (сокрыть открытие файла от основного кода) без ООП в данном случае, я не знаю.

3. `logfile.flush` не должен влиять на производительность, по крайней мере положительно. Отрицательное влияние если и есть, то оно не существенно. О памяти здесь переживать не стоит, буфер используется небольшой 16kb или 64kb. Кажется Python сам ничего не буферизует, так что после `write` данные передаются ОС и можно не волноваться за то что они попадут куда следует.

4. Ошибки при обработке ошибок больная тема :-). Так что такие обработчики не то что бы совсем лишены смысла. Открытие действительно может не получиться. Запись тоже, скорее всего только из-за закрытого дескриптора. Но помимо записи о самом факте ошибке, не помешало бы ещё написать подробности о ней: тип и сообщение …Exception as exc: …' {}'.format(type(exc).__name__, exc)…. В случае ошибки записи не помешает что-то такое:
if not logfile.closed:
    logfile.close()
logfile = None
И так как файл может не получиться открыть и при этом выполнение кода не прерывается, нужно поставить второй раз условие `logfile is None` непосредственно для записи или сделать выход из подпрограммы в случае ошибки при открытии файла.

p.s. Что там за `else`? Автор пробовал выполнить алгоритм в уме? Что у него получилось в случае `logfile is None`?

..bw
admiral
bw
Что там за `else`? Автор пробовал выполнить алгоритм в уме? Что у него получилось в случае `logfile is None`?
Да, ступил. При первом вызове откроется только файл, а в него ничего не будет записано.
Просто хотел сделать так, что если файл не будет открыт, то и print в файл не нужно выполнять.
Вот:
def printlog(*args):
    """
    Подпрограмма одновременного вывода строки на экран и в файл
    """
    global logfile
    t = time.strftime("%H:%M:%S") + " "
    print (t, *args)
    if logfile is None:
        try:
            logfile = open(LOGFILE, 'a')
        except Exception:
            print (t, "Не могу открыть лог-файл")
            return
    try:
        print(t, *args, file = logfile)
        logfile.flush()
    except Exception:
        print (t, "Не могу добавить строку в лог-файл")
doza_and
admiral
Тем, что он не корректно работает в PyScripter

Беру код из документации:
http://docs.python.org/2/howto/logging-cookbook.html#logging-cookbook
import logging
import sys
logger = logging.getLogger('simple_example')
logger.setLevel(logging.DEBUG)
# create file handler which logs even debug messages
fh = logging.FileHandler('spam.log')
fh.setLevel(logging.DEBUG)
# create console handler with a higher log level
ch = logging.StreamHandler()
ch.setLevel(logging.ERROR)
# create formatter and add it to the handlers
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
ch.setFormatter(formatter)
fh.setFormatter(formatter)
# add the handlers to logger
logger.addHandler(ch)
logger.addHandler(fh)
# 'application' code
logger.debug('debug message')
logger.info('info message')
logger.warn('warn message')
logger.error('error message')
logger.critical('critical message')

Он отлично работает и в pyscripter. Как во встроенном движке так и в remote. Проблема похоже в установках Level по умолчанию. Если ставить явно то в pyscripter все работает.

Остальное обсуждение после этого не актуально.
admiral
Спасибо. Такой код действительно заработал.
Буду использовать logging.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB