Python günlük çıktısını nasıl renklendirebilirim?


354

Bir süre önce, muhtemelen günlük sistemi nedeniyle (tüm mesajlar standartlaştırıldığı için) renkli çıktıya sahip bir Mono uygulaması gördüm.

Şimdi, Python, loggingçıktıyı özelleştirmek için birçok seçenek belirlemenizi sağlayan modüle sahiptir . Yani, benzer bir şeyin Python ile mümkün olacağını hayal ediyorum, ama bunu hiçbir yerde nasıl yapacağımı bulamıyorum.

Python loggingmodülü çıktısını renkli yapmanın bir yolu var mı ?

İstediğim (örneğin) kırmızı hatalar, mavi veya sarı hatalar ayıklama vb.

Tabii ki bu muhtemelen uyumlu bir terminal gerektirir (çoğu modern terminal vardır); ancak loggingrenk desteklenmiyorsa orijinal çıktıya geri dönebilirim .

Loglama modülü ile nasıl renkli çıktı alabileceğime dair bir fikrin var mı?


1
Hem Linux hem de Windows olmak üzere çok platformlu bir çözüm istediğinizi belirtmelisiniz.
sorin

1
Eclipse / PyDev kullanıyorsanız ilgili: Tutulma konsolundaki günlükleri
renklendirme


5
Tüm işletim sistemlerini ve Python sürümlerini (2.7 ve 3. *) desteklemek için yazdığım chromalog'u da deneyebilirsiniz
ereOn

1
Aslında ANSI kodlarını günlük dosyasına döken çözümler kötü bir fikirdir, altı ay içinde bir şey için selamlıyorsanız sizi yakalarlar, ancak normal ifadenizde ANSI karakterlerine izin vermeyi unuturlar. Aşağıda, günlüğü yazarken değil, günlüğü görüntülerken renk ekleyen bazı çözümler var ...
Jonathan Hartley

Yanıtlar:


192

Renklerin kaçtığını zaten biliyordum, bir süre önce bash istemimde kullandım. Yine de teşekkürler.
İstediğim, sonunda birkaç deneme ve hatadan sonra yaptığım günlükleme modülü ile entegre etmekti.
İşte sonunda ne ile:

BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8)

#The background is set with 40 plus the number of the color, and the foreground with 30

#These are the sequences need to get colored ouput
RESET_SEQ = "\033[0m"
COLOR_SEQ = "\033[1;%dm"
BOLD_SEQ = "\033[1m"

def formatter_message(message, use_color = True):
    if use_color:
        message = message.replace("$RESET", RESET_SEQ).replace("$BOLD", BOLD_SEQ)
    else:
        message = message.replace("$RESET", "").replace("$BOLD", "")
    return message

COLORS = {
    'WARNING': YELLOW,
    'INFO': WHITE,
    'DEBUG': BLUE,
    'CRITICAL': YELLOW,
    'ERROR': RED
}

class ColoredFormatter(logging.Formatter):
    def __init__(self, msg, use_color = True):
        logging.Formatter.__init__(self, msg)
        self.use_color = use_color

    def format(self, record):
        levelname = record.levelname
        if self.use_color and levelname in COLORS:
            levelname_color = COLOR_SEQ % (30 + COLORS[levelname]) + levelname + RESET_SEQ
            record.levelname = levelname_color
        return logging.Formatter.format(self, record)

Ve kullanmak için kendi Logger'ınızı oluşturun:

# Custom logger class with multiple destinations
class ColoredLogger(logging.Logger):
    FORMAT = "[$BOLD%(name)-20s$RESET][%(levelname)-18s]  %(message)s ($BOLD%(filename)s$RESET:%(lineno)d)"
    COLOR_FORMAT = formatter_message(FORMAT, True)
    def __init__(self, name):
        logging.Logger.__init__(self, name, logging.DEBUG)                

        color_formatter = ColoredFormatter(self.COLOR_FORMAT)

        console = logging.StreamHandler()
        console.setFormatter(color_formatter)

        self.addHandler(console)
        return


logging.setLoggerClass(ColoredLogger)

Başka birinin buna ihtiyacı varsa.

Birden fazla günlükçü veya işleyici kullanıyorsanız dikkatli olun: ColoredFormatterdiğer işleyicilere iletilen veya diğer günlükçilere yayılan kayıt nesnesini değiştiriyor. Dosya günlüklerini vb. Yapılandırdıysanız, büyük olasılıkla günlük dosyalarında renk olmasını istemezsiniz. Bunu önlemek için, sadece bir kopyasını oluşturmak için en iyisi recordile copy.copy()levelname özelliğini manipüle önce, ya da (kredi biçimlendirilmiş dize dönmeden önce, bir önceki değere levelname sıfırlamak için Michael yorumlarda).


SARI, BEYAZ, MAVİ vb. Nerede tanımlanır?
Swaroop CH

1
@Swaroop - Bunlar, Google'da arama yapabileceğiniz veya burada bulabileceğiniz ANSI kaçış kodlarıdır: en.wikipedia.org/wiki/ANSI_escape_code veya alternatif olarak pueblo.sourceforge.net/doc/manual/ansi_color_codes.html
Brian M Av

53
Sadece bunun için bir logger alt sınıfı oluşturmanız gerektiğine inanmıyorum - cevabınız, bir uzman oluşturmak Formatterve bir kullanımını belirtmek kadar iyidir StreamHandler. Ancak kaydedici alt sınıfına gerek yoktur. Aslında bir logger sınıfının kullanılması, oluşturulan her logger'a bir işleyici ekler, ki bu genellikle istediğiniz şey değildir.
Vinay Sajip


6
Bir tarafı not ColoredFormatter. Diğer işleyicilere iletilen veya diğer günlükçilere yayılan kayıt nesnesini değiştiriyor. Dosya günlüklerini vb. Yapılandırdıysanız, büyük olasılıkla günlük dosyalarında renk olmasını istemezsiniz. Bundan kaçınmak için, muhtemelen en iyisi, levelname özniteliğini değiştirmeden önce recordile bir kopyasını oluşturmak copy.copy()veya biçimlendirilmiş dizeyi döndürmeden önce level adını bir önceki değere sıfırlamaktır.
Michael

149

Yıllar önce kendi kullanımım için renkli bir akış işleyicisi yazdım. Sonra bu sayfada rastladım ve insanlar kopyalama / :-( yapıştırarak olduklarını kod parçacıkları bir koleksiyon buldum. Benim akışı işleyici şu anda sadece UNIX (Linux, Mac OS X) üzerinde çalışır fakat avantajı olmasıdır PyPI geçerli (ve GitHub ) ve kullanımı çok basit.Ayrıca bir Vim sözdizimi modu var :-). Gelecekte Windows üzerinde çalışacak şekilde genişletebilirim.

Paketi yüklemek için:

$ pip install coloredlogs

Çalıştığını doğrulamak için:

$ coloredlogs --demo

Kendi kodunuzu kullanmaya başlamak için:

$ python
> import coloredlogs, logging
> coloredlogs.install()
> logging.info("It works!")
2014-07-30 21:21:26 peter-macbook root[7471] INFO It works!

Yukarıdaki örnekte gösterilen varsayılan günlük biçimi tarih, saat, ana bilgisayar adı, günlükçünün adı, PID, günlük düzeyi ve günlük mesajını içerir. Pratikte böyle görünüyor:

Coloredlogs output ekran görüntüsü

NOT: MinTTY ile Git Bash kullanırken

Windows'ta Git Bash'in belgelenmiş bazı tuhaflıkları var: Winpty ve Git Bash

Hangi ANSI kaçış kodları ve ncurses tarzı karakter yeniden yazma ve animasyonlar için, komutların önüne ön ek eklemeniz gerekir winpty.

$ winpty coloredlogs --demo
$ winpty python your_colored_logs_script.py

2
yeterince komik, ben sadece bu konuda " pypi.python.org/pypi/coloredlogs/0.4.7 " için bir bağlantı eklemek için gidiyordu !
Iosu S.

1
Nedense AttributeError: 'module' object has no attribute 'install'kullanırken almaya devam ediyorum coloredlogs.install(). Bunu en son sürümle onaylayabilir misiniz?
con-f-use

11
Bu çok güzel görünüyor. Ne yazık ki, birçok şeyi kırar; özellikle logging.basicConfig çağrılarını geçersiz kılar. Bu, örneğin özel bir biçimlendiricinin kullanılmasını imkansız hale getirir.
Clément

@ Clément: İki (örtüşen?) Soru: (1) Tam olarak "logging.basicConfig çağrılarını geçersiz kılar" ve (2) alternatif ne anlama gelir? Her ikisi de logging.basicConfig()ve coloredlogs.install()konsolda oturum açan bir akış işleyicisi yükleyin, böylece "geçersiz" olmadan yinelenen iletiler alırsınız ...
xolox

Pakette coloredlogs.installolduğu gibi (1) veya (daha makul olarak) hangi formatın kullanılacağını söylemenin bir yolu için sihir bekledim colorlog.
Clément

74

İşte herhangi bir platformda çalışması gereken bir çözüm. Sadece bana söylemiyorsa ben de güncelleyeceğim.

Nasıl çalışır: ANSI kaçışlarını destekleyen platformda bunları (Windows olmayan) kullanıyor ve Windows'ta konsol renklerini değiştirmek için API çağrılarını kullanıyor.

Komut dosyası, standart kütüphaneden logging.StreamHandler.emit yöntemini bir paketleyici ekleyerek hackler.

TestColorer.py

# Usage: add Colorer.py near you script and import it.
import logging
import Colorer

logging.warn("a warning")
logging.error("some error")
logging.info("some info")

Colorer.py

#!/usr/bin/env python
# encoding: utf-8
import logging
# now we patch Python code to add color support to logging.StreamHandler
def add_coloring_to_emit_windows(fn):
        # add methods we need to the class
    def _out_handle(self):
        import ctypes
        return ctypes.windll.kernel32.GetStdHandle(self.STD_OUTPUT_HANDLE)
    out_handle = property(_out_handle)

    def _set_color(self, code):
        import ctypes
        # Constants from the Windows API
        self.STD_OUTPUT_HANDLE = -11
        hdl = ctypes.windll.kernel32.GetStdHandle(self.STD_OUTPUT_HANDLE)
        ctypes.windll.kernel32.SetConsoleTextAttribute(hdl, code)

    setattr(logging.StreamHandler, '_set_color', _set_color)

    def new(*args):
        FOREGROUND_BLUE      = 0x0001 # text color contains blue.
        FOREGROUND_GREEN     = 0x0002 # text color contains green.
        FOREGROUND_RED       = 0x0004 # text color contains red.
        FOREGROUND_INTENSITY = 0x0008 # text color is intensified.
        FOREGROUND_WHITE     = FOREGROUND_BLUE|FOREGROUND_GREEN |FOREGROUND_RED
       # winbase.h
        STD_INPUT_HANDLE = -10
        STD_OUTPUT_HANDLE = -11
        STD_ERROR_HANDLE = -12

        # wincon.h
        FOREGROUND_BLACK     = 0x0000
        FOREGROUND_BLUE      = 0x0001
        FOREGROUND_GREEN     = 0x0002
        FOREGROUND_CYAN      = 0x0003
        FOREGROUND_RED       = 0x0004
        FOREGROUND_MAGENTA   = 0x0005
        FOREGROUND_YELLOW    = 0x0006
        FOREGROUND_GREY      = 0x0007
        FOREGROUND_INTENSITY = 0x0008 # foreground color is intensified.

        BACKGROUND_BLACK     = 0x0000
        BACKGROUND_BLUE      = 0x0010
        BACKGROUND_GREEN     = 0x0020
        BACKGROUND_CYAN      = 0x0030
        BACKGROUND_RED       = 0x0040
        BACKGROUND_MAGENTA   = 0x0050
        BACKGROUND_YELLOW    = 0x0060
        BACKGROUND_GREY      = 0x0070
        BACKGROUND_INTENSITY = 0x0080 # background color is intensified.     

        levelno = args[1].levelno
        if(levelno>=50):
            color = BACKGROUND_YELLOW | FOREGROUND_RED | FOREGROUND_INTENSITY | BACKGROUND_INTENSITY 
        elif(levelno>=40):
            color = FOREGROUND_RED | FOREGROUND_INTENSITY
        elif(levelno>=30):
            color = FOREGROUND_YELLOW | FOREGROUND_INTENSITY
        elif(levelno>=20):
            color = FOREGROUND_GREEN
        elif(levelno>=10):
            color = FOREGROUND_MAGENTA
        else:
            color =  FOREGROUND_WHITE
        args[0]._set_color(color)

        ret = fn(*args)
        args[0]._set_color( FOREGROUND_WHITE )
        #print "after"
        return ret
    return new

def add_coloring_to_emit_ansi(fn):
    # add methods we need to the class
    def new(*args):
        levelno = args[1].levelno
        if(levelno>=50):
            color = '\x1b[31m' # red
        elif(levelno>=40):
            color = '\x1b[31m' # red
        elif(levelno>=30):
            color = '\x1b[33m' # yellow
        elif(levelno>=20):
            color = '\x1b[32m' # green 
        elif(levelno>=10):
            color = '\x1b[35m' # pink
        else:
            color = '\x1b[0m' # normal
        args[1].msg = color + args[1].msg +  '\x1b[0m'  # normal
        #print "after"
        return fn(*args)
    return new

import platform
if platform.system()=='Windows':
    # Windows does not support ANSI escapes and we are using API calls to set the console color
    logging.StreamHandler.emit = add_coloring_to_emit_windows(logging.StreamHandler.emit)
else:
    # all non-Windows platforms are supporting ANSI escapes so we use them
    logging.StreamHandler.emit = add_coloring_to_emit_ansi(logging.StreamHandler.emit)
    #log = logging.getLogger()
    #log.addFilter(log_filter())
    #//hdlr = logging.StreamHandler()
    #//hdlr.setFormatter(formatter())

3
Buna dayanarak bir StreamHandler sınıfı yazdım, bkz. Gist.github.com/mooware/a1ed40987b6cc9ab9c65 .
mooware

2
bu benim için çalıştı! satır 90: olmalıdır args[1].msg = color + str(args[1].msg) + '\x1b[0m' # normal.
Rasika Perera

Bu çözümü seviyorum. şu anda kullanıyor. Görüyorum ki _set_color özniteliği var, belirli bir günlük iletisi için bunu yapmanın bir yolu var mı? düzenleme , oh görmek sadece bir yama için windows makineleri. farklı kullanım durumları için özel eklemek güzel olurdu.
brizz

ANSI rengi için +1. Xterm'de aynı anda 256 renk bile alabilirsiniz ve paleti dinamik olarak tanımlayabilirsiniz! Bununla birlikte, bir işlev tanımının dışında oturum açarken olası alma kilidi sorunlarını önlemek için günlük işlevlerine yapılan tüm çağrıların bir işlev tanımı içinde olması gerektiğini unutmayın . Kodunuz çoğunlukla iyi görünüyor; TestColorer.pybeni biraz endişelendiriyor.
personal_cloud

Bu, gerçek günlük dosyalarındaki günlük iletilerinin başında ve sonunda renk kodlarıyla sonuçlanır.
MehmedB

74

Güncelleme : Bu çok uzun süredir çizmek istediğim bir kaşıntı olduğu için devam ettim ve benim gibi tembel insanlar için basit şeyler yapmak isteyen basit bir kütüphane yazdım: zenlog

Colorlog bunun için mükemmel. Bu var PyPI geçerli (ve dolayısıyla kurulabilir through pip install colorlog) ve aktif olarak tutulan .

Günlük kaydını ayarlamak ve düzgün görünen günlük iletileri yazdırmak için hızlı bir kopyala ve yapıştırılabilir snippet:

import logging
LOG_LEVEL = logging.DEBUG
LOGFORMAT = "  %(log_color)s%(levelname)-8s%(reset)s | %(log_color)s%(message)s%(reset)s"
from colorlog import ColoredFormatter
logging.root.setLevel(LOG_LEVEL)
formatter = ColoredFormatter(LOGFORMAT)
stream = logging.StreamHandler()
stream.setLevel(LOG_LEVEL)
stream.setFormatter(formatter)
log = logging.getLogger('pythonConfig')
log.setLevel(LOG_LEVEL)
log.addHandler(stream)

log.debug("A quirky message only developers care about")
log.info("Curious users might want to know this")
log.warn("Something is wrong and any user should be informed")
log.error("Serious stuff, this is red for a reason")
log.critical("OH NO everything is on fire")

Çıktı:

Colorlog çıktısı


4
Mükemmel cevap; +1. Kod örneği olsa kırpılabilir ( setLevelgerçekten üç çağrı gerekli mi?)
Clément

1
Eğer cevapları yeterince uzun süre geçirdiysem böyle bir cevap bulacağımı umuyordum. ☺ Umarım @airmind bunu kabul edilmiş bir cevap yapmayı düşünür, böylece gelecekteki iş zeki insanlar en iyi tembelliğe sahip en iyi kütüphane gibi görünen şeyleri bulabilirler. 😉
Michael Scheper

Ben sadece ÇIKTI ^ ^
Agustin Barrachina

69

Önceden tanımlanmış kayıt seviyeleri için ve yeni bir sınıf tanımlamadan hızlı ve kirli çözüm.

logging.addLevelName( logging.WARNING, "\033[1;31m%s\033[1;0m" % logging.getLevelName(logging.WARNING))
logging.addLevelName( logging.ERROR, "\033[1;41m%s\033[1;0m" % logging.getLevelName(logging.ERROR))

@ spiderplant0 içe aktarma günlüğü; # @ABC'den kodu yapıştırın; logging.warning ile deneyin ('bu bir testtir'). "UYARI: Bu bir testtir" in büyük harfinin renkli olduğunu göreceksiniz. Linux sadece btw üzerinde çalışıyor
Riccardo Galli

3
Yalnızca loglevel adı renklendirildiğinden, loglevel adının konsola yazdırıldığından emin olmanız gerekir. Bu benim için kutudan çıkmaz. Bu çizgiler boyunca bir şey yardımcı olacaktır: logging.basicConfig(format='%(asctime)s [%(name)s] [%(levelname)s] %(message)s')Tabii ki %(levelnames)sönemli.
Sebastian

4
Uygulamak ve anlamak için en basit ve en temiz çözüm.
F. Santiago

1
Linux konsolunda deneyin. echo -e "Normal texst \033[1;31mred bold text\033[0m normal text again". echo -eoption "\ 033" kelimesini Escape ASCII sembolünün sekizli formu olarak yorumlar. Bu özel sembol, bazı uyumlu terminalleri sonraki karakterleri (karakter mdahil olmak üzere) özel komutlar olarak yorumlar. en.wikipedia.org/wiki/ANSI_escape_code
eugene-parlak

1
Küçük gelişme: bu kodu içeri koyun if sys.sdterr.isatty():. Bu durumda, çıktıyı dosyaya yönlendirirseniz, dosya bu çıkış karakterlerini içermez.
lesnik

36

2020 kodu, ek paket gerekmez, Python 3

Sınıf tanımlama

import logging

class CustomFormatter(logging.Formatter):
    """Logging Formatter to add colors and count warning / errors"""

    grey = "\x1b[38;21m"
    yellow = "\x1b[33;21m"
    red = "\x1b[31;21m"
    bold_red = "\x1b[31;1m"
    reset = "\x1b[0m"
    format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s (%(filename)s:%(lineno)d)"

    FORMATS = {
        logging.DEBUG: grey + format + reset,
        logging.INFO: grey + format + reset,
        logging.WARNING: yellow + format + reset,
        logging.ERROR: red + format + reset,
        logging.CRITICAL: bold_red + format + reset
    }

    def format(self, record):
        log_fmt = self.FORMATS.get(record.levelno)
        formatter = logging.Formatter(log_fmt)
        return formatter.format(record)

Örnek günlükçü

# create logger with 'spam_application'
logger = logging.getLogger("My_app")
logger.setLevel(logging.DEBUG)

# create console handler with a higher log level
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)

ch.setFormatter(CustomFormatter())

logger.addHandler(ch)

Ve kullan!

logger.debug("debug message")
logger.info("info message")
logger.warning("warning message")
logger.error("error message")
logger.critical("critical message")

Sonuç resim açıklamasını buraya girin

Tam renk şeması resim açıklamasını buraya girin

Pencereler için

Bu çözüm Mac OS, IDE terminallerinde çalışır. Görünüşe göre pencerenin komut isteminde varsayılan olarak hiç renk yok. İşte onları nasıl etkinleştireceğinizi gösteren talimatlar, https://www.howtogeek.com/322432/how-to-customize-your-command-prompts-color-scheme-with-microsofts-colortool/


1
Testi çalıştırıyorum (python 3.7, windows), ancak günlük kaydı renkleri göstermiyor:←[38;21m2019-11-12 19:29:50,994 - My_app - DEBUG - debug message (test_colored_log.py:43)←[0m ←[38;21m2019-11-12 19:29:50,994 - My_app - INFO - info message (test_colored_log.py:44)←[0m ←[33;21m2019-11-12 19:29:50,994 - My_app - WARNING - warning message (test_colored_log.py:45)←[0m ←[31;21m2019-11-12 19:29:50,994 - My_app - ERROR - error message (test_colored_log.py:46)←[0m ←[31;1m2019-11-12 19:29:50,994 - My_app - CRITICAL - critical message (test_colored_log.py:47)←[0m
yapıcı

2
Bu yanıtı çok beğendim, bir repo yaptım , birkaç artış ve bir ansi renk hile sayfası ile bir .
Teodoro

@constructor Nerede çalıştırıyorsunuz? IDE konsolu mu? Windows terminali?
Sergey Pleshakov

@Joe tam olarak ne işe yaramıyor? ortamınız nedir ve hangi hataları alıyorsunuz? Platformlarda çalışmasını sağlamak için çözümü gözden geçirmek istiyorum
Sergey Pleshakov

@SergeyPleshakov Terminal Visual Studio Code'da tekrar test ettim ve şimdi çalışıyor, ancak Windows komut satırında çalışmıyor:[38;21m2020-06-03 21:12:46,363 [INFO ] [algo] info[0m [33;21m2020-06-03 21:12:46,363 [WARNING] [algo] warning [algo.py:18][0m [31;21m2020-06-03 21:12:46,363 [ERROR ] [algo] error[0m [38;21m2020-06-03 21:12:46,364 [INFO ] [algo] result: None[0m
yapıcı

17

Sanırım renkli logger varyasyonumu da ekleyebilirim.

Bu süslü bir şey değildir, ancak kullanımı çok basittir ve kayıt nesnesini değiştirmez, böylece bir dosya işleyicisi kullanılıyorsa ANSI kaçış dizilerinin bir günlük dosyasına kaydedilmesini önler. Günlük mesajı biçimlendirmesini etkilemez.

Günlükleme modülünün Formatter'ını zaten kullanıyorsanız, renkli düzey adları almak için yapmanız gereken tek şey, Formatter öğütücü işleyicilerinizi ColoredFormatter ile değiştirmektir. Tüm bir uygulamayı günlüğe kaydediyorsanız, bunu yalnızca üst düzey günlükçü için yapmanız gerekir.

colored_log.py

#!/usr/bin/env python

from copy import copy
from logging import Formatter

MAPPING = {
    'DEBUG'   : 37, # white
    'INFO'    : 36, # cyan
    'WARNING' : 33, # yellow
    'ERROR'   : 31, # red
    'CRITICAL': 41, # white on red bg
}

PREFIX = '\033['
SUFFIX = '\033[0m'

class ColoredFormatter(Formatter):

    def __init__(self, patern):
        Formatter.__init__(self, patern)

    def format(self, record):
        colored_record = copy(record)
        levelname = colored_record.levelname
        seq = MAPPING.get(levelname, 37) # default white
        colored_levelname = ('{0}{1}m{2}{3}') \
            .format(PREFIX, seq, levelname, SUFFIX)
        colored_record.levelname = colored_levelname
        return Formatter.format(self, colored_record)

Örnek kullanım

app.py

#!/usr/bin/env python

import logging
from colored_log import ColoredFormatter

# Create top level logger
log = logging.getLogger("main")

# Add console handler using our custom ColoredFormatter
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
cf = ColoredFormatter("[%(name)s][%(levelname)s]  %(message)s (%(filename)s:%(lineno)d)")
ch.setFormatter(cf)
log.addHandler(ch)

# Add file handler
fh = logging.FileHandler('app.log')
fh.setLevel(logging.DEBUG)
ff = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setFormatter(ff)
log.addHandler(fh)

# Set log level
log.setLevel(logging.DEBUG)

# Log some stuff
log.debug("app has started")
log.info("Logging to 'app.log' in the script dir")
log.warning("This is my last warning, take heed")
log.error("This is an error")
log.critical("He's dead, Jim")

# Import a sub-module 
import sub_module

sub_module.py

#!/usr/bin/env python

import logging
log = logging.getLogger('main.sub_module')

log.debug("Hello from the sub module")

Sonuçlar

Terminal çıkışı

Terminal çıkışı

app.log içeriği

2017-09-29 00:32:23,434 - main - DEBUG - app has started
2017-09-29 00:32:23,434 - main - INFO - Logging to 'app.log' in the script dir
2017-09-29 00:32:23,435 - main - WARNING - This is my last warning, take heed
2017-09-29 00:32:23,435 - main - ERROR - This is an error
2017-09-29 00:32:23,435 - main - CRITICAL - He's dead, Jim
2017-09-29 00:32:23,435 - main.sub_module - DEBUG - Hello from the sub module

Tabii ki terminal ve günlük dosyası çıktılarını biçimlendirerek istediğiniz kadar süslü hale gelebilirsiniz. Yalnızca kayıt seviyesi renklendirilecektir.

Umarım birisi bunu faydalı bulur ve aynı şeyden çok daha fazlası değildir. :)

Python örnek dosyaları bu GitHub Gist'ten indirilebilir: https://gist.github.com/KurtJacobson/48e750701acec40c7161b5a2f79e6bfd


2
BTW mesajın kendisine renk eklemek için önce bu satırı ekleyin return:colored_record.msg = ('{0}{1}m{2}{3}').format(self.PREFIX, seq, colored_record.getMessage(), self.SUFFIX)
The Godfather

15

Ön plan ve arka plan için airmind destekleyici etiketlerden örnek güncelledim. Günlük biçimlendirici dizenizde $ BLACK - $ WHITE renk değişkenlerini kullanmanız yeterlidir. Arka planı ayarlamak için sadece $ BG-BLACK - $ BG-WHITE kullanın.

import logging

BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8)

COLORS = {
    'WARNING'  : YELLOW,
    'INFO'     : WHITE,
    'DEBUG'    : BLUE,
    'CRITICAL' : YELLOW,
    'ERROR'    : RED,
    'RED'      : RED,
    'GREEN'    : GREEN,
    'YELLOW'   : YELLOW,
    'BLUE'     : BLUE,
    'MAGENTA'  : MAGENTA,
    'CYAN'     : CYAN,
    'WHITE'    : WHITE,
}

RESET_SEQ = "\033[0m"
COLOR_SEQ = "\033[1;%dm"
BOLD_SEQ  = "\033[1m"

class ColorFormatter(logging.Formatter):

    def __init__(self, *args, **kwargs):
        # can't do super(...) here because Formatter is an old school class
        logging.Formatter.__init__(self, *args, **kwargs)

    def format(self, record):
        levelname = record.levelname
        color     = COLOR_SEQ % (30 + COLORS[levelname])
        message   = logging.Formatter.format(self, record)
        message   = message.replace("$RESET", RESET_SEQ)\
                           .replace("$BOLD",  BOLD_SEQ)\
                           .replace("$COLOR", color)
        for k,v in COLORS.items():
            message = message.replace("$" + k,    COLOR_SEQ % (v+30))\
                             .replace("$BG" + k,  COLOR_SEQ % (v+40))\
                             .replace("$BG-" + k, COLOR_SEQ % (v+40))
        return message + RESET_SEQ

logging.ColorFormatter = ColorFormatter

Böylece, yapılandırma dosyanızda aşağıdakileri basitçe yapabilirsiniz:

[formatter_colorFormatter]
class=logging.ColorFormatter
format= $COLOR%(levelname)s $RESET %(asctime)s $BOLD$COLOR%(name)s$RESET %(message)s

Büyük gelişme. Ancak hakkında yorum supersadece sanırım bazı eski Python sürümü için geçerlidir? Bu cevap 2010'dan beri. Python 2.7
Joakim

14

Sen alabilirsiniz colorlog modülü ve kullanımı ColoredFormattergünlük iletilerini renklendirmek için.

Misal

Ana modül için kazan plakası:

import logging
import os
import sys
try:
    import colorlog
except ImportError:
    pass

def setup_logging():
    root = logging.getLogger()
    root.setLevel(logging.DEBUG)
    format      = '%(asctime)s - %(levelname)-8s - %(message)s'
    date_format = '%Y-%m-%d %H:%M:%S'
    if 'colorlog' in sys.modules and os.isatty(2):
        cformat = '%(log_color)s' + format
        f = colorlog.ColoredFormatter(cformat, date_format,
              log_colors = { 'DEBUG'   : 'reset',       'INFO' : 'reset',
                             'WARNING' : 'bold_yellow', 'ERROR': 'bold_red',
                             'CRITICAL': 'bold_red' })
    else:
        f = logging.Formatter(format, date_format)
    ch = logging.StreamHandler()
    ch.setFormatter(f)
    root.addHandler(ch)

setup_logging()
log = logging.getLogger(__name__)

Kod, eğer colorlog modülü takılıysa ve çıktı gerçekten bir terminale giderse, günlük mesajlarındaki renkleri etkinleştirir. Bu, günlük çıktısı yeniden yönlendirildiğinde kaçış dizilerinin bir dosyaya yazılmasını önler.

Ayrıca, koyu arka planı olan terminaller için daha uygun olan özel bir renk düzeni ayarlanır.

Bazı günlük kaydı çağrıları:

log.debug   ('Hello Debug')
log.info    ('Hello Info')
log.warn    ('Hello Warn')
log.error   ('Hello Error')
log.critical('Hello Critical')

Çıktı:

resim açıklamasını buraya girin


2
Ayrıca bazı iyi varsayılanları olan colorlog.basicConfigyerine kullanabilirsinizlogging.basicConfig
MarSoft

1
Kayıt için, colorlog her zaman doğrudan Windows platformlarında çalışmaz (belirtildiği gibi, colorama bağımlılığı gereklidir). Bununla bile, Anaconda / Spyder env'de çalışmak için sorun yaşadım. Örneğin escape_code.py'de (bu konudaki github.com/spyder-ide/spyder/issues/1917 ) colorama.init (strip = False) belirtmeniz gerekebilir
Matt-Mac-Muffin


11

Sorin tarafından sağlanan orijinal örneği değiştirdim ve StreamHandler'i ColorizedConsoleHandler'a alt sınıfta değiştirdim.

Çözümlerinin dezavantajı, iletiyi değiştirmesidir ve bu, gerçek günlük iletisini değiştirdiği için, diğer tüm işleyiciler de değiştirilmiş iletiyi alır.

Bu, bizim durumumuzda renk kodları olan günlük dosyalarına neden oldu, çünkü birden fazla kaydedici kullanıyoruz.

Aşağıdaki sınıf yalnızca ansi'yi destekleyen platformlarda çalışır, ancak Windows renk kodlarını eklemek önemsiz olmalıdır.

import copy
import logging


class ColoredConsoleHandler(logging.StreamHandler):
    def emit(self, record):
        # Need to make a actual copy of the record
        # to prevent altering the message for other loggers
        myrecord = copy.copy(record)
        levelno = myrecord.levelno
        if(levelno >= 50):  # CRITICAL / FATAL
            color = '\x1b[31m'  # red
        elif(levelno >= 40):  # ERROR
            color = '\x1b[31m'  # red
        elif(levelno >= 30):  # WARNING
            color = '\x1b[33m'  # yellow
        elif(levelno >= 20):  # INFO
            color = '\x1b[32m'  # green
        elif(levelno >= 10):  # DEBUG
            color = '\x1b[35m'  # pink
        else:  # NOTSET and anything else
            color = '\x1b[0m'  # normal
        myrecord.msg = color + str(myrecord.msg) + '\x1b[0m'  # normal
        logging.StreamHandler.emit(self, myrecord)


7

Tonlarca cevap var. Ama hiçbiri dekoratörler hakkında konuşmuyor. İşte benim.

Çünkü çok daha basit.

Hiçbir şey içe aktarmaya veya alt sınıf yazmaya gerek yoktur:

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


import logging


NO_COLOR = "\33[m"
RED, GREEN, ORANGE, BLUE, PURPLE, LBLUE, GREY = \
    map("\33[%dm".__mod__, range(31, 38))

logging.basicConfig(format="%(message)s", level=logging.DEBUG)
logger = logging.getLogger(__name__)

# the decorator to apply on the logger methods info, warn, ...
def add_color(logger_method, color):
  def wrapper(message, *args, **kwargs):
    return logger_method(
      # the coloring is applied here.
      color+message+NO_COLOR,
      *args, **kwargs
    )
  return wrapper

for level, color in zip((
  "info", "warn", "error", "debug"), (
  GREEN, ORANGE, RED, BLUE
)):
  setattr(logger, level, add_color(getattr(logger, level), color))

# this is displayed in red.
logger.error("Launching %s." % __file__)

Bu, kırmızıdaki hataları, mavi hata ayıklama mesajlarını vb. Ayarlar. Soruda olduğu gibi.

Hatta sarıcıyı colorkullanarak mesajın rengini dinamik olarak ayarlamak için bir argüman almak üzere uyarlayabiliriz.logger.debug("message", color=GREY)

EDIT: İşte çalışma zamanında renkleri ayarlamak için uyarlanmış dekoratör:

def add_color(logger_method, _color):
  def wrapper(message, *args, **kwargs):
    color = kwargs.pop("color", _color)
    if isinstance(color, int):
      color = "\33[%dm" % color
    return logger_method(
      # the coloring is applied here.
      color+message+NO_COLOR,
      *args, **kwargs
    )
  return wrapper

# blah blah, apply the decorator...

# this is displayed in red.
logger.error("Launching %s." % __file__)
# this is displayed in blue
logger.error("Launching %s." % __file__, color=34)
# and this, in grey
logger.error("Launching %s." % __file__, color=GREY)

6

Airmind'in her şeyi bir sınıfta tutan yaklaşımının bir başka küçük remiksi:

class ColorFormatter(logging.Formatter):
  FORMAT = ("[$BOLD%(name)-20s$RESET][%(levelname)-18s]  "
            "%(message)s "
            "($BOLD%(filename)s$RESET:%(lineno)d)")

  BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8)

  RESET_SEQ = "\033[0m"
  COLOR_SEQ = "\033[1;%dm"
  BOLD_SEQ = "\033[1m"

  COLORS = {
    'WARNING': YELLOW,
    'INFO': WHITE,
    'DEBUG': BLUE,
    'CRITICAL': YELLOW,
    'ERROR': RED
  }

  def formatter_msg(self, msg, use_color = True):
    if use_color:
      msg = msg.replace("$RESET", self.RESET_SEQ).replace("$BOLD", self.BOLD_SEQ)
    else:
      msg = msg.replace("$RESET", "").replace("$BOLD", "")
    return msg

  def __init__(self, use_color=True):
    msg = self.formatter_msg(self.FORMAT, use_color)
    logging.Formatter.__init__(self, msg)
    self.use_color = use_color

  def format(self, record):
    levelname = record.levelname
    if self.use_color and levelname in self.COLORS:
      fore_color = 30 + self.COLORS[levelname]
      levelname_color = self.COLOR_SEQ % fore_color + levelname + self.RESET_SEQ
      record.levelname = levelname_color
    return logging.Formatter.format(self, record)

Formatlayıcıyı bir işleyiciye iliştirmek için aşağıdakine benzer:

handler.setFormatter(ColorFormatter())
logger.addHandler(handler)

5

Herhangi bir terminal metin boyama için basit ama çok esnek bir araçtır 'olduğu colout '.

pip install colout
myprocess | colout REGEX_WITH_GROUPS color1,color2...

Normal ifadenin 1. grubuyla eşleşen 'işlemim' çıktısındaki herhangi bir metin renk1, grup 2 renk2 vb. İle renklendirilir.

Örneğin:

tail -f /var/log/mylogfile | colout '^(\w+ \d+ [\d:]+)|(\w+\.py:\d+ .+\(\)): (.+)$' white,black,cyan bold,bold,normal

yani ilk regex grubu (parens) günlük dosyasındaki ilk tarihle, ikinci grup bir python dosya adı, satır numarası ve işlev adı ile eşleşir ve üçüncü grup bundan sonra gelen günlük iletisiyle eşleşir. Ayrıca paralel bir 'kalın / normaller' dizisi ve renk dizisi kullanıyorum. Bu şuna benzer:

renkli biçimlendirme ile günlük dosyası

Normal ifadelerimin hiçbiriyle eşleşmeyen satırların veya satır bölümlerinin hala yankılandığını unutmayın, bu nedenle bu 'grep --color' gibi değildir - hiçbir şey çıktıdan filtrelenmez.

Açıkçası bu, yalnızca günlük dosyalarını kuyruklamakla kalmayıp herhangi bir işlemle kullanabileceğiniz kadar esnektir. Genellikle bir şeyi renklendirmek istediğimde anında yeni bir normal ifadeyi karıştırıyorum. Bu nedenle, renklendirmeyi herhangi bir özel günlük dosyası boyama aracına tercih ederim, çünkü ne renk aldığımdan bağımsız olarak sadece bir araç öğrenmem gerekiyor: günlüğe kaydetme, test çıktısı, terminaldeki kod parçacıklarını vurgulayan sözdizimi vb.

Ayrıca, IMHO'nun kötü bir fikir olduğu günlük dosyasının içine ANSI kodlarını dökmekten de kaçınır, çünkü grep regex'inizde ANSI kodlarını eşleştirmeyi hatırlamadığınız sürece, günlük dosyasındaki kalıplar için selamlamak gibi şeyleri kıracaktır.


4
import logging
import sys

colors = {'pink': '\033[95m', 'blue': '\033[94m', 'green': '\033[92m', 'yellow': '\033[93m', 'red': '\033[91m',
      'ENDC': '\033[0m', 'bold': '\033[1m', 'underline': '\033[4m'}

logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)


def str_color(color, data):
    return colors[color] + str(data) + colors['ENDC']

params = {'param1': id1, 'param2': id2}

logging.info('\nParams:' + str_color("blue", str(params)))`

+1 [9*m"Parlak" ANSI renk kodlarıyla güzel örnek ! Not: Son satırınız beni biraz ilgilendiriyor çünkü bir fonksiyon tanımının dışında oturum açmanın Python'da güvenli olup olmadığı henüz bilinmiyor .
personal_cloud

2

İşte benim çözümüm:

class ColouredFormatter(logging.Formatter):
    RESET = '\x1B[0m'
    RED = '\x1B[31m'
    YELLOW = '\x1B[33m'
    BRGREEN = '\x1B[01;32m'  # grey in solarized for terminals

    def format(self, record, colour=False):
        message = super().format(record)

        if not colour:
            return message

        level_no = record.levelno
        if level_no >= logging.CRITICAL:
            colour = self.RED
        elif level_no >= logging.ERROR:
            colour = self.RED
        elif level_no >= logging.WARNING:
            colour = self.YELLOW
        elif level_no >= logging.INFO:
            colour = self.RESET
        elif level_no >= logging.DEBUG:
            colour = self.BRGREEN
        else:
            colour = self.RESET

        message = colour + message + self.RESET

        return message


class ColouredHandler(logging.StreamHandler):
    def __init__(self, stream=sys.stdout):
        super().__init__(stream)

    def format(self, record, colour=False):
        if not isinstance(self.formatter, ColouredFormatter):
            self.formatter = ColouredFormatter()

        return self.formatter.format(record, colour)

    def emit(self, record):
        stream = self.stream
        try:
            msg = self.format(record, stream.isatty())
            stream.write(msg)
            stream.write(self.terminator)
            self.flush()
        except Exception:
            self.handleError(record)


h = ColouredHandler()
h.formatter = ColouredFormatter('{asctime} {levelname:8} {message}', '%Y-%m-%d %H:%M:%S', '{')
logging.basicConfig(level=logging.DEBUG, handlers=[h])

1

Ben sorun vardı biraz biçimlendirici düzgün kurmak oldu:

class ColouredFormatter(logging.Formatter):    
    def __init__(self, msg):
        logging.Formatter.__init__(self, msg)
        self._init_colour = _get_colour()

    def close(self):
        # restore the colour information to what it was
        _set_colour(self._init_colour)

    def format(self, record):        
        # Add your own colourer based on the other examples
        _set_colour( LOG_LEVEL_COLOUR[record.levelno] )
        return logging.Formatter.format(self, record)         

def init():
    # Set up the formatter. Needs to be first thing done.
    rootLogger = logging.getLogger()
    hdlr = logging.StreamHandler()
    fmt = ColouredFormatter('%(message)s')
    hdlr.setFormatter(fmt)
    rootLogger.addHandler(hdlr)

Ve sonra kullanmak için:

import coloured_log
import logging

coloured_log.init()
logging.info("info")    
logging.debug("debug")    

coloured_log.close()    # restore colours

Sahte kod olması gerekiyordu (_set_colour da eksik), ancak bir şey ekledi. En çok sorun olan şey, biçimlendiricinin doğru şekilde nasıl takılacağını bilmekti.
Nick

"Tesisatçı jakı" çözümüne bakın. Bu sorunu çözmek için daha iyi bir yol olduğunu düşünüyorum (yani işleyici renklendirme yapmalıdır). stackoverflow.com/questions/384076/…
Nick

1

Diğer çözümler iyi görünse de bazı sorunları var. Bazıları bazen istenmeyen tüm çizgileri renklendirir ve bazıları birlikte sahip olabileceğiniz herhangi bir yapılandırmayı atlar. Aşağıdaki çözüm, iletinin kendisinden başka bir şeyi etkilemez.

kod

class ColoredFormatter(logging.Formatter):
    def format(self, record):
        if record.levelno == logging.WARNING:
            record.msg = '\033[93m%s\033[0m' % record.msg
        elif record.levelno == logging.ERROR:
            record.msg = '\033[91m%s\033[0m' % record.msg
        return logging.Formatter.format(self, record)

Misal

logger = logging.getLogger('mylogger')
handler = logging.StreamHandler()

log_format = '[%(asctime)s]:%(levelname)-7s:%(message)s'
time_format = '%H:%M:%S'
formatter = ColoredFormatter(log_format, datefmt=time_format)
handler.setFormatter(formatter)
logger.addHandler(handler)

logger.warn('this should be yellow')
logger.error('this should be red')

Çıktı

[17:01:36]:WARNING:this should be yellow
[17:01:37]:ERROR  :this should be red

Gördüğünüz gibi, diğer her şey çıktısı alınmakta ve başlangıç ​​renklerinde kalmaktadır. Mesajdan başka bir şey değiştirmek isterseniz log_format, örnekte renk kodlarını iletebilirsiniz .


kullandığımda, mesajlar iki kez yazdırılır. neden biliyor musun?
Validus Oculus

@ detaylandırabilir misiniz? Yani [17:01:36]:WARNING:this should be yellowthis should be yellowiki satır yazdırmak gibi bir şey mi demek istediniz ?
Pithikos

Yorumun özeti için özür dilerim. Birincisi oldu: [17:01:36]: UYARI: bu sarı olmalı \ nbu sarı olmalı. Ancak, sadece biçimlendirilmiş olanın gösterilmesini istiyorum, aksi takdirde gereksiz günlükler nedeniyle bir çöp gibi görünüyor.
Validus Oculus

@ MuratKarakuş, uygulama hakkında tam bir görüşe sahip olmadan bunun neden olduğundan emin değil. Özel bir kaydedici kullanıyorsanız belki bir noktada parazit yapıyor olabilirsiniz? Hızlı bir düzeltme kaldırmak olabilir 7s:%(message)sdan log_format.
Pithikos

1

Biri sadece iletiyi (ColoredFormatter) renklendiren ve biri tüm satırı (ColorizingStreamHandler) renklendiren eklemek için iki gönderme var. Bunlar ayrıca önceki çözümlerden daha fazla ANSI renk kodu içerir.

Bazı içerikler (değişiklikle) aşağıdaki kaynaklardan sağlanmıştır: http://plumberjack.blogspot.com/2010/12/colorizing-logging-output-in-terminals.html .

Yalnızca mesajı renklendirir:

class ColoredFormatter(logging.Formatter):
    """Special custom formatter for colorizing log messages!"""

    BLACK = '\033[0;30m'
    RED = '\033[0;31m'
    GREEN = '\033[0;32m'
    BROWN = '\033[0;33m'
    BLUE = '\033[0;34m'
    PURPLE = '\033[0;35m'
    CYAN = '\033[0;36m'
    GREY = '\033[0;37m'

    DARK_GREY = '\033[1;30m'
    LIGHT_RED = '\033[1;31m'
    LIGHT_GREEN = '\033[1;32m'
    YELLOW = '\033[1;33m'
    LIGHT_BLUE = '\033[1;34m'
    LIGHT_PURPLE = '\033[1;35m'
    LIGHT_CYAN = '\033[1;36m'
    WHITE = '\033[1;37m'

    RESET = "\033[0m"

    def __init__(self, *args, **kwargs):
        self._colors = {logging.DEBUG: self.DARK_GREY,
                        logging.INFO: self.RESET,
                        logging.WARNING: self.BROWN,
                        logging.ERROR: self.RED,
                        logging.CRITICAL: self.LIGHT_RED}
        super(ColoredFormatter, self).__init__(*args, **kwargs)

    def format(self, record):
        """Applies the color formats"""
        record.msg = self._colors[record.levelno] + record.msg + self.RESET
        return logging.Formatter.format(self, record)

    def setLevelColor(self, logging_level, escaped_ansi_code):
        self._colors[logging_level] = escaped_ansi_code

Bütün çizgiyi renklendirir:

class ColorizingStreamHandler(logging.StreamHandler):

    BLACK = '\033[0;30m'
    RED = '\033[0;31m'
    GREEN = '\033[0;32m'
    BROWN = '\033[0;33m'
    BLUE = '\033[0;34m'
    PURPLE = '\033[0;35m'
    CYAN = '\033[0;36m'
    GREY = '\033[0;37m'

    DARK_GREY = '\033[1;30m'
    LIGHT_RED = '\033[1;31m'
    LIGHT_GREEN = '\033[1;32m'
    YELLOW = '\033[1;33m'
    LIGHT_BLUE = '\033[1;34m'
    LIGHT_PURPLE = '\033[1;35m'
    LIGHT_CYAN = '\033[1;36m'
    WHITE = '\033[1;37m'

    RESET = "\033[0m"

    def __init__(self, *args, **kwargs):
        self._colors = {logging.DEBUG: self.DARK_GREY,
                        logging.INFO: self.RESET,
                        logging.WARNING: self.BROWN,
                        logging.ERROR: self.RED,
                        logging.CRITICAL: self.LIGHT_RED}
        super(ColorizingStreamHandler, self).__init__(*args, **kwargs)

    @property
    def is_tty(self):
        isatty = getattr(self.stream, 'isatty', None)
        return isatty and isatty()

    def emit(self, record):
        try:
            message = self.format(record)
            stream = self.stream
            if not self.is_tty:
                stream.write(message)
            else:
                message = self._colors[record.levelno] + message + self.RESET
                stream.write(message)
            stream.write(getattr(self, 'terminator', '\n'))
            self.flush()
        except (KeyboardInterrupt, SystemExit):
            raise
        except:
            self.handleError(record)

    def setLevelColor(self, logging_level, escaped_ansi_code):
        self._colors[logging_level] = escaped_ansi_code


1

Bu renk kodlarını içeren bir Enum'dur:

class TerminalColour:
    """
    Terminal colour formatting codes
    """
    # /programming/287871/print-in-terminal-with-colors
    MAGENTA = '\033[95m'
    BLUE = '\033[94m'
    GREEN = '\033[92m'
    YELLOW = '\033[93m'
    RED = '\033[91m'
    GREY = '\033[0m'  # normal
    WHITE = '\033[1m'  # bright white
    UNDERLINE = '\033[4m'

Bu , her günlük seviyesinin adlarına uygulanabilir . Bunun korkunç bir saldırı olduğunu unutmayın.

logging.addLevelName(logging.INFO, "{}{}{}".format(TerminalColour.WHITE, logging.getLevelName(logging.INFO), TerminalColour.GREY))
logging.addLevelName(logging.WARNING, "{}{}{}".format(TerminalColour.YELLOW, logging.getLevelName(logging.WARNING), TerminalColour.GREY))
logging.addLevelName(logging.ERROR, "{}{}{}".format(TerminalColour.RED, logging.getLevelName(logging.ERROR), TerminalColour.GREY))
logging.addLevelName(logging.CRITICAL, "{}{}{}".format(TerminalColour.MAGENTA, logging.getLevelName(logging.CRITICAL), .GREY))

Günlük biçimlendiricinizin günlük düzeyinin adını içermesi gerektiğini unutmayın

%(levelname)

Örneğin:

    LOGGING = {
...
        'verbose': {
            'format': '%(asctime)s %(levelname)s %(name)s:%(lineno)s %(module)s %(process)d %(thread)d %(message)s'
        },
        'simple': {
            'format': '[%(asctime)s] %(levelname)s %(name)s %(message)s'
        },

1

FriendlyLog başka bir alternatiftir. Linux, Windows ve MacOS altında Python 2 & 3 ile çalışır.


Modül yolu karmaşasını azaltmak için yeni PR'yi bekliyorum
mbspark

1

Seviyeye göre renklendirmeye ek olarak alternatif mesajlarla günlük argümanlarını vurgulamaya ne dersiniz? Son zamanlarda bunun için basit bir kod yazdım. Diğer bir avantajı da günlük aramasının Python 3 destek stili biçimlendirmeyle yapılmasıdır. ( "{}").

En son kodu ve örnekleri burada bulabilirsiniz: https://github.com/davidohana/colargulog

Örnek Kayıt Kodu:

root_logger = logging.getLogger()
console_handler = logging.StreamHandler(stream=sys.stdout)
console_format = "%(asctime)s - %(levelname)-8s - %(name)-25s - %(message)s"
colored_formatter = ColorizedArgsFormatter(console_format)
console_handler.setFormatter(colored_formatter)
root_logger.addHandler(console_handler)

logger = logging.getLogger(__name__)
logger.info("Hello World")
logger.info("Request from {} handled in {:.3f} ms", socket.gethostname(), 11)
logger.info("Request from {} handled in {:.3f} ms", "127.0.0.1", 33.1)
logger.info("My favorite drinks are {}, {}, {}, {}", "milk", "wine", "tea", "beer")
logger.debug("this is a {} message", logging.getLevelName(logging.DEBUG))
logger.info("this is a {} message", logging.getLevelName(logging.INFO))
logger.warning("this is a {} message", logging.getLevelName(logging.WARNING))
logger.error("this is a {} message", logging.getLevelName(logging.ERROR))
logger.critical("this is a {} message", logging.getLevelName(logging.CRITICAL))
logger.info("Does old-style formatting also work? %s it is, but no colors (yet)", True)

Çıktı:

resim açıklamasını buraya girin

Uygulama:

"""
colargulog - Python3 Logging with Colored Arguments and new string formatting style

Written by david.ohana@ibm.com
License: Apache-2.0
"""

import logging
import logging.handlers
import re


class ColorCodes:
    grey = "\x1b[38;21m"
    green = "\x1b[1;32m"
    yellow = "\x1b[33;21m"
    red = "\x1b[31;21m"
    bold_red = "\x1b[31;1m"
    blue = "\x1b[1;34m"
    light_blue = "\x1b[1;36m"
    purple = "\x1b[1;35m"
    reset = "\x1b[0m"


class ColorizedArgsFormatter(logging.Formatter):
    arg_colors = [ColorCodes.purple, ColorCodes.light_blue]
    level_fields = ["levelname", "levelno"]
    level_to_color = {
        logging.DEBUG: ColorCodes.grey,
        logging.INFO: ColorCodes.green,
        logging.WARNING: ColorCodes.yellow,
        logging.ERROR: ColorCodes.red,
        logging.CRITICAL: ColorCodes.bold_red,
    }

    def __init__(self, fmt: str):
        super().__init__()
        self.level_to_formatter = {}

        def add_color_format(level: int):
            color = ColorizedArgsFormatter.level_to_color[level]
            _format = fmt
            for fld in ColorizedArgsFormatter.level_fields:
                search = "(%\(" + fld + "\).*?s)"
                _format = re.sub(search, f"{color}\\1{ColorCodes.reset}", _format)
            formatter = logging.Formatter(_format)
            self.level_to_formatter[level] = formatter

        add_color_format(logging.DEBUG)
        add_color_format(logging.INFO)
        add_color_format(logging.WARNING)
        add_color_format(logging.ERROR)
        add_color_format(logging.CRITICAL)

    @staticmethod
    def rewrite_record(record: logging.LogRecord):
        if not BraceFormatStyleFormatter.is_brace_format_style(record):
            return

        msg = record.msg
        msg = msg.replace("{", "_{{")
        msg = msg.replace("}", "_}}")
        placeholder_count = 0
        # add ANSI escape code for next alternating color before each formatting parameter
        # and reset color after it.
        while True:
            if "_{{" not in msg:
                break
            color_index = placeholder_count % len(ColorizedArgsFormatter.arg_colors)
            color = ColorizedArgsFormatter.arg_colors[color_index]
            msg = msg.replace("_{{", color + "{", 1)
            msg = msg.replace("_}}", "}" + ColorCodes.reset, 1)
            placeholder_count += 1

        record.msg = msg.format(*record.args)
        record.args = []

    def format(self, record):
        orig_msg = record.msg
        orig_args = record.args
        formatter = self.level_to_formatter.get(record.levelno)
        self.rewrite_record(record)
        formatted = formatter.format(record)

        # restore log record to original state for other handlers
        record.msg = orig_msg
        record.args = orig_args
        return formatted


class BraceFormatStyleFormatter(logging.Formatter):
    def __init__(self, fmt: str):
        super().__init__()
        self.formatter = logging.Formatter(fmt)

    @staticmethod
    def is_brace_format_style(record: logging.LogRecord):
        if len(record.args) == 0:
            return False

        msg = record.msg
        if '%' in msg:
            return False

        count_of_start_param = msg.count("{")
        count_of_end_param = msg.count("}")

        if count_of_start_param != count_of_end_param:
            return False

        if count_of_start_param != len(record.args):
            return False

        return True

    @staticmethod
    def rewrite_record(record: logging.LogRecord):
        if not BraceFormatStyleFormatter.is_brace_format_style(record):
            return

        record.msg = record.msg.format(*record.args)
        record.args = []

    def format(self, record):
        orig_msg = record.msg
        orig_args = record.args
        self.rewrite_record(record)
        formatted = self.formatter.format(record)

        # restore log record to original state for other handlers
        record.msg = orig_msg
        record.args = orig_args
        return formatted

0

Pyfancy kullanın .

Misal:

print(pyfancy.RED + "Hello Red!" + pyfancy.END)

Soru, loggingayrı bir renklendirme kütüphanesi kullanma işlevini değiştirmekti.
Enfekte Drake

0

ZetaSyanthis'in renkleriyle sadece başka bir çözüm:

def config_log(log_level):

    def set_color(level, code):
        level_fmt = "\033[1;" + str(code) + "m%s\033[1;0m" 
        logging.addLevelName( level, level_fmt % logging.getLevelName(level) )

    std_stream = sys.stdout
    isatty = getattr(std_stream, 'isatty', None)
    if isatty and isatty():
        levels = [logging.DEBUG, logging.CRITICAL, logging.WARNING, logging.ERROR]
        for idx, level in enumerate(levels):
            set_color(level, 30 + idx )
        set_color(logging.DEBUG, 0)
    logging.basicConfig(stream=std_stream, level=log_level)

__main__fonksiyonunuzdan bir kez çağırın . Orada böyle bir şey var:

options, arguments = p.parse_args()
log_level = logging.DEBUG if options.verbose else logging.WARNING
config_log(log_level)

ayrıca çıktının bir konsol olduğunu doğrular, aksi takdirde renk kullanılmaz.


0
import logging

logging.basicConfig(filename="f.log" filemode='w', level=logging.INFO,
                    format = "%(logger_name)s %(color)s  %(message)s %(endColor)s")


class Logger(object):
    __GREEN = "\033[92m"
    __RED = '\033[91m'
    __ENDC = '\033[0m'

    def __init__(self, name):
        self.logger = logging.getLogger(name)
        self.extra={'logger_name': name, 'endColor': self.__ENDC, 'color': self.__GREEN}


    def info(self, msg):
        self.extra['color'] = self.__GREEN
        self.logger.info(msg, extra=self.extra)

    def error(self, msg):
        self.extra['color'] = self.__RED
        self.logger.error(msg, extra=self.extra)

kullanım

Logger("File Name").info("This shows green text")


Konsol için dosya adını dışarıda bırakabilir veya sadece dosyaadı = '' çalışmalıdır. basicConfig'i dosya numarası, modül gibi diğer özellikleri içerecek şekilde değiştirin ..
estifanos gebrehiwot

0

Aşağıdaki çözüm sadece python 3 ile çalışır, ancak benim için en açık görünüyor.

Fikir, kayıt nesnelerine 'renkli' özellikler eklemek için günlük kaydı fabrikasını kullanmak ve bu 'renkli' nitelikleri günlük biçiminde kullanmaktır.

import logging
logger = logging.getLogger(__name__)

def configure_logging(level):

    # add 'levelname_c' attribute to log resords
    orig_record_factory = logging.getLogRecordFactory()
    log_colors = {
        logging.DEBUG:     "\033[1;34m",  # blue
        logging.INFO:      "\033[1;32m",  # green
        logging.WARNING:   "\033[1;35m",  # magenta
        logging.ERROR:     "\033[1;31m",  # red
        logging.CRITICAL:  "\033[1;41m",  # red reverted
    }
    def record_factory(*args, **kwargs):
        record = orig_record_factory(*args, **kwargs)
        record.levelname_c = "{}{}{}".format(
            log_colors[record.levelno], record.levelname, "\033[0m")
        return record

    logging.setLogRecordFactory(record_factory)

    # now each log record object would contain 'levelname_c' attribute
    # and you can use this attribute when configuring logging using your favorite
    # method.
    # for demo purposes I configure stderr log right here

    formatter_c = logging.Formatter("[%(asctime)s] %(levelname_c)s:%(name)s:%(message)s")

    stderr_handler = logging.StreamHandler()
    stderr_handler.setLevel(level)
    stderr_handler.setFormatter(formatter_c)

    root_logger = logging.getLogger('')
    root_logger.setLevel(logging.DEBUG)
    root_logger.addHandler(stderr_handler)


def main():
    configure_logging(logging.DEBUG)

    logger.debug("debug message")
    logger.info("info message")
    logger.critical("something unusual happened")


if __name__ == '__main__':
    main()

Diğer renkli nitelikleri (fe message_c) oluşturmak için bu örneği kolayca değiştirebilir ve daha sonra istediğiniz yere renkli metin almak için bu nitelikleri kullanabilirsiniz.

(son zamanlarda keşfettim kullanışlı hile: Renkli hata ayıklama günlükleri ile bir dosya var ve ne zaman geçici benim uygulama günlük düzeyini artırmak istediğinizde Ben sadece tail -ffarklı terminalde günlük dosyası ve herhangi bir yapılandırma değiştirme ve yeniden uygulama w / o ekranda hata ayıklama günlükleri görmek )


0

Bu, airmind örneğinin bir başka Python3 varyantıdır. Diğer örneklerde görmediğim bazı özellikler istedim

  • terminal için renkler kullanın, ancak dosya işleyicilerine yazdırılamayan karakterler yazmayın (bunun için 2 biçimlendirici tanımladım)
  • belirli bir günlük iletisinin rengini geçersiz kılma yeteneği
  • günlükçüyü bir dosyadan yapılandırın (bu durumda yaml)

Notlar: Colorama kullandım ama bunu değiştirebilirsin, bu yüzden gerekli değil. Ayrıca test için sadece python dosyası çalıştırıyordum, bu yüzden sınıfım modülde . Modülünüz ne olursa olsun __main__değiştirmeniz (): __main__.ColoredFormattergerekir.

pip install colorama pyyaml

logging.yaml

---
version: 1
disable_existing_loggers: False
formatters:
  simple:
    format: "%(threadName)s - %(name)s - %(levelname)s - %(message)s"
  color:
    format: "%(threadName)s - %(name)s - %(levelname)s - %(message)s"
    (): __main__.ColoredFormatter
    use_color: true

handlers:
  console:
    class: logging.StreamHandler
    level: DEBUG
    formatter: color
    stream: ext://sys.stdout

  info_file_handler:
    class: logging.handlers.RotatingFileHandler
    level: INFO
    formatter: simple
    filename: app.log
    maxBytes: 20971520 
    backupCount: 20
    encoding: utf8

  error_file_handler:
    class: logging.handlers.RotatingFileHandler
    level: ERROR
    formatter: simple
    filename: errors.log
    maxBytes: 10485760 
    backupCount: 20
    encoding: utf8

root:
  level: DEBUG
  handlers: [console, info_file_handler, error_file_handler]

main.py

import logging
import logging.config
import os
from logging import Logger

import colorama
import yaml
from colorama import Back, Fore, Style

COLORS = {
    "WARNING": Fore.YELLOW,
    "INFO": Fore.CYAN,
    "DEBUG": Fore.BLUE,
    "CRITICAL": Fore.YELLOW,
    "ERROR": Fore.RED,
}


class ColoredFormatter(logging.Formatter):
    def __init__(self, *, format, use_color):
        logging.Formatter.__init__(self, fmt=format)
        self.use_color = use_color

    def format(self, record):
        msg = super().format(record)
        if self.use_color:
            levelname = record.levelname
            if hasattr(record, "color"):
                return f"{record.color}{msg}{Style.RESET_ALL}"
            if levelname in COLORS:
                return f"{COLORS[levelname]}{msg}{Style.RESET_ALL}"
        return msg


with open("logging.yaml", "rt") as f:
    config = yaml.safe_load(f.read())
    logging.config.dictConfig(config)

logger: Logger = logging.getLogger(__name__)
logger.info("Test INFO", extra={"color": Back.RED})
logger.info("Test INFO", extra={"color": f"{Style.BRIGHT}{Back.RED}"})
logger.info("Test INFO")
logger.debug("Test DEBUG")
logger.warning("Test WARN")

çıktı:

çıktı

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.