Как я могу регистрироваться вне основного модуля Flask?

У меня есть приложение Python Flask, файл записи настраивает регистратор в приложении, например:

app = Flask(__name__)
handler = logging.StreamHandler(sys.stdout)
app.logger.addHandler(handler)
app.logger.setLevel(logging.DEBUG)

Затем я делаю кучу записей, используя

app.logger.debug("Log Message")

который отлично работает. Однако у меня есть несколько функций API, таких как:

@app.route('/api/my-stuff', methods=['GET'])
def get_my_stuff():
    db_manager = get_manager()
    query = create_query(request.args)

    service = Service(db_manager, query)
    app.logger.debug("Req: {}".format(request.url))

Я хотел бы знать, как я могу выполнять ведение журнала в этом модуле Service/python. Должен ли я передать приложение к нему? Это похоже на плохую практику, но я не знаю, как получить дескриптор app.logger из-за главного файла Flask...

Ответ 1

Несмотря на то, что это возможный дубликат, я хочу выписать крошечный бит ведения журнала python.

НЕ пропускайте регистраторы. Вы всегда можете получить доступ к любому logging.getLogger(<log name as string>). По умолчанию это выглядит так: * flask использует имя, которое вы предоставляете классу Flask.

Поэтому, если ваш основной модуль называется "my_tool", вы захотите сделать logger = logging.getLogger('my_tool') в модуле Service.

Чтобы добавить к этому, мне нравится быть явным в том, чтобы называть мои регистраторы и пакеты, поэтому я бы сделал Flask('my_tool') ** и в других модулях, например, для регистраторов на уровне уровня. logger = logging.getLogger('my_tool.services') которые используют один и тот же корневой регистратор (и обработчики).

* Нет опыта, основанного на другом ответе.

** Опять же, не используйте колбу, dk, если это хорошая практика

Изменение: Супер простой глупый пример

Главное приложение фляги

import sys
import logging

import flask

from module2 import hi

app = flask.Flask('tester')

handler = logging.StreamHandler(sys.stdout)
handler.setFormatter(logging.Formatter(
    '%(asctime)s - %(name)s - %(levelname)s - %(message)s'))
app.logger.addHandler(handler)
app.logger.setLevel(logging.DEBUG)

@app.route("/index")
def index():
    app.logger.debug("TESTING!")
    hi()
    return "hi"

if __name__ == '__main__':
    app.run()

module2

import logging

log = logging.getLogger('tester.sub')


def hi():
    log.warning('warning test')

Выходы

127.0.0.1 - - [04/Oct/2016 20:08:29] "GET /index HTTP/1.1" 200 -
2016-10-04 20:08:29,098 - tester - DEBUG - TESTING!
2016-10-04 20:08:29,098 - tester.sub - WARNING - warning test

Редактирование 2: Передача сублигаргов

Полностью ненужный, просто для общих знаний.

Определив дочерний логгер, сделанный добавлением .something после имени корневого регистратора в logging.getLogger('root.something') он дает вам базовое другое пространство имен для работы.

Мне лично нравится использовать его для группировки функций при регистрации. Поэтому имейте, что .tool или .db знать, какой тип кода регистрируется. Но это также позволяет так, что у этих дочерних регистраторов могут быть свои собственные обработчики. Поэтому, если вы хотите, чтобы часть вашего кода печаталась в stderr, или в журнал, вы можете это сделать. Вот пример с измененным module2.

module2

import logging
import sys

log = logging.getLogger('tester.sub')
handler = logging.StreamHandler(sys.stderr)
handler.setFormatter(logging.Formatter('%(name)s - %(levelname)s - %(message)s'))
log.addHandler(handler)
log.setLevel(logging.INFO)


def hi():
    log.warning("test")

Вывод

127.0.0.1 - - [04/Oct/2016 20:23:18] "GET /index HTTP/1.1" 200 -
2016-10-04 20:23:18,354 - tester - DEBUG - TESTING!
tester.sub - WARNING - test
2016-10-04 20:23:18,354 - tester.sub - WARNING - test