Динамический путь к файлу и имя файла для FileHandler в файле конфигурации logger в python
У меня есть файл конфигурации журнала python с обработчиком файла ниже.
[handler_filelog]
class: FileHandler
args = ('/var/tmp/log/client.log','a')
Вместо этого мне нужно это в форме ниже (динамически сгенерированный путь).
[handler_filelog]
class: FileHandler
args = ('/var/tmp/log_<unique_string>/client.log','a')
Несколько экземпляров программы могут быть запущены и, следовательно, должны использоваться неконфликтные пути и файлы журнала.
После завершения установки регистратор не должен меняться до конца выполнения программы.
Есть ли способ справиться с этим, используя подход к файлу конфигурации?
Я не стремлюсь приступить к созданию регистраторов/обработчиков/форматов самостоятельно, так как в моем конфигурационном файле журнала есть много из них, и подход на основе файлов с конфигурацией намного приятнее.
(Обновление: я использую python 2.4)
Ответы
Ответ 1
Это делает то, что вам нужно. Сначала вы должны расширить класс FileHandler. Поместите это в файл, скажем myHandler.py в каталог вашего файла конфигурации:
import logging
import random
import os
class myFileHandler(logging.FileHandler):
def __init__(self,path,fileName,mode):
r = random.randint(1,100000)
path = path+"/log_"+str(r)
os.mkdir(path)
super(myFileHandler,self).__init__(path+"/"+fileName,mode)
И затем в конфигурационном файле вы можете использовать этот пользовательский FileHandler, как этот
class: myHandler.myFileHandler
args = ('/var/tmp','client.log','a')
Я проверил это на своей машине
Ответ 2
Если вы используете Python 2.7 или 3.2, вы можете использовать версию на основе словаря, которая позволяет вам указывать произвольные вызовы для возврата обработчиков - вы могли бы, например, используйте PID процесса для создания имени файла.
Обновление: Если вы используете 2.4, вы можете использовать пакет logutils, который должен работать с Python 2.4 (кроме класса LoggerAdapter, для которого требуется 2.5 или новее). Пакет logutils
содержит функциональность конфигурации на основе словаря.
Ответ 3
"CallbackFilter" может использоваться для реализации Dynamic filepath и filename для файла конфигурации logger в python. Вы можете определить write_dynamic_log, как показано ниже:
def write_dynamic_log(record):
now = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
dynamic_log_name = '/var/log/test_%s.log' %now
log_file = open(dynamic_log_name, "w")
log_file.write(record.msg)
log_file.close();
return True
Затем в файле конфигурации вы можете использовать этот фильтр следующим образом:
[handler_filelog]
class: FileHandler
formatter: brief
level : INFO
filters: [write_dynamic_log]
filename: static.log
Журнал INFO или выше будет выводиться в static.log, а также в dynamic_log.
Я протестировал его в своем проекте django, в котором я написал config в моих settings.py. Он работает нормально. LOGGING будет выглядеть так:
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'verbose': {
'format': '[%(levelname)s] %(asctime)s - %(pathname)s:%(lineno)d\n%(message)s'
},
'debug': {
'format': '[%(levelname)s] %(asctime)s - %(pathname)s:%(lineno)d\n\033[34m%(message)s\033[0m'
},
'error': {
'format': 'Component: %(module)s\nErrorCode: %(funcName)s\nReason: %(funcName)s\nDetail: [%(message)s]'
},
},
'filters': {
'write_error_logs': {
'()': 'django.utils.log.CallbackFilter',
'callback': write_error_log,
}
},
'handlers': {
'console': {
'class': 'logging.StreamHandler',
'formatter': 'verbose',
},
'debug': {
'class': 'logging.StreamHandler',
'formatter': 'debug',
},
'error': {
'level': 'ERROR',
'class': 'logging.FileHandler',
'filename': '/var/log/SmartStorageApp.err',
'formatter': 'error',
'filters': ['write_error_logs'],
},
},
'loggers': {
'django': {
'handlers': ['debug' if DEBUG else 'console', 'error'],
'level': 'INFO',
'propagate': True,
},
}
}