Позволяет ли python logging.handlers.RotatingFileHandler создавать файл журнала, доступный для записи в группе?
Я использую стандартный модуль журналирования Python (2.5.2), в частности RotatingFileHandler, в системе Linux. Мое приложение поддерживает как интерфейс командной строки, так и интерфейс веб-службы. Я хотел бы, чтобы оба записывали в один и тот же файл журнала. Однако, когда файл журнала поворачивается, новый файл имеет 644 разрешения и принадлежит пользователю веб-сервера, что не позволяет пользователю командной строки выполнять запись в него. Могу ли я указать, что новые файлы журналов должны быть доступны для записи в группе в конфигурации журналирования или во время инициализации журналирования?
Я посмотрел на настройку режима (r/w/a), но, похоже, он не поддерживает какие-либо разрешения для файлов.
8 ответов
Я прибег к сканированию модуля logging.handlers и не смог найти способ указать другой режим доступа к файлам. Итак, теперь у меня есть решение, основанное на расширении RotatingFileHandler в качестве пользовательского обработчика. Это было довольно безболезненно, когда я нашел несколько хороших ссылок на его создание. Код для пользовательского обработчика ниже.
class GroupWriteRotatingFileHandler(handlers.RotatingFileHandler):
def doRollover(self):
"""
Override base class method to make the new log file group writable.
"""
# Rotate the file first.
handlers.RotatingFileHandler.doRollover(self)
# Add group write to the current permissions.
currMode = os.stat(self.baseFilename).st_mode
os.chmod(self.baseFilename, currMode | stat.S_IWGRP)
Я также обнаружил, что для ссылки на пользовательский обработчик из файла конфигурации ведения журнала мне пришлось привязать мой модуль к пространству имен ведения журнала. Просто сделать, но раздражает.
from mynamespace.logging import custom_handlers
logging.custom_handlers = custom_handlers
Ссылки, которые я нашел полезными: привязка пользовательских обработчиков и создание пользовательских обработчиков
Вот немного лучшее решение. это переопределяет используемый метод _open. установить umask перед созданием, а затем вернуть его обратно в прежнее состояние.
class GroupWriteRotatingFileHandler(logging.handlers.RotatingFileHandler):
def _open(self):
prevumask=os.umask(0o002)
#os.fdopen(os.open('/path/to/file', os.O_WRONLY, 0600))
rtv=logging.handlers.RotatingFileHandler._open(self)
os.umask(prevumask)
return rtv
Вот простое решение, работающее нормально:
import os
class GroupWriteRotatingFileHandler(handlers.RotatingFileHandler):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
os.chmod(self.baseFilename, 0o0777) # You can change whatever permission you want here.
# you can also change the group of the file:
os.chown(self.baseFilename, uid, gid) # pass the user_id and group_id you want to set
Вот полное решение для Django, основанное на решении rob. в my_module
:
import logging
import logging.handlers
import os
class=
то, что происходит во время конфигурации журналирования, оценивается в пространстве имен модуля журналирования, и по умолчанию это не имеет привязки к обработчикам. Таким образом, мы должны вставить это явно, прежде чем мы сможем расширить его. Смотрите эту статью ТАК
logging.handlers = logging.handlers
Это волшебное заклинание, которое заняло у меня целую вечность, - я не мог поверить, что он что-то сделал! Наконец, класс Джона загрузится без ошибок.
class GroupWriteRotatingFileHandler(logging.handlers.RotatingFileHandler):
def _open(self):
prevumask = os.umask(0o002)
rtv = logging.handlers.RotatingFileHandler._open(self)
os.umask(prevumask)
return rtv
Чтобы использовать это для Django, добавьте следующее в файл настроек
from my_module import GroupWriteRotatingFileHandler
logging.handlers.GroupWriteRotatingFileHandler = GroupWriteRotatingFileHandler
А потом в LOGGING['handlers']['file']
у тебя есть
'class': 'logging.handlers.GroupWriteRotatingFileHandler'
Джеймс Гарднер написал обработчик, который только вращает файлы, но не создает и не удаляет их: http://packages.python.org/logrotate/index.html
Похоже, что def _open(self):
работал с umask(0o000)
получить все разрешения -rw-rw-rw-
.
os.chmod(self.baseFilename, 0o0777)
потерпел неудачу с ValueError: Unable to configure handler 'some_handler': [Errno 1] Operation not permitted:
если файл журнала принадлежит root:root
это отличается от запущенного процесса, например testuser
.
from logging import handlers
import logging
import os
class GroupWriteRotatingFileHandler(handlers.RotatingFileHandler):
def _open(self):
prevumask = os.umask(0o000) # -rw-rw-rw-
rtv = logging.handlers.RotatingFileHandler._open(self)
os.umask(prevumask)
return rtv
LOGGING = {
'handlers': {
'db_handler': {
'level': 'DEBUG',
'class': 'log.GroupWriteRotatingFileHandler',
'filename': PATH_TO_LOGS + '/db.log',
'maxBytes': maxBytes,
'backupCount': backupCount,
'formatter': 'standard',
},
Лог-файлы:
logs]# ls -lrt
-rw-rw-rw- 1 root root 71 Apr 1 16:02 db.log
logs]# ls -lrt
total 0
-rw-rw-rw- 1 testuser testuser 0 Apr 1 16:20 db.log
$ chgrp loggroup logdir
$ chmod g+w logdir
$ chmod g+s logdir
$ usermod -a -G loggroup myuser
$ umask 0002
Я думаю, что описанное здесь является антипаттерном — разные процессы не должны записывать данные в один и тот же файл.
И ни одно из приведенных выше решений не сработало для меня, вызывая разные проблемы с разрешениями в разных сценариях.
В качестве временного обходного пути я добавил случайный суффикс в имя файла журнала, чтобы каждый процесс при запуске получал уникальное имя файла.
Правильный способ решить эту проблему - иметь централизованный обработчик логов (сервер логов), например rsyslog.