В целом, современные операционные системы общего назначения очищают после прекращенных процессов. Это необходимо, потому что альтернатива заключается в том, что система теряет ресурсы с течением времени и требует перезагрузки из-за плохо написанных программ или просто имеет редко встречающиеся ошибки, которые утечки ресурсов.
Наличие вашей программы явно освобождает ее ресурсы в любом случае может быть хорошей практикой по разным причинам, например:
Однако, здесь есть причина, чтобы пропустить освобождение памяти: эффективное завершение работы. Например, предположим, что ваше приложение содержит большой кеш в памяти. Если он выходит, он проходит через всю структуру кэша и освобождает его по одному фрагменту за раз, что не приносит никакой пользы и тратит ресурсы. В частности, рассмотрим случай, когда страницы памяти, содержащие ваш кеш, были заменены на диск операционной системой; прогуливаясь по структуре и освобождая ее, вы сразу возвращаете все эти страницы в память , теряя значительное время и энергию без реальной выгоды и, возможно, даже заставляя другие программы в системе
Как пример, существуют высокопроизводительные серверы, которые работают, создавая процесс для каждого запроса, а затем завершая его завершение; таким образом, им даже не нужно отслеживать выделение памяти , и никогда вообще не делать освобождение или сборку мусора, поскольку все просто возвращается в свободную память операционной системы в конце процесса. (То же самое можно сделать в процессе с использованием специализированного распределителя памяти, но требует очень тщательного программирования, по сути дела, создавая собственное понятие «легкие процессы» в процессе ОС.)
Весь вывод журнала обрабатывается обработчиками; просто добавьте logging.StreamHandler()
к корневому логгеру.
Вот пример настройки обработчика потока (с использованием stdout
вместо значения по умолчанию stderr
) и добавления его в корневой логгер:
import logging
import sys
root = logging.getLogger()
root.setLevel(logging.DEBUG)
handler = logging.StreamHandler(sys.stdout)
handler.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
root.addHandler(handler)
Самый простой способ войти в стандартный вывод:
import logging
import sys
logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
Вы можете создать два обработчика для файла и стандартного вывода, а затем создать один регистратор с аргументом handlers
для basicConfig
. Это может быть полезно, если у вас одинаковый log_level и формат вывода для обоих обработчиков:
import logging
import sys
file_handler = logging.FileHandler(filename='tmp.log')
stdout_handler = logging.StreamHandler(sys.stdout)
handlers = [file_handler, stdout_handler]
logging.basicConfig(
level=logging.DEBUG,
format='[%(asctime)s] {%(filename)s:%(lineno)d} %(levelname)s - %(message)s',
handlers=handlers
)
logger = logging.getLogger('LOGGER_NAME')
Простейший способ войти в файл и в stderr:
import logging
logging.basicConfig(filename="logfile.txt")
stderrLogger=logging.StreamHandler()
stderrLogger.setFormatter(logging.Formatter(logging.BASIC_FORMAT))
logging.getLogger().addHandler(stderrLogger)
Вот очень простой пример:
import logging
l = logging.getLogger("test")
# Add a file logger
f = logging.FileHandler("test.log")
l.addHandler(f)
# Add a stream logger
s = logging.StreamHandler()
l.addHandler(s)
# Send a test message to both -- critical will always log
l.critical("test msg")
Вывод будет отображать «test msg» на stdout, а также в файле.
Поскольку никто не поделился аккуратными двумя вкладышами, я поделюсь своим:
logging.basicConfig(filename='logs.log', level=logging.DEBUG, format="%(asctime)s:%(levelname)s: %(message)s")
logging.getLogger().addHandler(logging.StreamHandler())
Возможно использование нескольких обработчиков.
import logging
import auxiliary_module
# create logger with 'spam_application'
log = logging.getLogger('spam_application')
log.setLevel(logging.DEBUG)
# create formatter and add it to the handlers
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
# create file handler which logs even debug messages
fh = logging.FileHandler('spam.log')
fh.setLevel(logging.DEBUG)
fh.setFormatter(formatter)
log.addHandler(fh)
# create console handler with a higher log level
ch = logging.StreamHandler()
ch.setLevel(logging.ERROR)
ch.setFormatter(formatter)
log.addHandler(ch)
log.info('creating an instance of auxiliary_module.Auxiliary')
a = auxiliary_module.Auxiliary()
log.info('created an instance of auxiliary_module.Auxiliary')
log.info('calling auxiliary_module.Auxiliary.do_something')
a.do_something()
log.info('finished auxiliary_module.Auxiliary.do_something')
log.info('calling auxiliary_module.some_function()')
auxiliary_module.some_function()
log.info('done with auxiliary_module.some_function()')
# remember to close the handlers
for handler in log.handlers:
handler.close()
log.removeFilter(handler)
Пожалуйста, смотрите: https://docs.python.org/2/howto/logging-cookbook.html
Вот решение, основанное на мощном, но плохо документированном методе logging.config.dictConfig
. Вместо того, чтобы отправлять каждое сообщение журнала на стандартный вывод, он отправляет сообщения с уровнем журнала ERROR
и выше на stderr
, а все остальное на stdout
. Это может быть полезно, если другие части системы прослушивают stderr
или stdout
.
import logging
import logging.config
import sys
class _ExcludeErrorsFilter(logging.Filter):
def filter(self, record):
"""Filters out log messages with log level ERROR (numeric value: 40) or higher."""
return record.levelno < 40
config = {
'version': 1,
'filters': {
'exclude_errors': {
'()': _ExcludeErrorsFilter
}
},
'formatters': {
# Modify log message format here or replace with your custom formatter class
'my_formatter': {
'format': '(%(process)d) %(asctime)s %(name)s (line %(lineno)s) | %(levelname)s %(message)s'
}
},
'handlers': {
'console_stderr': {
# Directs log messages with log level ERROR or higher to stderr
'class': 'logging.StreamHandler',
'level': 'ERROR',
'formatter': 'my_formatter',
'stream': sys.stderr
},
'console_stdout': {
# Directs log messages with log level lower than ERROR to stdout
'class': 'logging.StreamHandler',
'level': 'DEBUG',
'formatter': 'my_formatter',
'filters': ['exclude_errors'],
'stream': sys.stdout
},
'file': {
# Directs all log messages to a file
'class': 'logging.FileHandler',
'level': 'DEBUG',
'formatter': 'my_formatter',
'filename': 'my.log',
'encoding': 'utf8'
}
},
'root': {
# In general, this should be kept at 'NOTSET' to ensure it does
# not interfere with the log levels set for each handler
'level': 'NOTSET',
'handlers': ['console_stderr', 'console_stdout', 'file']
},
}
logging.config.dictConfig(config)