簡體   English   中英

項目的結構化日志記錄

[英]Structured Logging for a project

我在我的python項目上使用Logging。 我的問題是關於在我的項目中構建日志記錄的正確和優雅的方法,因為我將首先描述我正在使用的結構。

我有3個主要的.py腳本,所以在啟動時稱為服務的acquisition.py,actus.py和management.py。 上面的3個腳本導入network.py和devices.py。

我想組織與3個主要腳本相關的每個文件的日志記錄,所以我想擁有:acquisition.log,actuation.log和management.log。 在這個日志里面我希望從對network.py的調用中得到相應的日志一個device.py(使用名稱空間%(name)

示例(acquisition.log):

INFO acquisition.thread 2016-03-17 12:26:02,069 in Thread 70de3b66-e14b-11e5-8953-80fa5b0ae007
DEBUG acquisition 2016-03-17 12:26:02,070 Thread launched 70de3b66-e14b-11e5-8953-80fa5b0ae007
INFO acquisition.devices 2016-03-17 12:26:03,072  Variable_R read:  0013a20040c1bb0b  temperature1
ERROR acquisition.devices 2016-03-17 12:26:19,076 variable.read.DeviceConfigurationError: 0013a20040c1bb0b 
INFO acquisition.thread 2016-03-17 12:26:19,077 exit Thread 70ddfa20-e14b-11e5-8953-80fa5b0ae007
ERROR acquisition.devices 2016-03-17 12:26:25,085 variable.read.DeviceConfigurationError: 0013a20040c1bb0b 
INFO acquisition.thread 2016-03-17 12:26:25,086 exit Thread 70de3b66-e14b-11e5-8953-80fa5b0ae007

在這種情況下,您可以看到,對於相同的日志文件,我可以從不同的文件進行日志記錄,可以在日志命名空間acquisition.threadacquisition.devices中看到。

我實現這一點的方法是使用記錄器功能,我用它在每個文件中創建一個回退記錄器,我正在記錄。 並且,稍后如果我想記錄該文件中的信息,我將在主腳本文件中更改導入文件中創建的記錄器。

代碼示例解釋了上述內容:

acquisition.py(主腳本):

imports...
import logger_sys
import logging
import xnetwork
import xdevices

# Log configuration
log_name = os.path.basename(__file__).strip(".py")
logit = logger_sys.setup_logger(log_name, log_name) #internal logger for main file
logger_thread = logging.getLogger(log_name + '.thread')

#Log configuration of external files
xnetwork.logger = logging.getLogger(log_name + '.network')
xdevices.logger = logging.getLogger(log_name + '.devices')

logit.info("START acquisition_service")

# REST OF THE CODE... 

xdevices.py:

import logger_sys

# Fallback logger in case the calling script doesnt modify logger
log_name = __name__.strip(".py") + '_fallback'
logger = logger_sys.setup_logger(log_name, log_name, stream_hdlr=False)

# REST OF THE CODE...

xnetworks.py:

import logger_sys

# Fallback logger in case the calling script doesnt modify logger
log_name = __name__.strip(".py") + '_fallback'
logger = logger_sys.setup_logger(log_name, log_name, stream_hdlr=False)

# REST OF THE CODE...

logger_sys.py:

import logging, sys, os
from global_settings import RUNNING_MODE, DEBUG, STAGING, PRODUCTION

def setup_logger(namespace, filename, stream_hdlr=True):

    logger = logging.getLogger(namespace)

    handler_format = logging.Formatter("%(levelname)s %(name)s %(asctime)s %(message)s")

    log_handler = logging.FileHandler(filename + ".log")
    logger.addHandler(log_handler)
    log_handler.setFormatter(handler_format)

    if RUNNING_MODE == DEBUG:
        if stream_hdlr:
            log_handler = logging.StreamHandler(sys.stdout)
            logger.addHandler(log_handler)
            log_handler.setFormatter(handler_format)

        logger.setLevel(logging.DEBUG)

    elif RUNNING_MODE == STAGING or RUNNING_MODE == PRODUCTION:
        logger.setLevel(logging.INFO)

    return logger

目的?

  • 我想知道是否有更優雅的解決方案,不使用將logger作為參數傳遞給被調用方法的邏輯。

  • 我想了解在更復雜的情況下通常如何構建日志記錄,例如在使用外部模塊時。

  • 而且,我想閱讀關於這種采伐策略的批評者。

先感謝您

您應該學習正式的日志記錄和一些正確記錄的復雜項目。 我建議閱讀請求源代碼 ,看看一個相當復雜的項目如何進行日志記錄。

對您的案例來說,食譜的關鍵點可能是:

對logging.getLogger('someLogger')的多次調用返回對同一記錄器對象的引用。 這不僅在同一模塊中,而且在模塊之間也是如此,只要它在同一個Python解釋器過程中。

一種典型的方法是在文件的頂部有類似下面的內容:

import logging
log = logging.getLogger(__name__)

這使log成為全局,因此可以在函數中使用它而不將log作為參數傳遞:

def add(x, y):
    log.debug('Adding {} and {}'.format(x, y))
    return x + y

如果您正在創建一些長時間運行的服務並打算記錄所有/大多數/多個函數調用,請考慮使用裝飾器。 我建議來自Fresh Books Dev Blog的這篇文章作為使用裝飾器進行日志記錄的介紹。 聽起來您的程序可能會受益於裝飾器方法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM