python - मैं पायथन लॉगिंग आउटपुट कैसे रंग सकता हूं?




logging colors (21)

यहां एक समाधान है जो किसी भी मंच पर काम करना चाहिए। अगर यह सिर्फ मुझे नहीं बताता है और मैं इसे अपडेट कर दूंगा।

यह कैसे काम करता है: एएनएसआई एस्केप का समर्थन करने वाले मंच पर उनका उपयोग (गैर-विंडोज) और विंडोज़ पर कंसोल रंग बदलने के लिए एपीआई कॉल का उपयोग करता है।

स्क्रिप्ट लॉगिंग हैक करता है। मानक लाइब्रेरी से StreamHandler.emit विधि इसे एक रैपर जोड़ती है।

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())

कुछ समय पहले, मैंने रंगीन आउटपुट के साथ एक मोनो एप्लिकेशन देखा, संभवतः इसकी लॉग सिस्टम की वजह से (क्योंकि सभी संदेशों को मानकीकृत किया गया था)।

अब, पायथन में logging मॉड्यूल है, जो आपको आउटपुट को अनुकूलित करने के लिए कई विकल्प निर्दिष्ट करने देता है। तो, मैं कल्पना कर रहा हूं कि पाइथन के साथ ऐसा कुछ भी संभव होगा, लेकिन मुझे यह नहीं पता कि यह कहीं भी कैसे किया जाए।

पाइथन logging मॉड्यूल आउटपुट रंग में बनाने का कोई तरीका है?

मैं क्या चाहता हूं (उदाहरण के लिए) लाल रंग में त्रुटियां, नीले या पीले रंग में संदेशों को डीबग करें, और इसी तरह।

बेशक यह शायद एक संगत टर्मिनल (सबसे आधुनिक टर्मिनलों) की आवश्यकता होगी; लेकिन यदि रंग समर्थित नहीं है तो मैं मूल logging आउटपुट पर फ़ॉलबैक कर सकता हूं।

कोई विचार है कि मैं लॉगिंग मॉड्यूल के साथ रंगीन आउटपुट कैसे प्राप्त कर सकता हूं?


बहुत सारे जवाब हैं। लेकिन सजावट करने वालों के बारे में कोई बात नहीं कर रहा है। तो यहाँ मेरा है।

क्योंकि यह बहुत आसान है।

कुछ भी आयात करने की आवश्यकता नहीं है, न ही कोई सबक्लास लिखना है:

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

यह लाल रंग में त्रुटियों को सेट करता है, नीले रंग में संदेशों को डीबग करता है, और इसी तरह। सवाल में पूछे जाने की तरह।

हम logger.debug("message", color=GREY) का उपयोग करके संदेश के रंग को गतिशीलता के लिए color तर्क लेने के लिए रैपर को भी अनुकूलित कर सकते हैं।

संपादित करें: तो यहां रनटाइम पर रंग सेट करने के लिए अनुकूलित सजावटकर्ता है:

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)

Use pyfancy .

उदाहरण:

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

अपडेट करें : क्योंकि यह एक खुजली है कि मैं इतने लंबे समय तक खरोंच करने का मतलब रहा हूं, मैं आगे बढ़ गया और मेरे जैसे आलसी लोगों के लिए एक लाइब्रेरी लिखी जो सिर्फ चीजों को करने के सरल तरीके चाहते हैं: zenlog

Colorlog इसके लिए उत्कृष्ट है। यह पीईपीआई (और इस प्रकार pip install colorlog माध्यम से pip install colorlog ) पर उपलब्ध है और सक्रिय रूप से बनाए रखा जाता है

लॉगिंग सेट अप करने और सभ्य दिखने वाले लॉग संदेशों को मुद्रित करने के लिए यहां एक त्वरित प्रति-और-पेस्टेबल स्निपेट है:

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")

आउटपुट:


Well, I guess I might as well add my variation of the colored logger.

This is nothing fancy, but it is very simple to use and does not change the record object, thereby avoids logging the ANSI escape sequences to a log file if a file handler is used. It does not effect the log message formatting.

If you are already using the logging module's Formatter , all you have to do to get colored level names is to replace your counsel handlers Formatter with the ColoredFormatter. If you are logging an entire app you only need to do this for the top level logger.

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)

उदाहरण उपयोग

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")

परिणाम

Terminal output

app.log content

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 - ERROR - Hello from the sub module

Of course you can get as fancy as you want with formatting the terminal and log file outputs. Only the log level will be colorized.

I hope somebody finds this useful and it is not just too much more of the same. :)

The Python example files can be downloaded from this GitHub Gist: https://gist.github.com/KurtJacobson/48e750701acec40c7161b5a2f79e6bfd


आप कलरॉग मॉड्यूल आयात कर सकते हैं और लॉग संदेशों को ColoredFormatter देने के लिए अपने ColoredFormatter उपयोग कर सकते हैं।

उदाहरण

मुख्य मॉड्यूल के लिए बॉयलरप्लेट:

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__)

कोड केवल लॉग संदेशों में रंग सक्षम करता है, अगर कलरॉग मॉड्यूल स्थापित है और आउटपुट वास्तव में टर्मिनल पर जाता है। यह लॉग आउटपुट रीडायरेक्ट होने पर फ़ाइल में लिखे जाने वाले एस्केप अनुक्रमों से बचाता है।

साथ ही, एक कस्टम रंग योजना सेटअप है जो अंधेरे पृष्ठभूमि वाले टर्मिनलों के लिए बेहतर अनुकूल है।

कुछ उदाहरण लॉगिंग कॉल:

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

आउटपुट:


मेरे पास जोड़ने के लिए दो सबमिशन हैं, जिनमें से एक केवल संदेश (रंगीनफॉर्मेटर) को रंगता है, और इनमें से एक पूरी लाइन को रंग देता है (ColorizingStreamHandler)। इनमें पिछले समाधानों की तुलना में अधिक एएनएसआई रंग कोड भी शामिल हैं।

कुछ सामग्री को (संशोधन के साथ) से ऊपर दिया गया है: उपरोक्त पोस्ट, और http://plumberjack.blogspot.com/2010/12/colorizing-logging-output-in-terminals.html

केवल संदेश को रंगीन करता है:

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

Colorizes the whole line:

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

सालों पहले मैंने अपने इस्तेमाल के लिए एक रंगीन धारा हैंडलर लिखा था। तब मैं इस पृष्ठ पर आया और कोड स्निपेट का संग्रह पाया कि लोग कॉपी / पेस्ट कर रहे हैं :-(। मेरा स्ट्रीम हैंडलर वर्तमान में केवल यूनिक्स (लिनक्स, मैक ओएस एक्स) पर काम करता है लेकिन इसका फायदा यह है कि यह पीपीपीआई (और गिटहब ) पर उपलब्ध GitHub ) और यह उपयोग करने में आसान है। इसमें एक विम सिंटैक्स मोड भी है :-)। भविष्य में मैं इसे विंडोज़ पर काम करने के लिए बढ़ा सकता हूं।

पैकेज स्थापित करने के लिए:

$ pip install coloredlogs

यह पुष्टि करने के लिए कि यह काम करता है:

$ coloredlogs --demo

अपने कोड से शुरू करने के लिए:

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

उपर्युक्त उदाहरण में दिखाए गए डिफ़ॉल्ट लॉग प्रारूप में दिनांक, समय, होस्टनाम, लॉगर का नाम, पीआईडी, लॉग स्तर और लॉग संदेश शामिल है। अभ्यास में ऐसा लगता है:


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)))`

निम्नलिखित समाधान को देखो। स्ट्रीम हैंडलर रंग कर रही चीज होनी चाहिए, तो आपके पास केवल पूरी लाइन (फॉर्मेटर के साथ) के बजाय रंगों का रंग होना चाहिए।

http://plumberjack.blogspot.com/2010/12/colorizing-logging-output-in-terminals.html


पूर्वनिर्धारित लॉग स्तर के लिए और एक नई कक्षा को परिभाषित किए बिना त्वरित और गंदे समाधान।

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

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)

प्रयोग

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


अब अनुकूलन रंगीन लॉगिंग आउटपुट के लिए एक जारी पीपीआई मॉड्यूल है:

https://pypi.python.org/pypi/rainbow_logging_handler/

तथा

https://github.com/laysakura/rainbow_logging_handler

  • विंडोज का समर्थन करता है

  • Django का समर्थन करता है

  • अनुकूलन रंग

चूंकि इसे पाइथन अंडे के रूप में वितरित किया जाता है, इसलिए किसी भी पायथन एप्लिकेशन के लिए इंस्टॉल करना बहुत आसान है।


मैंने अग्रभूमि और पृष्ठभूमि के लिए टैग का समर्थन करने वाले एयरमाइंड से उदाहरण अपडेट किया। अपने लॉग फॉर्मेटर स्ट्रिंग में रंग वैरिएबल $ Black - $ WHITE का उपयोग करें। पृष्ठभूमि सेट करने के लिए बस $ बीजी-ब्लैक - $ बीजी-व्हाइट का उपयोग करें।

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

तो अब आप अपनी कॉन्फ़िगरेशन फ़ाइल में निम्नलिखित सरल कर सकते हैं:

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

मैंने सोरिन और उपclassed StreamHandler द्वारा प्रदान किए गए मूल उदाहरण को एक रंगीन कंसोल हैंडलर में संशोधित किया।

उनके समाधान का नकारात्मक पक्ष यह है कि यह संदेश को संशोधित करता है, और क्योंकि यह वास्तविक लॉगमेसेज को संशोधित कर रहा है क्योंकि किसी भी अन्य हैंडलर को संशोधित संदेश भी मिल जाएगा।

इसके परिणामस्वरूप हमारे मामले में उनमें रंगीन कोड के साथ लॉगफाइल होते हैं क्योंकि हम एकाधिक लॉगर्स का उपयोग करते हैं।

नीचे दी गई कक्षा केवल प्लेटफ़ॉर्म पर काम करती है जो ansi का समर्थन करती हैं, लेकिन इसमें विंडोज़ रंग कोड जोड़ने के लिए यह छोटा होना चाहिए।

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)

एयरमाइंड के दृष्टिकोण का एक और मामूली रीमिक्स जो सब कुछ एक वर्ग में रखता है:

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)

एक हैंडलर को फ़ॉर्मेटर संलग्न करने के लिए, कुछ ऐसा:

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

This is an Enum containing the colour codes:

class TerminalColour:
    """
    Terminal colour formatting codes
    """
    # https://.com/questions/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'

This may be applied to the names of each log level. Be aware that this is a monstrous hack.

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

Note that your log formatter must include the name of the log level

%(levelname)

उदाहरण के लिए:

    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'
        },

किसी भी टर्मिनल पाठ को रंगने के लिए एक सरल लेकिन बहुत लचीला उपकरण ' colout ' है।

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

जहां 'myprocess' के आउटपुट में कोई भी टेक्स्ट जो रेगेक्स के समूह 1 से मेल खाता है, रंग 1, रंग 2 के साथ समूह 2 के साथ रंगीन होगा।

उदाहरण के लिए:

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

यानी पहला रेगेक्स समूह (अभिभावक) लॉगफाइल में प्रारंभिक तारीख से मेल खाता है, दूसरा समूह एक पायथन फ़ाइल नाम, लाइन नंबर और फ़ंक्शन नाम से मेल खाता है, और तीसरा समूह उसके बाद आने वाले लॉग संदेश से मेल खाता है। मैं 'बोल्ड / मानक' के साथ-साथ रंगों के अनुक्रम के समांतर अनुक्रम का भी उपयोग करता हूं। ऐसा लगता है:

ध्यान दें कि रेखाओं या रेखाओं के कुछ भाग जो मेरे किसी भी रेगेक्स से मेल नहीं खाते हैं, अभी भी प्रतिबिंबित हैं, इसलिए यह 'grep --color' जैसा नहीं है - आउटपुट से कुछ भी फ़िल्टर नहीं किया गया है।

जाहिर है यह इतना लचीला है कि आप इसे किसी भी प्रक्रिया के साथ उपयोग कर सकते हैं, न केवल लॉगफाइल को पूंछ। मैं आमतौर पर फ्लाई पर एक नया रेगेक्स चाबुक करता हूं जब भी मैं कुछ रंगीन करना चाहता हूं। इस कारण से, मैं किसी भी कस्टम लॉगफाइल-रंग उपकरण के लिए कोलाउट पसंद करता हूं, क्योंकि मुझे केवल एक उपकरण सीखने की आवश्यकता है, चाहे मैं रंग दे रहा हूं: लॉगिंग, परीक्षण आउटपुट, टर्मिनल में कोड के स्निपेट को हाइलाइट करना सिंटैक्स इत्यादि।

यह वास्तव में लॉगफाइल में एएनएसआई कोड को डंप करने से बचाता है, जो आईएमएचओ एक बुरा विचार है, क्योंकि यह लॉगफाइल में पैटर्न के लिए grepping जैसी चीज़ें तोड़ देगा जब तक कि आप हमेशा अपने grep regex में एएनएसआई कोड से मेल नहीं खाते।


मेरा समाधान यहाँ है:

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])

जबकि अन्य समाधान ठीक लगते हैं, उनके पास कुछ समस्याएं हैं। कुछ लोग पूरी लाइनों को रंग देते हैं जो कुछ बार नहीं चाहते थे और कुछ किसी भी कॉन्फ़िगरेशन को छोड़ देते हैं जो आपके पास हो सकता है। नीचे दिया गया समाधान संदेश को स्वयं ही कुछ भी प्रभावित नहीं करता है।

कोड

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)

उदाहरण

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

उत्पादन

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

जैसा कि आप देखते हैं, बाकी सब कुछ अभी भी आउटपुट हो जाता है और उनके शुरुआती रंग में रहता है। अगर आप संदेश से कुछ और बदलना चाहते हैं तो आप उदाहरण में log_format रंग कोड पास कर सकते हैं।


हालांकि मैं हमेशा उपयोग tryऔर exceptबयानों की अनुशंसा करता हूं , यहां आपके लिए कुछ संभावनाएं हैं (मेरा निजी पसंदीदा उपयोग कर रहा है os.access):

  1. फ़ाइल खोलने का प्रयास करें:

    फ़ाइल खोलना हमेशा फ़ाइल के अस्तित्व को सत्यापित करेगा। आप इस तरह एक समारोह कर सकते हैं:

    def File_Existence(filepath):
        f = open(filepath)
        return True
    

    यदि यह गलत है, तो यह पाइथन के बाद के संस्करणों में एक अनचाहे IOError या OSError के साथ निष्पादन को रोक देगा। अपवाद को पकड़ने के लिए, आपको खंड को छोड़कर एक प्रयास का उपयोग करना होगा। बेशक, आप हमेशा एक का उपयोग कर सकते tryexcept` बयान इसलिए की तरह (धन्यवाद करने के लिए hsandt मुझे लगता है कि बनाने के लिए):

    def File_Existence(filepath):
        try:
            f = open(filepath)
        except IOError, OSError: # Note OSError is for later versions of Python
            return False
    
        return True
    
  2. उपयोग करें os.path.exists(path):

    यह आपके द्वारा निर्दिष्ट किए गए विवरण के अस्तित्व की जांच करेगा। हालांकि, यह फ़ाइलों और निर्देशिकाओं के लिए जांच करता है इसलिए आप इसका उपयोग कैसे करें इसके बारे में सावधान रहें।

    import os.path
    >>> os.path.exists("this/is/a/directory")
    True
    >>> os.path.exists("this/is/a/file.txt")
    True
    >>> os.path.exists("not/a/directory")
    False
    
  3. उपयोग करें os.access(path, mode):

    यह जांच करेगा कि क्या आपके पास फ़ाइल तक पहुंच है या नहीं। यह अनुमतियों की जांच करेगा। Os.py दस्तावेज़ के आधार पर, टाइपिंग os.F_OK, यह पथ के अस्तित्व की जांच करेगा। हालांकि, इसका उपयोग एक सुरक्षा छेद बनाएगा, क्योंकि कोई भी अनुमतियों की जांच करने और फ़ाइल खोलने के बीच समय का उपयोग करके आपकी फ़ाइल पर हमला कर सकता है। इसके बजाय आपको इसकी अनुमतियों की जांच करने के बजाय फ़ाइल खोलने के लिए सीधे जाना चाहिए। ( EAFP बनाम LBYP )। यदि आप फ़ाइल को बाद में खोलने वाले नहीं हैं, और केवल इसके अस्तित्व की जांच कर रहे हैं, तो आप इसका उपयोग कर सकते हैं।

    वैसे भी, यहां:

    >>> import os
    >>> os.access("/is/a/file.txt", os.F_OK)
    True
    

मुझे यह भी जिक्र करना चाहिए कि दो तरीके हैं कि आप फ़ाइल के अस्तित्व को सत्यापित करने में सक्षम नहीं होंगे। या तो मुद्दा होगा permission deniedया no such file or directory। यदि आप एक पकड़ते हैं IOError, तो IOError as e(मेरे पहले विकल्प की तरह) सेट करें , और फिर टाइप करें print(e.args)ताकि आप उम्मीद कर सकें कि आप अपनी समस्या का निर्धारण कर सकते हैं। मुझे उम्मीद है यह मदद करेगा! :)





python logging colors