Подтвердить что ты не робот

Как настроить ведение журнала в Python

Я новичок в Python и просто начинаю один проект. Я привык использовать log4j в Java, и я хотел бы записывать все модули и классы в Python, как и в Java.

В Java у меня есть один файл конфигурации журнала в папке src с именем log4j.properties, как показано ниже:

log4j.rootLogger=DEBUG, Console, fileout

log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d{dd/MM/yyyy HH:mm:ss} %5p [%t] (%F:%L) - %m%n

log4j.appender.fileout=org.apache.log4j.RollingFileAppender
log4j.appender.fileout.File=servidor.log
log4j.appender.fileout.layout=org.apache.log4j.PatternLayout
log4j.appender.fileout.layout.ConversionPattern=%d{dd/MM/yyyy HH:mm:ss} (%F:%L) %p %t %c - %m%n

Он записывается в консоль и файл.

В моих классах мне нужно импортировать log4j и добавлять статический атрибут для восстановления регистратора log4j с загруженной конфигурацией, тогда все классы будут регистрироваться в консоли и файле. Файл конфигурации загружается автоматически по имени. Например:

import org.apache.log4j.Logger;

public class Main {
    public static Logger logger = Logger.getLogger(Main.class);
    public static void main(String[] args) {
        logger.info("Hello");
    }
}

Теперь у меня проблема с настройкой ведения журнала на Python, я прочитал документы, но не смог найти способ использовать его во многих модулях/классах. Как я мог легко настраивать протоколы Python для легкого доступа к моим модулям и классам без кода в каждом модуле/классе? Возможно ли воспроизвести тот же код, который я написал в Python?

4b9b3361

Ответ 1

На самом деле в Python это выглядит очень похоже. Есть разные способы сделать это. Я обычно создаю класс logger, который очень прост:

import os
import logging 
import settings   # alternativly from whereever import settings  

class Logger(object):

    def __init__(self, name):
        name = name.replace('.log','')
        logger = logging.getLogger('log_namespace.%s' % name)    # log_namespace can be replaced with your namespace 
        logger.setLevel(logging.DEBUG)
        if not logger.handlers:
            file_name = os.path.join(settings.LOGGING_DIR, '%s.log' % name)    # usually I keep the LOGGING_DIR defined in some global settings file
            handler = logging.FileHandler(file_name)
            formatter = logging.Formatter('%(asctime)s %(levelname)s:%(name)s %(message)s')
            handler.setFormatter(formatter)
            handler.setLevel(logging.DEBUG)
            logger.addHandler(handler)
        self._logger = logger

    def get(self):
        return self._logger

Затем, если я хочу что-то записать в класс или модуль, я просто импортирую регистратор и создаю экземпляр. Передача имени класса создаст один файл для каждого класса. Регистратор может затем записывать сообщения в свой файл с помощью отладки, информации, ошибок и т. Д.:

from module_where_logger_is_defined import Logger

class MyCustomClass(object):

    def __init__(self):
        self.logger = Logger(self.__class__.__name__).get()   # accessing the "private" variables for each class

    def do_something():
        ...
        self.logger.info('Hello')

    def raise_error():
        ...
        self.logger.error('some error message')

Обновленный ответ

За эти годы я немного изменил то, как я использую логи Python. Основываясь на передовой практике, я настраиваю ведение журнала всего приложения один раз в любом модуле, который загружается сначала во время запуска приложения, а затем использую отдельные средства ведения журнала в каждом файле. Пример:


# app.py (runs when application starts)

import logging
import os.path

def main():
    logging_config = {
        'version': 1,
        'disable_existing_loggers': False,
        'formatters': {
            'standard': {
                'format': '%(asctime)s [%(levelname)s] %(name)s: %(message)s'
            },
        },
        'handlers': {
            'default_handler': {
                'class': 'logging.handlers.FileHandler',
                'level': 'DEBUG',
                'formatter': 'standard',
                'filename': os.path.join('logs', 'application.log'),
                'encoding': 'utf8'
            },
        },
        'loggers': {
            '': {
                'handlers': ['default_handler'],
                'level': 'DEBUG',
                'propagate': False
            }
        }
    }
    logging.config.dictConfig(logging_config)
    # start application ...

if __name__ == '__main__':
    main()

# submodule.py (any application module used later in the application)

import logging

# define top level module logger
logger = logging.getLogger(__name__)

def do_something():
    # application code ...
    logger.info('Something happended')
    # more code ...
    try:
        # something which might break
    except SomeError:
        logger.exception('Something broke')
        # handle exception
    # more code ...

Выше приведен рекомендуемый способ сделать это. Каждый модуль определяет свой собственный регистратор и может легко определить на основе атрибута __name__ какое сообщение было зарегистрировано в каком модуле, когда вы просматриваете журналы. Это удаляет шаблон из моего исходного ответа и вместо этого использует модуль logging.config из стандартной библиотеки Python.

Ответ 2

Документы предоставляют довольно хороший пример использования вашего регистратора в нескольких модулях. В основном, вы устанавливаете регистрацию один раз в начале вашей программы. Затем вы импортируете модуль регистрации, где бы вы ни занимались, и используйте его.

myapp.py

import logging
import mylib

def main():
    logging.basicConfig(filename='myapp.log', level=logging.INFO)
    logging.info('Started')
    mylib.do_something()
    logging.info('Finished')

if __name__ == '__main__':
    main()

mylib.py

import logging

def do_something():
    logging.info('Doing something')

В этом примере показана очень упрощенная настройка журнала, но вы можете легко использовать различные способы настройки ведения журнала для настройки более сложных сценариев.