dosyaya oturum açmak ve stdout'a yazdırmak için logger yapılandırması


354

Ben oldukça iyi çalışan bir dosyaya bazı hata ayıklama dizeleri günlüğe kaydetmek için Python günlüğü modülünü kullanıyorum. Şimdi ek olarak, dizeleri stdout'a yazdırmak için bu modülü kullanmak istiyorum. Bunu nasıl yaparım? Dizelerimi bir dosyaya kaydetmek için aşağıdaki kodu kullanıyorum:

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)

ve daha sonra,

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

Burada yardım için teşekkürler!

Yanıtlar:


452

Sadece kök kaydediciye bir tanıtıcı alın ve ekleyin StreamHandler. StreamHandlerStderr'e yazar. Stderr üzerinden gerçekten stdout'a ihtiyacınız olup olmadığından emin değilim, ancak Python logger'ı kurduğumda ve bunu da eklediğimde kullandığım şey bu FileHandler. Sonra tüm günlüklerim her iki yere de gidiyor (istediğiniz gibi geliyor).

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

stdoutBunun yerine çıktı almak istiyorsanız stderr, bunu yapıcıya belirtmeniz yeterlidir StreamHandler.

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

Ayrıca, Formattertüm günlük satırlarınızın ortak bir üstbilgisi olması için bir de ekleyebilirsiniz .

yani:

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)

Şu biçime yazdırır:

2012-12-05 16:58:26,618 [MainThread  ] [INFO ]  my message

19
Ayrıca StreamHandlerile başlatabilirsiniz sys.stdoutve sonra stderr yerine o günlüğe kaydedilir.
Silas Ray

1
@ sr2222 logger.addHandler (sys.stdout) bana NameError veriyor: name 'sys' tanımlı değil
stdcerr

21
Peki evet ... önce yapmalısın import sys. Ve aslında işleyiciyi başlatın, yaniconsoleHandler = logging.StreamHandler(sys.stdout)
Silas Ray

15
Çünkü daha önce de söylediğim gibi, bunu böyle yapmıyorsunuz. HANDLER'i sys.stdout ile oluşturun, ardından işleyiciyi kaydediciye ekleyin.
Silas Ray

6
rootLogger.setLevel(logging.DEBUG)Bilgi veya hata ayıklama iletileri görmeye çalışıyorsanız unutmayın
storm_m2138

248

logging.basicConfig()handlersPython 3.3'ten bu yana, özellikle aynı biçimlendiriciyle birden çok işleyici ayarlarken günlük kaydı kurulumunu çok kolaylaştıran bir anahtar kelime argümanı alabilir :

handlers- Belirtilirse, kök kaydediciye eklemek için önceden oluşturulmuş işleyicilerden oluşan bir yinelenebilir olmalıdır. Halihazırda formatlayıcı ayarlanmamış olan işleyicilere bu fonksiyonda oluşturulan varsayılan formatlayıcı atanacaktır.

Bu nedenle, tüm kurulum aşağıdaki gibi tek bir çağrı ile yapılabilir:

import logging

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

(Veya orijinal sorunun gereksinimlerine göre import sys+ StreamHandler(sys.stdout)işaretiyle - StreamHandler için varsayılan stderr'a yazmaktır. Günlük biçimini özelleştirmek ve dosya adı / satır, iş parçacığı bilgileri vb. Gibi şeyler eklemek istiyorsanız LogRecord özelliklerine bakın .)

Yukarıdaki kurulum betiğin başlangıcına yakın bir kez yapılmalıdır. Daha sonra aşağıdaki gibi kod tabanında diğer tüm yerlerden günlüğe kaydetmeyi kullanabilirsiniz:

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

Not: Eğer işe yaramazsa, başka biri muhtemelen kayıt sistemini zaten farklı şekilde başlatmıştır. Yorumlar logging.root.handlers = [], aramadan önce yapmayı önerir basicConfig().


5
level = logging.INFO ya da istenilen seviyeyi ayarlamayı unutmayın
Andy Matteson

5
Tanım için FileHandler: logging.FileHandler(filename, mode='a', encoding=None, delay=False). Bu, aynı klasörde oturum açmak istediğinizde sadece kullanabileceğiniz anlamına gelir FileHandler("mylog.log"). Her seferinde günlüğün üzerine yazmak istiyorsanız, "w" yi ikinci argüman olarak ayarlayın.
user136036

7
Bunu denedim, ancak konsol çıktı veriyor olmasına rağmen çıktı dosyası boş .. Herhangi bir öneri ..?
Ramesh-X

4
@ Ramesh-X, bu beni de delirtti. sadece logging.root.handlers = []çağrıdan önce yapın basicConfig, işleve bir göz atın - sinir bozucu.
ihadanny

70

Bağımsız değişkenler olmadan bir StreamHandler eklemek stdout yerine stderr'a gider. Başka bir işlemin stdout dökümünde bir bağımlılığı varsa (yani bir NRPE eklentisi yazarken), stdout'u açıkça belirttiğinizden emin olun, aksi takdirde beklenmedik sorunlarla karşılaşabilirsiniz.

Sorudan varsayılan değerleri ve LOGFILE'ı yeniden kullanan hızlı bir örnek:

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)

Bunu deniyorum.
Ajay Kumar

19

Ya çalıştırmak basicConfigile stream=sys.stdoutbir manuel olarak ekleyin başka işleyicileri kurma veya herhangi bir mesaj giriş veya öncesinde argüman olarak StreamHandler(bu konuda, ya da istediğiniz herhangi bir başka kaydedicisi) kök loggera Stdout'a olduğunu iter mesajları.


5

Waterboy'un kodunu birden fazla Python paketinde tekrar tekrar kullandıktan sonra, sonunda burada bulabileceğiniz küçük bir bağımsız Python paketine döktüm:

https://github.com/acschaefer/duallog

Kod iyi belgelenmiştir ve kullanımı kolaydır. Sadece .pydosyayı indirin ve projenize ekleyin veya paketin tamamını yükleyin pip install duallog.


Nedense ne dosya (boş) konsola giriş
almıyor

5

Günlüğü stdoutve rotating filefarklı düzeyleri ve biçimleri ile:

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.')

2

İşte Waterboy'un cevabına ve diğer çeşitli kaynaklara dayanan eksiksiz, güzel bir şekilde sarılmış bir çözüm . Hem konsol hem de günlük dosyasına günlüğe kaydetmeyi destekler, farklı günlük düzeyi ayarlarına izin verir, renklendirilmiş çıktı sağlar ve kolayca yapılandırılabilir ( Gist olarak da kullanılabilir ):

#!/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 colored 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())

-4

2.7 için aşağıdakileri deneyin:

fh = logging.handlers.RotatingFileHandler(LOGFILE, maxBytes=(1048576*5), backupCount=7)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.