Làm thế nào tôi có thể tô màu đầu ra đăng nhập Python?


352

Cách đây một thời gian, tôi thấy một ứng dụng Mono có đầu ra màu, có lẽ là do hệ thống nhật ký của nó (vì tất cả các thông báo đã được chuẩn hóa).

Bây giờ, Python có loggingmô-đun, cho phép bạn chỉ định rất nhiều tùy chọn để tùy chỉnh đầu ra. Vì vậy, tôi đang tưởng tượng điều gì đó tương tự sẽ có thể xảy ra với Python, nhưng tôi không thể tìm ra cách làm điều này ở bất cứ đâu.

Có cách nào để làm cho loggingđầu ra mô-đun Python có màu không?

Những gì tôi muốn (ví dụ) lỗi màu đỏ, thông báo gỡ lỗi màu xanh hoặc màu vàng, v.v.

Tất nhiên điều này có thể sẽ yêu cầu một thiết bị đầu cuối tương thích (hầu hết các thiết bị đầu cuối hiện đại); nhưng tôi có thể quay lại đầu loggingra ban đầu nếu màu không được hỗ trợ.

Bất kỳ ý tưởng làm thế nào tôi có thể nhận được đầu ra màu với mô-đun đăng nhập?


1
Bạn nên xác định rằng bạn muốn một giải pháp đa nền tảng - cả Linux và Windows.
sorin

1
Liên quan nếu bạn sử dụng Eclipse / PyDev: Tô màu các bản ghi trong bảng điều khiển nhật thực
Tobias Kienzler

5
Có lẽ bạn cũng có thể sử dụng colorlog
Ehtesh Choudhury

5
Bạn cũng có thể dùng thử chromalog mà tôi đã viết để hỗ trợ tất cả các hệ điều hành và phiên bản Python (2.7 và 3. *)
vào

1
Các giải pháp thực sự kết xuất mã ANSI trong logfile là một ý tưởng tồi, chúng sẽ đuổi bạn ra khi bạn đang chuẩn bị một cái gì đó trong sáu tháng nhưng quên không cho phép ký tự ANSI trong mẫu biểu thức chính quy của bạn. Có một số giải pháp bên dưới sẽ thêm màu khi bạn xem nhật ký, thay vì ghi nhật ký ...
Jonathan Hartley

Câu trả lời:


192

Tôi đã biết về các màu thoát, tôi đã sử dụng chúng trong dấu nhắc bash của tôi một lúc trước. Dù sao cũng cảm ơn bạn.
Những gì tôi muốn là tích hợp nó với mô-đun đăng nhập, điều mà cuối cùng tôi đã làm sau một vài lần thử và lỗi.
Đây là những gì tôi kết thúc với:

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)

Và để sử dụng nó, hãy tạo Logger của riêng bạn:

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

Chỉ trong trường hợp bất cứ ai khác cần nó.

Hãy cẩn thận nếu bạn đang sử dụng nhiều hơn một logger hoặc trình xử lý: ColoredFormatterđang thay đổi đối tượng bản ghi, được truyền tiếp cho các trình xử lý khác hoặc truyền sang các logger khác. Nếu bạn đã cấu hình bộ ghi tệp, v.v. có lẽ bạn không muốn có màu trong tệp nhật ký. Để tránh điều đó, tốt nhất là chỉ cần tạo một bản sao recordvới copy.copy()trước khi thao tác thuộc tính levelname hoặc đặt lại tên cấp độ về giá trị trước đó, trước khi trả lại chuỗi được định dạng (ghi có cho Michael trong các nhận xét).


Ở đâu là VÀNG, TRẮNG, XANH, v.v.
Swaroop CH

1
@Swaroop - Đó là các mã thoát ANSI, bạn có thể đọc tra cứu trên Google hoặc tìm tại đây: en.wikipedia.org/wiki/ANSI_escape_code hoặc thay thế pueblo.sourceforge.net/doc/manual/ansi_color_codes.html
Brian M Săn

53
Tôi không tin rằng bạn nên tạo một lớp con logger chỉ cho việc này - câu trả lời của bạn là tốt cho đến khi tạo ra một chuyên ngành Formattervà chỉ định sử dụng nó trên a StreamHandler. Nhưng không cần một lớp con logger. Trong thực tế, việc sử dụng một lớp logger thêm một trình xử lý cho mỗi logger được tạo, đó không phải là điều bạn thường muốn.
Vinay Sajip


6
Một bên lưu ý đến ColoredFormatter. Nó đang thay đổi đối tượng bản ghi, được truyền tiếp cho các trình xử lý khác hoặc được truyền tới các logger khác. Nếu bạn đã cấu hình bộ ghi tệp, v.v. có lẽ bạn không muốn có màu trong tệp nhật ký. Để tránh điều đó, có lẽ tốt nhất là chỉ cần tạo một bản sao recordvới copy.copy()trước khi thao tác thuộc tính levelname hoặc đặt lại tên cấp độ về giá trị trước đó, trước khi trả về chuỗi được định dạng.
Michael

148

Nhiều năm trước tôi đã viết một trình xử lý dòng màu cho việc sử dụng của riêng tôi. Sau đó, tôi đã xem qua trang này và tìm thấy một tập hợp các đoạn mã mà mọi người đang sao chép / dán :-(. Trình xử lý luồng của tôi hiện chỉ hoạt động trên UNIX (Linux, Mac OS X) nhưng ưu điểm là nó có sẵn trên PyPI (và GitHub ) và nó rất đơn giản để sử dụng. Nó cũng có chế độ cú pháp Vim :-). Trong tương lai tôi có thể mở rộng nó để hoạt động trên Windows.

Để cài đặt gói:

$ pip install coloredlogs

Để xác nhận rằng nó hoạt động:

$ coloredlogs --demo

Để bắt đầu với mã của riêng bạn:

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

Định dạng nhật ký mặc định được hiển thị trong ví dụ trên chứa ngày, thời gian, tên máy chủ, tên của trình ghi nhật ký, PID, mức nhật ký và thông điệp tường trình. Đây là những gì nó trông giống như trong thực tế:

Ảnh chụp màn hình của đầu ra colorlog

LƯU Ý: Khi sử dụng Git Bash w / MinTTY

Git Bash trên windows có một số quirks được ghi lại: Winpty và Git Bash

Mà đối với mã thoát ANSI và viết lại và ký tự kiểu ký tự kiểu ncurses, bạn cần phải thêm tiền tố vào lệnh winpty.

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

2
đủ buồn cười, tôi chỉ cần thêm một liên kết đến " pypi.python.org/pypi/coloredlogs/0.4.7 " trong chủ đề này!
Iosu S.

1
Vì một số lý do tôi tiếp tục nhận được AttributeError: 'module' object has no attribute 'install'khi sử dụng coloredlogs.install(). Bạn có thể xác nhận rằng với phiên bản mới nhất.
con-f-use

11
Cái này nhìn đẹp quá. Thật không may, nó phá vỡ nhiều thứ; đặc biệt, nó sẽ gọi các cuộc gọi đến log.basicConfig. Điều này làm cho nó không thể sử dụng một trình định dạng tùy chỉnh, ví dụ.
Clément

@ Clément: Hai câu hỏi (chồng chéo?): (1) Ý của bạn chính xác là gì bởi "các cuộc gọi voids đến log.basicConfig" và (2) thay thế sẽ là gì? Cả hai logging.basicConfig()coloredlogs.install()cài đặt một trình xử lý luồng ghi nhật ký vào bảng điều khiển, do đó, không "bỏ trống", bạn sẽ nhận được các tin nhắn trùng lặp ...
xolox

Tôi mong đợi một trong hai phép thuật cho (1), hoặc (hợp lý hơn) một cách để biết coloredlogs.installđịnh dạng nào sẽ sử dụng, như trong colorloggói.
Clément

74

Đây là một giải pháp nên hoạt động trên mọi nền tảng. Nếu nó không chỉ cho tôi biết và tôi sẽ cập nhật nó.

Cách thức hoạt động: trên nền tảng hỗ trợ thoát ANSI đang sử dụng chúng (không phải Windows) và trên Windows, nó sử dụng các lệnh gọi API để thay đổi màu của bảng điều khiển.

Kịch bản lệnh hack phương thức log.StreamHandler.emit từ thư viện chuẩn thêm một trình bao bọc cho nó.

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
Tôi đã viết một lớp StreamHandler dựa trên điều này, xem gist.github.com/mooware/a1ed40987b6cc9ab9c65 .
mooware

2
Điều này làm việc cho tôi! dòng 90: nên args[1].msg = color + str(args[1].msg) + '\x1b[0m' # normal.
Rasika Perera

Tôi thích giải pháp này. sử dụng nó hiện nay. Tôi thấy có một thuộc tính _set_color, có cách nào để làm điều này cho một thông điệp tường trình cụ thể không? chỉnh sửa , oh thấy đó chỉ là một bản vá cho máy windows. sẽ được tốt đẹp để thêm tùy chỉnh cho các trường hợp sử dụng khác nhau.
brizz

+1 cho màu ANSI. Trong xterm, bạn thậm chí có thể nhận được 256 màu cùng một lúc và bạn có thể xác định bảng màu một cách linh hoạt! Tuy nhiên, lưu ý rằng tất cả các lệnh gọi đến chức năng ghi nhật ký phải nằm trong định nghĩa hàm để tránh các sự cố khóa nhập tiềm ẩn khi đăng nhập bên ngoài định nghĩa hàm . Mã của bạn trông chủ yếu là tốt; chỉ cần một chút TestColorer.pyquan tâm đến tôi
Personal_cloud

Điều này dẫn đến mã màu ở đầu và cuối của thông điệp tường trình trong các tệp nhật ký thực tế.
MehmedB

74

Cập nhật : Bởi vì đây là một vết ngứa mà tôi đã có ý định gãi quá lâu, tôi đã đi trước và viết một thư viện cho những người lười biếng như tôi, những người chỉ muốn những cách đơn giản để làm mọi thứ: zenlog

Colorlog là tuyệt vời cho việc này. Nó có sẵn trên PyPI (và do đó có thể cài đặt thông qua pip install colorlog) và được duy trì tích cực .

Đây là đoạn trích sao chép và dán nhanh để thiết lập ghi nhật ký và in thông điệp nhật ký trông đẹp mắt:

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

Đầu ra:

Đầu ra Colorlog


4
Câu trả lời chính xác; +1. Ví dụ mã có thể được cắt bớt (ba cuộc gọi có setLevelthực sự cần thiết không?)
Clément

1
Tôi đã hy vọng tôi sẽ tìm thấy một câu trả lời như thế này nếu tôi lội qua các câu trả lời đủ lâu. Tôi hy vọng @airmind sẽ xem xét đưa ra câu trả lời được chấp nhận này, vì vậy những người làm việc thông minh trong tương lai có thể tìm thấy những gì dường như là thư viện tốt nhất với sự lười biếng tối ưu.
Michael Scheper

Tôi vừa nêu lên điều này cho các ví dụ về tin nhắn của OUTPUT ^^
Agustin Barrachina

69

Giải pháp nhanh và bẩn cho các mức nhật ký được xác định trước và không xác định một lớp mới.

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 nhập nhật ký; # dán mã từ @ABC; hãy thử với log.warning ('đây là một bài kiểm tra'). Bạn sẽ thấy phần chữ hoa của "CẢNH BÁO: đây là bài kiểm tra" được tô màu. Nó chỉ hoạt động trên linux btw
Riccardo Galli

3
Vì chỉ có tên loglevel được tô màu, bạn phải chắc chắn rằng tên loglevel được in lên bàn điều khiển. Điều này không xảy ra với tôi. Một cái gì đó dọc theo những dòng này sẽ giúp: logging.basicConfig(format='%(asctime)s [%(name)s] [%(levelname)s] %(message)s')Trường hợp tất nhiên %(levelnames)slà quan trọng.
Sebastian

4
Giải pháp đơn giản và sạch sẽ nhất để áp dụng và hiểu.
F. Santiago

1
Chỉ cần thử trong bảng điều khiển Linux. echo -e "Normal texst \033[1;31mred bold text\033[0m normal text again". -etùy chọn echo diễn giải "\ 033" dưới dạng bát phân của biểu tượng Escape ASCII. Biểu tượng đặc biệt này làm cho một số thiết bị đầu cuối tương thích diễn giải các ký tự tiếp theo ( mbao gồm char ) là các lệnh đặc biệt. vi.wikipedia.org/wiki/ANSI_escape_code
eugene-sáng

1
Cải thiện nhỏ: đặt mã này vào bên trong if sys.sdterr.isatty():. Trong trường hợp này nếu bạn chuyển hướng đầu ra thành tệp, tệp sẽ không chứa các ký tự thoát này.
lesnik

35

Mã 2020, không yêu cầu gói bổ sung, Python 3

Xác định một lớp học

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)

Ghi nhật 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)

Và sử dụng!

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

Kết quả nhập mô tả hình ảnh ở đây

Bảng màu đầy đủ nhập mô tả hình ảnh ở đây

Cho cửa sổ

Giải pháp này hoạt động trên Mac OS, thiết bị đầu cuối IDE. Có vẻ như dấu nhắc lệnh của window không có màu theo mặc định. Dưới đây là hướng dẫn cách bật chúng, mà tôi chưa thử https://www.howtogeek.com/322432/how-to-customize-your-command-prompts-color-scheme-with-microsofts-colortool/


1
Tôi chạy thử nghiệm (python 3.7, windows), nhưng đăng nhập không hiển thị màu:←[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
xây dựng

Điều này không làm việc không may.
Joe

2
Tôi thích câu trả lời này đến nỗi tôi đã thực hiện một repo cho nó, với một vài gia số và một bảng cheat màu ansi.
Teodoro

@constructor bạn chạy nó ở đâu? Bảng điều khiển IDE? thiết bị đầu cuối cửa sổ?
Serge Pleshakov

@Joe chính xác những gì không hoạt động? môi trường của bạn là gì và bạn có lỗi gì? Tôi muốn sửa đổi giải pháp để làm cho nó hoạt động trên các nền tảng
Serge Pleshakov

17

Chà, tôi đoán tôi cũng có thể thêm biến thể của logger màu.

Điều này không có gì lạ mắt, nhưng nó rất đơn giản để sử dụng và không thay đổi đối tượng bản ghi, do đó tránh ghi nhật ký các chuỗi thoát ANSI vào tệp nhật ký nếu sử dụng trình xử lý tệp. Nó không ảnh hưởng đến định dạng thông điệp tường trình.

Nếu bạn đã sử dụng Trình định dạng của mô-đun ghi nhật ký , tất cả những gì bạn phải làm để có được tên cấp độ màu là thay thế trình xử lý tư vấn của bạn Trình định dạng bằng Trình tạo màu. Nếu bạn đang đăng nhập toàn bộ ứng dụng, bạn chỉ cần thực hiện việc này cho trình ghi nhật ký cấp cao nhất.

màu_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)

Ví dụ sử dụng

ứng dụng

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

Các kết quả

Đầu ra thiết bị đầu cuối

Đầu ra thiết bị đầu cuối

nội dung app.log

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

Tất nhiên bạn có thể có được sự ưa thích như bạn muốn với định dạng đầu ra và đầu ra tệp nhật ký. Chỉ mức độ nhật ký sẽ được tô màu.

Tôi hy vọng ai đó thấy điều này hữu ích và nó không chỉ là quá nhiều như vậy. :)

Có thể tải xuống các tệp ví dụ Python từ GitHub Gist này: https://gist.github.com/KurtJacobson/48e750701acec40c7161b5a2f79e6bfd


2
BTW để thêm màu vào chính thông điệp, chỉ cần thêm dòng này trước return:colored_record.msg = ('{0}{1}m{2}{3}').format(self.PREFIX, seq, colored_record.getMessage(), self.SUFFIX)
Bố già

15

Tôi đã cập nhật ví dụ từ các thẻ hỗ trợ airmind cho tiền cảnh và hậu cảnh. Chỉ cần sử dụng các biến màu $ BLACK - $ WHITE trong chuỗi định dạng nhật ký của bạn. Để đặt nền, chỉ cần sử dụng $ BG-BLACK - $ BG-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

Vì vậy, bây giờ bạn có thể đơn giản làm như sau trong tệp cấu hình của bạn:

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

Cải tiến tuyệt vời. Tuy nhiên, nhận xét về superchỉ áp dụng cho một số phiên bản Python cổ đại tôi đoán? Vì câu trả lời này là từ năm 2010. Nó hoạt động tốt với tôi với Python 2.7
Joakim

14

Bạn có thể nhập mô-đun colorlog và sử dụng mô-đunColoredFormatter để tô màu các thông điệp .

Thí dụ

Nồi hơi cho mô-đun chính:

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

Mã chỉ cho phép màu trong các thông điệp tường trình, nếu mô-đun colorlog được cài đặt và nếu đầu ra thực sự đi đến một thiết bị đầu cuối. Điều này tránh các chuỗi thoát được ghi vào một tệp khi đầu ra nhật ký được chuyển hướng.

Ngoài ra, một bảng màu tùy chỉnh là thiết lập phù hợp hơn cho các thiết bị đầu cuối có nền tối.

Một số ví dụ ghi nhật ký cuộc gọi:

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

Đầu ra:

nhập mô tả hình ảnh ở đây


2
Cũng có thể sử dụng colorlog.basicConfigthay vì logging.basicConfigcó một số mặc định tốt
MarSoft

1
Đối với bản ghi, colorlog không phải lúc nào cũng hoạt động trực tiếp trên nền tảng Windows (như được chỉ định, phụ thuộc colorama là bắt buộc). Ngay cả với điều đó, tôi đã gặp khó khăn để khiến nó hoạt động trong Anaconda / Spyder env. Bạn có thể cần chỉ định colorama.init (dải = Sai) trong esc_code.py (như được chỉ ra trong chuỗi này github.com/spyder-ide/spyder/issues/1917 )
Matt-Mac-Muffin

11

Nhìn vào giải pháp sau đây. Trình xử lý luồng phải là thứ thực hiện tô màu, sau đó bạn có tùy chọn tô màu các từ thay vì chỉ toàn bộ dòng (với Trình định dạng).

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


Bạn có thể tìm thấy một triển khai cập nhật trong ý chính này (được duy trì bởi tác giả blog). Tôi đang sử dụng nó và hoạt động tốt. Cám ơn vì đã chia sẻ.
ồn ào

11

Tôi đã sửa đổi ví dụ ban đầu được cung cấp bởi Sorin và StreamHandler được phân lớp thành ColorizedConsoleHandler.

Nhược điểm của giải pháp của họ là nó sửa đổi thông báo và bởi vì đó là sửa đổi logmessage thực tế, bất kỳ trình xử lý nào khác cũng sẽ nhận được thông báo sửa đổi.

Điều này dẫn đến các logfile có mã màu trong trường hợp của chúng tôi vì chúng tôi sử dụng nhiều logger.

Lớp bên dưới chỉ hoạt động trên các nền tảng hỗ trợ ansi, nhưng việc thêm các mã màu cửa sổ vào nó là chuyện nhỏ.

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

Có hàng tấn phản hồi. Nhưng không ai nói về trang trí. Vậy đây là của tôi.

Bởi vì nó đơn giản hơn rất nhiều.

Không cần nhập bất cứ thứ gì, cũng không cần viết bất kỳ lớp con nào:

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

Điều này đặt các lỗi màu đỏ, thông báo gỡ lỗi màu xanh lam, v.v. Giống như hỏi trong câu hỏi.

Thậm chí chúng ta có thể điều chỉnh trình bao bọc để đưa ra một colorđối số thành động lực đặt màu của thông điệp bằng cách sử dụnglogger.debug("message", color=GREY)

EDIT: Vì vậy, đây là trình trang trí phù hợp để đặt màu khi chạy:

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

Một bản phối lại nhỏ khác của cách tiếp cận của airmind giữ mọi thứ trong một lớp:

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)

Để sử dụng đính kèm trình định dạng vào trình xử lý, đại loại như:

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

5

Một công cụ đơn giản nhưng rất linh hoạt để tô màu bất kỳ văn bản đầu cuối nào là ' colout '.

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

Trong đó bất kỳ văn bản nào trong đầu ra của 'my process' khớp với nhóm 1 của regex sẽ được tô màu bằng color1, nhóm 2 với color2, v.v.

Ví dụ:

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

tức là nhóm regex đầu tiên (parens) khớp với ngày ban đầu trong logfile, nhóm thứ hai khớp với tên tệp python, số dòng và tên hàm và nhóm thứ ba khớp với thông điệp tường trình xuất hiện sau đó. Tôi cũng sử dụng một chuỗi song song 'đậm / chuẩn' cũng như chuỗi màu. Điều này trông giống như:

logfile với định dạng màu

Lưu ý rằng các dòng hoặc các phần của dòng không khớp với bất kỳ biểu thức chính nào của tôi vẫn được lặp lại, vì vậy đây không phải là 'grep --color' - không có gì được lọc ra khỏi đầu ra.

Rõ ràng điều này đủ linh hoạt để bạn có thể sử dụng nó với bất kỳ quy trình nào, không chỉ là các logfiles. Tôi thường chỉ cần đánh một regex mới bất cứ khi nào tôi muốn tô màu một cái gì đó. Vì lý do này, tôi thích colout hơn bất kỳ công cụ tô màu logfile tùy chỉnh nào, bởi vì tôi chỉ cần học một công cụ, bất kể tôi đang tô màu gì: ghi nhật ký, đầu ra thử nghiệm, cú pháp tô sáng đoạn mã trong thiết bị đầu cuối, v.v.

Nó cũng tránh thực sự bỏ mã ANSI vào logfile, IMHO là một ý tưởng tồi, bởi vì nó sẽ phá vỡ mọi thứ như grepping cho các mẫu trong logfile trừ khi bạn luôn nhớ khớp mã ANSI trong biểu thức grep của bạn.


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 Ví dụ đẹp với [9*mmã cho màu ANSI "sáng"! PS dòng cuối cùng của bạn quan tâm đến tôi một chút bởi vì vẫn chưa biết liệu đăng nhập bên ngoài định nghĩa hàm có an toàn trong Python hay không .
Personal_cloud

2

Đây là giải pháp của tôi:

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

Điều tôi gặp khó khăn là thiết lập bộ định dạng đúng cách:

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)

Và sau đó sử dụng:

import coloured_log
import logging

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

coloured_log.close()    # restore colours

Nó được cho là mã giả (cũng như _set_colour bị mất), nhưng đã thêm một cái gì đó. Điều gặp khó khăn nhất là biết cách gắn định dạng chính xác.
Nick

Xem giải pháp "jack thợ sửa ống nước". Tôi nghĩ rằng đây là một cách tốt hơn để giải quyết vấn đề (tức là người xử lý nên thực hiện việc tô màu). stackoverflow.com/questions/384076/iêu
Nick

1

Trong khi các giải pháp khác có vẻ tốt, họ có một số vấn đề. Một số làm màu cho toàn bộ các dòng mà một số lần không muốn và một số bỏ qua bất kỳ cấu hình nào bạn có thể có cùng nhau. Giải pháp dưới đây không ảnh hưởng gì đến bản thân tin nhắn.

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)

Thí dụ

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

Đầu ra

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

Như bạn thấy, mọi thứ khác vẫn được xuất ra và giữ nguyên màu sắc ban đầu của chúng. Nếu bạn muốn thay đổi bất cứ điều gì khác ngoài thông điệp, bạn có thể chỉ cần chuyển mã màu log_formatvào ví dụ.


Khi tôi sử dụng nó, tin nhắn được in hai lần. bạn có biết tại sao?
Validus Oculus

@ bạn có thể giải thích? Cụ thể bạn có nghĩa là một cái gì đó giống như [17:01:36]:WARNING:this should be yellowthis should be yellowhoặc một dòng đầy đủ được in hai lần?
Pithikos

Xin lỗi vì sự ngắn gọn của bình luận. Điều trước đã xảy ra: [17:01:36]: CẢNH BÁO: đây phải là màu vàng \ nthis nên là màu vàng. Tuy nhiên, tôi chỉ muốn một định dạng được hiển thị, nếu không nó trông giống như một thùng rác do các bản ghi dự phòng.
Validus Oculus

@ MuratKarakuş không chắc tại sao điều này xảy ra mà không có cái nhìn đầy đủ về việc thực hiện. Nếu bạn đang sử dụng một logger tùy chỉnh, có thể bạn đang can thiệp vào một lúc nào đó? Một sửa chữa nhanh chóng có thể là để loại bỏ 7s:%(message)skhỏi log_format.
Pithikos

1

Tôi có hai bài nộp để thêm, một trong số đó chỉ tô màu cho thông điệp (ColoringFormatter) và một trong số đó tô màu toàn bộ dòng (ColorizingStreamHandler). Chúng cũng bao gồm nhiều mã màu ANSI hơn các giải pháp trước đó.

Một số nội dung đã có nguồn gốc (có sửa đổi) từ: Bài đăng ở trên và http://plumberjack.blogspot.com/2010/12/colorizing-logging-output-in-terminals.html .

Chỉ tô màu tin nhắn:

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

Tô màu toàn bộ dòng:

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

Đây là một Enum chứa mã màu:

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'

Điều này có thể được áp dụng cho tên của từng cấp độ nhật ký. Hãy nhận biết rằng đây là một hack khủng khiếp.

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

Lưu ý rằng trình định dạng nhật ký của bạn phải bao gồm tên của cấp độ nhật ký

%(levelname)

ví dụ:

    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 là một lựa chọn khác. Nó hoạt động với Python 2 & 3 trong Linux, Windows và MacOS.


Mong chờ PR mới để giảm sự lộn xộn đường dẫn mô-đun
mbspark

1

Điều gì về làm nổi bật cũng ghi nhật ký đối số thông điệp với màu sắc xen kẽ, ngoài việc tô màu theo cấp độ? Gần đây tôi đã viết mã đơn giản cho điều đó. Một ưu điểm khác là cuộc gọi nhật ký được thực hiện với định dạng kiểu cú đúp Python 3. ( "{}").

Xem mã mới nhất và ví dụ tại đây: https://github.com/davidohana/colargulog

Mã đăng nhập mẫu:

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)

Đầu ra:

nhập mô tả hình ảnh ở đây

Thực hiện:

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

Sử dụng pyfancy .

Thí dụ:

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

Câu hỏi là điều chỉnh loggingchức năng để sử dụng một thư viện tô màu riêng biệt.
Bị nhiễm Drake

0

Chỉ là một giải pháp khác, với màu sắc của ZetaSyanthis:

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)

gọi nó một lần từ __main__chức năng của bạn . Tôi có một cái gì đó như thế này:

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

nó cũng xác minh rằng đầu ra là một bàn điều khiển, nếu không thì không có màu nào được sử dụng.


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)

Sử dụng

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


Đối với bảng điều khiển, bạn có thể bỏ tên tệp hoặc đơn giản là filename = '' sẽ hoạt động. sửa đổi basicConfig để bao gồm các thuộc tính khác như số tệp, mô-đun ..
estifanos gebrehiwot

0

Giải pháp sau chỉ hoạt động với python 3, nhưng đối với tôi nó có vẻ rõ ràng nhất.

Ý tưởng là sử dụng nhà máy bản ghi nhật ký để thêm các thuộc tính 'màu' vào các đối tượng bản ghi nhật ký và hơn là sử dụng các thuộc tính 'màu' này trong định dạng nhật ký.

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

Bạn có thể dễ dàng sửa đổi ví dụ này để tạo các thuộc tính màu khác (fe message_c) và sau đó sử dụng các thuộc tính này để lấy văn bản màu (chỉ) ở nơi bạn muốn.

(mẹo tiện dụng tôi đã phát hiện gần đây: Tôi có một tệp có nhật ký gỡ lỗi màu và bất cứ khi nào tôi muốn tăng tạm thời mức ghi nhật ký của ứng dụng, tôi chỉ cần tail -ftệp nhật ký trong thiết bị đầu cuối khác và thấy nhật ký gỡ lỗi trên màn hình không thay đổi cấu hình và khởi động lại ứng dụng )


0

Đây là một biến thể Python3 khác của ví dụ về airmind. Tôi muốn một số tính năng cụ thể mà tôi không thấy trong các ví dụ khác

  • sử dụng màu cho thiết bị đầu cuối nhưng không viết các ký tự không in được trong trình xử lý tệp (Tôi đã xác định 2 trình định dạng cho việc này)
  • khả năng ghi đè màu cho một thông điệp tường trình cụ thể
  • cấu hình logger từ một tập tin (yaml trong trường hợp này)

Ghi chú: Tôi đã sử dụng colorama nhưng bạn có thể sửa đổi điều này để không bắt buộc. Ngoài ra để thử nghiệm, tôi chỉ chạy tệp python nên lớp của tôi nằm trong mô-đun __main__Bạn sẽ phải thay đổi (): __main__.ColoredFormatterthành bất kỳ mô-đun nào.

pip install colorama pyyaml

đăng nhập.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]

chính

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

đầu ra:

đầu ra

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.