499

私はPythonのロギングモジュールを使用して、いくつかのデバッグ文字列をかなりうまく機能するファイルに記録しています。さらに、このモジュールを使用して、文字列をstdoutに出力したいと思います。どうすればよいですか?文字列をファイルに記録するために、次のコードを使用します。

import logging
import logging.handlers
logger = logging.getLogger("")
logger.setLevel(logging.DEBUG)
handler = logging.handlers.RotatingFileHandler(
    LOGFILE, maxBytes=(1048576*5), backupCount=7
)
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
handler.setFormatter(formatter)
logger.addHandler(handler)

次に、次のようなロガー関数を呼び出します

logger.debug("I am written to the file")

ここで助けてくれてありがとう!

4

8 に答える 8

605

ルートロガーへのハンドルを取得し、を追加するだけStreamHandlerです。StreamHandlerstderrへの書き込み。stderrよりもstdoutが本当に必要かどうかはわかりませんが、これはPythonロガーをセットアップするときに使用するものであり、これも追加FileHandlerします。次に、すべてのログが両方の場所に送信されます(これはあなたが望むように聞こえます)。

import logging
logging.getLogger().addHandler(logging.StreamHandler())

stdoutの代わりにに出力する場合stderrは、コンストラクターに指定するだけですStreamHandler

import sys
# ...
logging.getLogger().addHandler(logging.StreamHandler(sys.stdout))

Formatterまた、すべてのログ行に共通のヘッダーが含まれるように、を追加することもできます。

すなわち:

import logging
logFormatter = logging.Formatter("%(asctime)s [%(threadName)-12.12s] [%(levelname)-5.5s]  %(message)s")
rootLogger = logging.getLogger()

fileHandler = logging.FileHandler("{0}/{1}.log".format(logPath, fileName))
fileHandler.setFormatter(logFormatter)
rootLogger.addHandler(fileHandler)

consoleHandler = logging.StreamHandler()
consoleHandler.setFormatter(logFormatter)
rootLogger.addHandler(consoleHandler)

次の形式で印刷します。

2012-12-05 16:58:26,618 [MainThread  ] [INFO ]  my message
于 2012-12-05T22:43:00.510 に答える
468

logging.basicConfig()Python 3.3以降、キーワード引数を取ることができますhandlers。これにより、特に同じフォーマッターで複数のハンドラーを設定する場合に、ログの設定が大幅に簡素化されます。

handlers–指定されている場合、これは、ルートロガーに追加するために作成済みのハンドラーの反復可能である必要があります。フォーマッターがまだ設定されていないハンドラーには、この関数で作成されたデフォルトのフォーマッターが割り当てられます。

したがって、セットアップ全体は、次のような1回の呼び出しで実行できます。

import logging

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s [%(levelname)s] %(message)s",
    handlers=[
        logging.FileHandler("debug.log"),
        logging.StreamHandler()
    ]
)

(または、元の質問の要件ごとにimport sys+StreamHandler(sys.stdout)を使用– StreamHandlerのデフォルトはstderrに書き込むことです。ログ形式をカスタマイズしてファイル名/行、スレッド情報などを追加する場合は、 LogRecord属性を確認してください。)

上記の設定は、スクリプトの最初の方で1回だけ実行する必要があります。後で次のように、コードベースの他のすべての場所からのロギングを使用できます。

logging.info('Useful message')
logging.error('Something bad happened')
...

注:機能しない場合は、他の誰かがすでにログシステムを別の方法で初期化した可能性があります。logging.root.handlers = []コメントは、への呼び出しの前に行うことを示唆していますbasicConfig()

于 2017-09-07T14:17:31.037 に答える
85

引数なしでStreamHandlerを追加すると、stdoutではなくstderrに移動します。他のプロセスがstdoutダンプに依存している場合(つまり、NRPEプラグインを作成する場合)、必ずstdoutを明示的に指定してください。そうしないと、予期しない問題が発生する可能性があります。

質問からの想定値とLOGFILEを再利用する簡単な例を次に示します。

import logging
from logging.handlers import RotatingFileHandler
from logging import handlers
import sys

log = logging.getLogger('')
log.setLevel(logging.DEBUG)
format = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")

ch = logging.StreamHandler(sys.stdout)
ch.setFormatter(format)
log.addHandler(ch)

fh = handlers.RotatingFileHandler(LOGFILE, maxBytes=(1048576*5), backupCount=7)
fh.setFormatter(format)
log.addHandler(fh)
于 2014-09-24T02:49:04.703 に答える
24

これは、ウォーターボーイの回答と他のさまざまな情報源に基づいた、完全でうまくラップされたソリューションです。コンソールとログファイルの両方へのログ記録をサポートし、さまざまなログレベル設定を可能にし、色付きの出力を提供し、簡単に構成できます(Gistとしても利用可能)。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# -------------------------------------------------------------------------------
#                                                                               -
#  Python dual-logging setup (console and log file),                            -
#  supporting different log levels and colorized output                         -
#                                                                               -
#  Created by Fonic <https://github.com/fonic>                                  -
#  Date: 04/05/20                                                               -
#                                                                               -
#  Based on:                                                                    -
#  https://stackoverflow.com/a/13733863/1976617                                 -
#  https://uran198.github.io/en/python/2016/07/12/colorful-python-logging.html  -
#  https://en.wikipedia.org/wiki/ANSI_escape_code#Colors                        -
#                                                                               -
# -------------------------------------------------------------------------------

# Imports
import os
import sys
import logging

# Logging formatter supporting colorized output
class LogFormatter(logging.Formatter):

    COLOR_CODES = {
        logging.CRITICAL: "\033[1;35m", # bright/bold magenta
        logging.ERROR:    "\033[1;31m", # bright/bold red
        logging.WARNING:  "\033[1;33m", # bright/bold yellow
        logging.INFO:     "\033[0;37m", # white / light gray
        logging.DEBUG:    "\033[1;30m"  # bright/bold black / dark gray
    }

    RESET_CODE = "\033[0m"

    def __init__(self, color, *args, **kwargs):
        super(LogFormatter, self).__init__(*args, **kwargs)
        self.color = color

    def format(self, record, *args, **kwargs):
        if (self.color == True and record.levelno in self.COLOR_CODES):
            record.color_on  = self.COLOR_CODES[record.levelno]
            record.color_off = self.RESET_CODE
        else:
            record.color_on  = ""
            record.color_off = ""
        return super(LogFormatter, self).format(record, *args, **kwargs)

# Setup logging
def setup_logging(console_log_output, console_log_level, console_log_color, logfile_file, logfile_log_level, logfile_log_color, log_line_template):

    # Create logger
    # For simplicity, we use the root logger, i.e. call 'logging.getLogger()'
    # without name argument. This way we can simply use module methods for
    # for logging throughout the script. An alternative would be exporting
    # the logger, i.e. 'global logger; logger = logging.getLogger("<name>")'
    logger = logging.getLogger()

    # Set global log level to 'debug' (required for handler levels to work)
    logger.setLevel(logging.DEBUG)

    # Create console handler
    console_log_output = console_log_output.lower()
    if (console_log_output == "stdout"):
        console_log_output = sys.stdout
    elif (console_log_output == "stderr"):
        console_log_output = sys.stderr
    else:
        print("Failed to set console output: invalid output: '%s'" % console_log_output)
        return False
    console_handler = logging.StreamHandler(console_log_output)

    # Set console log level
    try:
        console_handler.setLevel(console_log_level.upper()) # only accepts uppercase level names
    except:
        print("Failed to set console log level: invalid level: '%s'" % console_log_level)
        return False

    # Create and set formatter, add console handler to logger
    console_formatter = LogFormatter(fmt=log_line_template, color=console_log_color)
    console_handler.setFormatter(console_formatter)
    logger.addHandler(console_handler)

    # Create log file handler
    try:
        logfile_handler = logging.FileHandler(logfile_file)
    except Exception as exception:
        print("Failed to set up log file: %s" % str(exception))
        return False

    # Set log file log level
    try:
        logfile_handler.setLevel(logfile_log_level.upper()) # only accepts uppercase level names
    except:
        print("Failed to set log file log level: invalid level: '%s'" % logfile_log_level)
        return False

    # Create and set formatter, add log file handler to logger
    logfile_formatter = LogFormatter(fmt=log_line_template, color=logfile_log_color)
    logfile_handler.setFormatter(logfile_formatter)
    logger.addHandler(logfile_handler)

    # Success
    return True

# Main function
def main():

    # Setup logging
    script_name = os.path.splitext(os.path.basename(sys.argv[0]))[0]
    if (not setup_logging(console_log_output="stdout", console_log_level="warning", console_log_color=True,
                        logfile_file=script_name + ".log", logfile_log_level="debug", logfile_log_color=False,
                        log_line_template="%(color_on)s[%(created)d] [%(threadName)s] [%(levelname)-8s] %(message)s%(color_off)s")):
        print("Failed to setup logging, aborting.")
        return 1

    # Log some messages
    logging.debug("Debug message")
    logging.info("Info message")
    logging.warning("Warning message")
    logging.error("Error message")
    logging.critical("Critical message")

# Call main function
if (__name__ == "__main__"):
    sys.exit(main())

Microsoft Windowsに関する注意:Microsoft Windows
で実際に色を表示するには、追加の手順が必要です。2つのオプションがあります(どちらもMicrosoft Windows 10で正常にテストされています)。

1)次のコードを使用してANSIターミナルモードを有効にします(ターミナルがフラグを設定することでエスケープシーケンスを解釈できるようにしますENABLE_VIRTUAL_TERMINAL_PROCESSING。これについての詳細は、ここここここここ):

# Enable ANSI terminal mode on Microsoft Windows
def windows_enable_ansi_terminal_mode():
    if (sys.platform != "win32"):
        return None
    try:
        import ctypes
        kernel32 = ctypes.windll.kernel32
        result = kernel32.SetConsoleMode(kernel32.GetStdHandle(-11), 7)
        if (result == 0): raise Exception
        return True
    except:
        return False

2)Pythonパッケージcoloramaを使用します( stdoutおよびstderrに送信された出力をフィルター処理し、エスケープシーケンスをネイティブのWindows API呼び出しに変換します):

import colorama
colorama.init()
于 2020-04-05T14:00:24.983 に答える
20

他のハンドラーを設定したりメッセージをログに記録したりする前に、引数としてを使用して実行basicConfigするか、メッセージをstdoutにプッシュするを手動でルートロガー(またはその他の必要なロガー)に追加します。stream=sys.stdoutStreamHandler

于 2012-12-05T22:37:43.397 に答える
13

さまざまなレベルと形式でのstdoutロギング:rotating file

import logging
import logging.handlers
import sys

if __name__ == "__main__":

    # Change root logger level from WARNING (default) to NOTSET in order for all messages to be delegated.
    logging.getLogger().setLevel(logging.NOTSET)

    # Add stdout handler, with level INFO
    console = logging.StreamHandler(sys.stdout)
    console.setLevel(logging.INFO)
    formater = logging.Formatter('%(name)-13s: %(levelname)-8s %(message)s')
    console.setFormatter(formater)
    logging.getLogger().addHandler(console)

    # Add file rotating handler, with level DEBUG
    rotatingHandler = logging.handlers.RotatingFileHandler(filename='rotating.log', maxBytes=1000, backupCount=5)
    rotatingHandler.setLevel(logging.DEBUG)
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    rotatingHandler.setFormatter(formatter)
    logging.getLogger().addHandler(rotatingHandler)

    log = logging.getLogger("app." + __name__)

    log.debug('Debug message, should only appear in the file.')
    log.info('Info message, should appear in file and stdout.')
    log.warning('Warning message, should appear in file and stdout.')
    log.error('Error message, should appear in file and stdout.')
于 2019-12-20T22:13:23.700 に答える
7

Waterboyのコードを複数のPythonパッケージで何度も使用した後、私はついにそれを小さなスタンドアロンのPythonパッケージにキャストしました。これは次の場所にあります。

https://github.com/acschaefer/duallog

コードは十分に文書化されており、使いやすいです。ファイルをダウンロード.pyしてプロジェクトに含めるか、を介してパッケージ全体をインストールするだけpip install duallogです。

于 2018-10-27T00:58:28.883 に答える
-5

2.7の場合、次のことを試してください。

fh = logging.handlers.RotatingFileHandler(LOGFILE, maxBytes=(1048576*5), backupCount=7)
于 2016-07-19T22:57:24.653 に答える