Hướng dẫn python performance logging - ghi nhật ký hiệu suất python

Gói Stdlib

import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5 cung cấp rất nhiều tính linh hoạt và chức năng cho các nhà phát triển / DevOps / nhân viên hỗ trợ, và sự linh hoạt đó có một số chi phí, rõ ràng. Nếu nhu cầu về hiệu suất vượt qua sự cần thiết phải linh hoạt, bạn cần phải đi với một thứ khác. Bạn đã thực hiện các bước để tối ưu hóa mô tả trong tài liệu? Một cuộc gọi ghi nhật ký điển hình theo thứ tự hàng chục micro giây trên phần cứng hợp lý, điều mà hầu như không có vẻ quá mức. Tuy nhiên, việc đăng nhập vào các vòng lặp chặt chẽ hiếm khi được khuyến khích, nếu chỉ vì lượng thông tin được tạo ra có thể mất quá nhiều thời gian để lội qua.

Show

Mã để tìm người gọi có thể khá đắt, nhưng là cần thiết nếu bạn muốn, ví dụ: Tên tệp và số dòng nơi thực hiện cuộc gọi ghi nhật ký.

import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
6 được dành cho các kịch bản trong đó I/O khai thác sẽ mất thời gian đáng kể và không thể thực hiện theo băng tần. Ví dụ: một ứng dụng web có nhật ký cần được gửi qua email cho quản trị viên trang web không thể rủi ro bằng cách sử dụng trực tiếp
import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
7, vì cái bắt tay email có thể chậm.

Đừng quên rằng việc chuyển đổi ngữ cảnh trong Python là chậm. Bạn đã thử

import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
8 chưa? Có một điểm bắt đầu phù hợp trong tài liệu cho một quy trình nhận riêng thực hiện I/O thực tế để nộp, email, v.v. để quy trình của bạn chỉ thực hiện ổ cắm I/O và không thực hiện chuyển đổi ngữ cảnh chỉ để ghi nhật ký. Và sử dụng ổ cắm tên miền hoặc UDP có thể vẫn nhanh hơn, mặc dù sau đó là mất mát.

Có nhiều cách khác để tối ưu hóa. Ví dụ, các trình xử lý tiêu chuẩn trong việc ghi nhật ký làm khóa xung quanh

import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
9, đối với an toàn chủ đề - nếu trong một kịch bản cụ thể dưới sự kiểm soát của bạn, không có sự tranh chấp nào đối với người xử lý, bạn có thể có một lớp con xử lý không thu nhận và phát hành khóa. Và như thế.

Gói Python

import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5 là một gói nhẹ nhưng có thể mở rộng để theo dõi tốt hơn những gì mã của bạn làm. Sử dụng nó mang lại cho bạn sự linh hoạt hơn nhiều so với việc chỉ xả mã của bạn bằng các cuộc gọi
>>> import logging
>>> import pdb

>>> def f(x):
...     logging.error("bad vibes")
...     return x / 0
... 
>>> pdb.run("f(1)")
1 thừa.

Tuy nhiên, gói Python từ

import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5 có thể phức tạp ở một số điểm nhất định. Trình xử lý, logger, cấp độ, không gian tên, bộ lọc: Nó không dễ để theo dõi tất cả các phần này và cách chúng tương tác.

Một cách để buộc các kết thúc lỏng lẻo trong sự hiểu biết của bạn về

import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5 là nhìn trộm dưới mui xe vào mã nguồn cpython của nó. Mã Python đằng sau
import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5 là súc tích và mô -đun, và đọc qua nó có thể giúp bạn có được khoảnh khắc đó.

Bài viết này có nghĩa là để bổ sung cho việc ghi nhật ký tài liệu cũng như đăng nhập vào Python, đây là một hướng dẫn về cách sử dụng gói.

Đến cuối bài viết này, bạn sẽ quen thuộc với những điều sau đây::

  • import logging
    import sys
    
    logger = logging.getLogger("pylog")
    logger.setLevel(logging.DEBUG)
    h2 = logging.FileHandler(filename="/tmp/records.log")
    h2.setLevel(logging.INFO)
    h2 = logging.StreamHandler(sys.stderr)
    h2.setLevel(logging.ERROR)
    logger.addHandler(h2)
    logger.addHandler(h2)
    logger.info("testing %d.. %d.. %d..", 1, 2, 3)
    
    5 cấp độ và cách chúng hoạt động
  • Thread-Safety so với Process-Safety trong
    import logging
    import sys
    
    logger = logging.getLogger("pylog")
    logger.setLevel(logging.DEBUG)
    h2 = logging.FileHandler(filename="/tmp/records.log")
    h2.setLevel(logging.INFO)
    h2 = logging.StreamHandler(sys.stderr)
    h2.setLevel(logging.ERROR)
    logger.addHandler(h2)
    logger.addHandler(h2)
    logger.info("testing %d.. %d.. %d..", 1, 2, 3)
    
    5
  • Thiết kế của
    import logging
    import sys
    
    logger = logging.getLogger("pylog")
    logger.setLevel(logging.DEBUG)
    h2 = logging.FileHandler(filename="/tmp/records.log")
    h2.setLevel(logging.INFO)
    h2 = logging.StreamHandler(sys.stderr)
    h2.setLevel(logging.ERROR)
    logger.addHandler(h2)
    logger.addHandler(h2)
    logger.info("testing %d.. %d.. %d..", 1, 2, 3)
    
    5 từ góc độ OOP
  • Đăng nhập thư viện so với các ứng dụng
  • Thực tiễn và mô hình thiết kế tốt nhất để sử dụng
    import logging
    import sys
    
    logger = logging.getLogger("pylog")
    logger.setLevel(logging.DEBUG)
    h2 = logging.FileHandler(filename="/tmp/records.log")
    h2.setLevel(logging.INFO)
    h2 = logging.StreamHandler(sys.stderr)
    h2.setLevel(logging.ERROR)
    logger.addHandler(h2)
    logger.addHandler(h2)
    logger.info("testing %d.. %d.. %d..", 1, 2, 3)
    
    5

Đối với hầu hết các phần, chúng tôi sẽ đi theo mô-đun cốt lõi trong gói Python, ____ ____55 để xây dựng một bức tranh về cách mà nó đặt ra.

Làm thế nào để theo dõi

Bởi vì mã nguồn

import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5 là trung tâm của bài viết này, bạn có thể giả sử rằng bất kỳ khối mã hoặc liên kết nào cũng dựa trên một cam kết cụ thể trong kho lưu trữ CPython Python 3.7, cụ thể là cam kết
(Pdb) l
1514                     exc_info = (type(exc_info), exc_info, exc_info.__traceback__)
1515                 elif not isinstance(exc_info, tuple):
1516                     exc_info = sys.exc_info()
1517             record = self.makeRecord(self.name, level, fn, lno, msg, args,
1518                                      exc_info, func, extra, sinfo)
1519 ->          self.handle(record)
1520
1521         def handle(self, record):
1522             """
1523             Call the handlers for the specified record.
1524
(Pdb) from pprint import pprint
(Pdb) pprint(vars(record))
{'args': (),
 'created': 1550671851.660067,
 'exc_info': None,
 'exc_text': None,
 'filename': '',
 'funcName': 'f',
 'levelname': 'ERROR',
 'levelno': 40,
 'lineno': 2,
 'module': '',
 'msecs': 660.067081451416,
 'msg': 'bad vibes',
 'name': 'root',
 'pathname': '',
 'process': 2360,
 'processName': 'MainProcess',
 'relativeCreated': 295145.5490589142,
 'stack_info': None,
 'thread': 4372293056,
 'threadName': 'MainThread'}
1. Bạn có thể tìm thấy gói
import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5 trong thư mục
(Pdb) l
1514                     exc_info = (type(exc_info), exc_info, exc_info.__traceback__)
1515                 elif not isinstance(exc_info, tuple):
1516                     exc_info = sys.exc_info()
1517             record = self.makeRecord(self.name, level, fn, lno, msg, args,
1518                                      exc_info, func, extra, sinfo)
1519 ->          self.handle(record)
1520
1521         def handle(self, record):
1522             """
1523             Call the handlers for the specified record.
1524
(Pdb) from pprint import pprint
(Pdb) pprint(vars(record))
{'args': (),
 'created': 1550671851.660067,
 'exc_info': None,
 'exc_text': None,
 'filename': '',
 'funcName': 'f',
 'levelname': 'ERROR',
 'levelno': 40,
 'lineno': 2,
 'module': '',
 'msecs': 660.067081451416,
 'msg': 'bad vibes',
 'name': 'root',
 'pathname': '',
 'process': 2360,
 'processName': 'MainProcess',
 'relativeCreated': 295145.5490589142,
 'stack_info': None,
 'thread': 4372293056,
 'threadName': 'MainThread'}
3 trong nguồn cpython.

Trong gói

import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5, hầu hết các lần nâng nặng xảy ra trong
(Pdb) l
1514                     exc_info = (type(exc_info), exc_info, exc_info.__traceback__)
1515                 elif not isinstance(exc_info, tuple):
1516                     exc_info = sys.exc_info()
1517             record = self.makeRecord(self.name, level, fn, lno, msg, args,
1518                                      exc_info, func, extra, sinfo)
1519 ->          self.handle(record)
1520
1521         def handle(self, record):
1522             """
1523             Call the handlers for the specified record.
1524
(Pdb) from pprint import pprint
(Pdb) pprint(vars(record))
{'args': (),
 'created': 1550671851.660067,
 'exc_info': None,
 'exc_text': None,
 'filename': '',
 'funcName': 'f',
 'levelname': 'ERROR',
 'levelno': 40,
 'lineno': 2,
 'module': '',
 'msecs': 660.067081451416,
 'msg': 'bad vibes',
 'name': 'root',
 'pathname': '',
 'process': 2360,
 'processName': 'MainProcess',
 'relativeCreated': 295145.5490589142,
 'stack_info': None,
 'thread': 4372293056,
 'threadName': 'MainThread'}
5, đó là tệp bạn sẽ dành nhiều thời gian nhất ở đây:

cpython/
│
├── Lib/
│   ├── logging/
│   │   ├── __init__.py
│   │   ├── config.py
│   │   └── handlers.py
│   ├── ...
├── Modules/
├── Include/
...
... [truncated]

Với điều đó, hãy để nhảy vào.

Sơ bộ

Trước khi chúng tôi đến các lớp học hạng nặng, hàng trăm dòng hàng đầu của

(Pdb) l
1514                     exc_info = (type(exc_info), exc_info, exc_info.__traceback__)
1515                 elif not isinstance(exc_info, tuple):
1516                     exc_info = sys.exc_info()
1517             record = self.makeRecord(self.name, level, fn, lno, msg, args,
1518                                      exc_info, func, extra, sinfo)
1519 ->          self.handle(record)
1520
1521         def handle(self, record):
1522             """
1523             Call the handlers for the specified record.
1524
(Pdb) from pprint import pprint
(Pdb) pprint(vars(record))
{'args': (),
 'created': 1550671851.660067,
 'exc_info': None,
 'exc_text': None,
 'filename': '',
 'funcName': 'f',
 'levelname': 'ERROR',
 'levelno': 40,
 'lineno': 2,
 'module': '',
 'msecs': 660.067081451416,
 'msg': 'bad vibes',
 'name': 'root',
 'pathname': '',
 'process': 2360,
 'processName': 'MainProcess',
 'relativeCreated': 295145.5490589142,
 'stack_info': None,
 'thread': 4372293056,
 'threadName': 'MainThread'}
6 giới thiệu một vài khái niệm tinh tế nhưng quan trọng.

Sơ bộ số 1: Một cấp độ chỉ là một (Pdb) l 1514 exc_info = (type(exc_info), exc_info, exc_info.__traceback__) 1515 elif not isinstance(exc_info, tuple): 1516 exc_info = sys.exc_info() 1517 record = self.makeRecord(self.name, level, fn, lno, msg, args, 1518 exc_info, func, extra, sinfo) 1519 -> self.handle(record) 1520 1521 def handle(self, record): 1522 """ 1523 Call the handlers for the specified record. 1524 (Pdb) from pprint import pprint (Pdb) pprint(vars(record)) {'args': (), 'created': 1550671851.660067, 'exc_info': None, 'exc_text': None, 'filename': '', 'funcName': 'f', 'levelname': 'ERROR', 'levelno': 40, 'lineno': 2, 'module': '', 'msecs': 660.067081451416, 'msg': 'bad vibes', 'name': 'root', 'pathname': '', 'process': 2360, 'processName': 'MainProcess', 'relativeCreated': 295145.5490589142, 'stack_info': None, 'thread': 4372293056, 'threadName': 'MainThread'} 7!

Các đối tượng như

(Pdb) l
1514                     exc_info = (type(exc_info), exc_info, exc_info.__traceback__)
1515                 elif not isinstance(exc_info, tuple):
1516                     exc_info = sys.exc_info()
1517             record = self.makeRecord(self.name, level, fn, lno, msg, args,
1518                                      exc_info, func, extra, sinfo)
1519 ->          self.handle(record)
1520
1521         def handle(self, record):
1522             """
1523             Call the handlers for the specified record.
1524
(Pdb) from pprint import pprint
(Pdb) pprint(vars(record))
{'args': (),
 'created': 1550671851.660067,
 'exc_info': None,
 'exc_text': None,
 'filename': '',
 'funcName': 'f',
 'levelname': 'ERROR',
 'levelno': 40,
 'lineno': 2,
 'module': '',
 'msecs': 660.067081451416,
 'msg': 'bad vibes',
 'name': 'root',
 'pathname': '',
 'process': 2360,
 'processName': 'MainProcess',
 'relativeCreated': 295145.5490589142,
 'stack_info': None,
 'thread': 4372293056,
 'threadName': 'MainThread'}
8 hoặc
(Pdb) l
1514                     exc_info = (type(exc_info), exc_info, exc_info.__traceback__)
1515                 elif not isinstance(exc_info, tuple):
1516                     exc_info = sys.exc_info()
1517             record = self.makeRecord(self.name, level, fn, lno, msg, args,
1518                                      exc_info, func, extra, sinfo)
1519 ->          self.handle(record)
1520
1521         def handle(self, record):
1522             """
1523             Call the handlers for the specified record.
1524
(Pdb) from pprint import pprint
(Pdb) pprint(vars(record))
{'args': (),
 'created': 1550671851.660067,
 'exc_info': None,
 'exc_text': None,
 'filename': '',
 'funcName': 'f',
 'levelname': 'ERROR',
 'levelno': 40,
 'lineno': 2,
 'module': '',
 'msecs': 660.067081451416,
 'msg': 'bad vibes',
 'name': 'root',
 'pathname': '',
 'process': 2360,
 'processName': 'MainProcess',
 'relativeCreated': 295145.5490589142,
 'stack_info': None,
 'thread': 4372293056,
 'threadName': 'MainThread'}
9 có vẻ hơi mờ. Những biến này là gì trong nội bộ, và chúng được xác định như thế nào?

Trên thực tế, các hằng số chữ hoa từ Python,

import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5 chỉ là các số nguyên, tạo thành một bộ sưu tập giống như enum của các cấp số:

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0

Tại sao không chỉ sử dụng các chuỗi

class Logger(Filterer):
    # ...
    def getEffectiveLevel(self):
        logger = self
        while logger:
            if logger.level:
                return logger.level
            logger = logger.parent
        return NOTSET

    def isEnabledFor(self, level):
        try:
            return self._cache[level]
        except KeyError:
            _acquireLock()
            if self.manager.disable >= level:
                is_enabled = self._cache[level] = False
            else:
                is_enabled = self._cache[level] = level >= self.getEffectiveLevel()
            _releaseLock()
        return is_enabled
1 hoặc
class Logger(Filterer):
    # ...
    def getEffectiveLevel(self):
        logger = self
        while logger:
            if logger.level:
                return logger.level
            logger = logger.parent
        return NOTSET

    def isEnabledFor(self, level):
        try:
            return self._cache[level]
        except KeyError:
            _acquireLock()
            if self.manager.disable >= level:
                is_enabled = self._cache[level] = False
            else:
                is_enabled = self._cache[level] = level >= self.getEffectiveLevel()
            _releaseLock()
        return is_enabled
2? Các cấp là hằng số ____777 để cho phép so sánh đơn giản, rõ ràng của một cấp với một cấp khác. Họ cũng được đặt tên để cho họ mượn ý nghĩa ngữ nghĩa. Nói rằng một tin nhắn có mức độ nghiêm trọng là 50 có thể không rõ ràng ngay lập tức, nhưng nói rằng nó có mức độ
class Logger(Filterer):
    # ...
    def getEffectiveLevel(self):
        logger = self
        while logger:
            if logger.level:
                return logger.level
            logger = logger.parent
        return NOTSET

    def isEnabledFor(self, level):
        try:
            return self._cache[level]
        except KeyError:
            _acquireLock()
            if self.manager.disable >= level:
                is_enabled = self._cache[level] = False
            else:
                is_enabled = self._cache[level] = level >= self.getEffectiveLevel()
            _releaseLock()
        return is_enabled
4 cho bạn biết rằng bạn đã có đèn đỏ nhấp nháy ở đâu đó trong chương trình của bạn.

Bây giờ, về mặt kỹ thuật, bạn chỉ có thể vượt qua dạng

class Logger(Filterer):
    # ...
    def getEffectiveLevel(self):
        logger = self
        while logger:
            if logger.level:
                return logger.level
            logger = logger.parent
        return NOTSET

    def isEnabledFor(self, level):
        try:
            return self._cache[level]
        except KeyError:
            _acquireLock()
            if self.manager.disable >= level:
                is_enabled = self._cache[level] = False
            else:
                is_enabled = self._cache[level] = level >= self.getEffectiveLevel()
            _releaseLock()
        return is_enabled
5 của một cấp độ ở một số nơi, chẳng hạn như
class Logger(Filterer):
    # ...
    def getEffectiveLevel(self):
        logger = self
        while logger:
            if logger.level:
                return logger.level
            logger = logger.parent
        return NOTSET

    def isEnabledFor(self, level):
        try:
            return self._cache[level]
        except KeyError:
            _acquireLock()
            if self.manager.disable >= level:
                is_enabled = self._cache[level] = False
            else:
                is_enabled = self._cache[level] = level >= self.getEffectiveLevel()
            _releaseLock()
        return is_enabled
6. Trong nội bộ, điều này sẽ gọi
class Logger(Filterer):
    # ...
    def getEffectiveLevel(self):
        logger = self
        while logger:
            if logger.level:
                return logger.level
            logger = logger.parent
        return NOTSET

    def isEnabledFor(self, level):
        try:
            return self._cache[level]
        except KeyError:
            _acquireLock()
            if self.manager.disable >= level:
                is_enabled = self._cache[level] = False
            else:
                is_enabled = self._cache[level] = level >= self.getEffectiveLevel()
            _releaseLock()
        return is_enabled
7, cuối cùng thực hiện tìm kiếm
class Logger(Filterer):
    # ...
    def getEffectiveLevel(self):
        logger = self
        while logger:
            if logger.level:
                return logger.level
            logger = logger.parent
        return NOTSET

    def isEnabledFor(self, level):
        try:
            return self._cache[level]
        except KeyError:
            _acquireLock()
            if self.manager.disable >= level:
                is_enabled = self._cache[level] = False
            else:
                is_enabled = self._cache[level] = level >= self.getEffectiveLevel()
            _releaseLock()
        return is_enabled
8 cho
(Pdb) l
1514                     exc_info = (type(exc_info), exc_info, exc_info.__traceback__)
1515                 elif not isinstance(exc_info, tuple):
1516                     exc_info = sys.exc_info()
1517             record = self.makeRecord(self.name, level, fn, lno, msg, args,
1518                                      exc_info, func, extra, sinfo)
1519 ->          self.handle(record)
1520
1521         def handle(self, record):
1522             """
1523             Call the handlers for the specified record.
1524
(Pdb) from pprint import pprint
(Pdb) pprint(vars(record))
{'args': (),
 'created': 1550671851.660067,
 'exc_info': None,
 'exc_text': None,
 'filename': '',
 'funcName': 'f',
 'levelname': 'ERROR',
 'levelno': 40,
 'lineno': 2,
 'module': '',
 'msecs': 660.067081451416,
 'msg': 'bad vibes',
 'name': 'root',
 'pathname': '',
 'process': 2360,
 'processName': 'MainProcess',
 'relativeCreated': 295145.5490589142,
 'stack_info': None,
 'thread': 4372293056,
 'threadName': 'MainThread'}
7: tương ứng:

_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv

Bạn nên thích cái nào hơn? Tôi không quá quan tâm đến điều này, nhưng điều đáng chú ý là các tài liệu

import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5 luôn sử dụng biểu mẫu
(Pdb) l
1514                     exc_info = (type(exc_info), exc_info, exc_info.__traceback__)
1515                 elif not isinstance(exc_info, tuple):
1516                     exc_info = sys.exc_info()
1517             record = self.makeRecord(self.name, level, fn, lno, msg, args,
1518                                      exc_info, func, extra, sinfo)
1519 ->          self.handle(record)
1520
1521         def handle(self, record):
1522             """
1523             Call the handlers for the specified record.
1524
(Pdb) from pprint import pprint
(Pdb) pprint(vars(record))
{'args': (),
 'created': 1550671851.660067,
 'exc_info': None,
 'exc_text': None,
 'filename': '',
 'funcName': 'f',
 'levelname': 'ERROR',
 'levelno': 40,
 'lineno': 2,
 'module': '',
 'msecs': 660.067081451416,
 'msg': 'bad vibes',
 'name': 'root',
 'pathname': '',
 'process': 2360,
 'processName': 'MainProcess',
 'relativeCreated': 295145.5490589142,
 'stack_info': None,
 'thread': 4372293056,
 'threadName': 'MainThread'}
9 thay vì
class Logger(Filterer):
    # ...
    def getEffectiveLevel(self):
        logger = self
        while logger:
            if logger.level:
                return logger.level
            logger = logger.parent
        return NOTSET

    def isEnabledFor(self, level):
        try:
            return self._cache[level]
        except KeyError:
            _acquireLock()
            if self.manager.disable >= level:
                is_enabled = self._cache[level] = False
            else:
                is_enabled = self._cache[level] = level >= self.getEffectiveLevel()
            _releaseLock()
        return is_enabled
2 hoặc
>>> import logging
>>> logger = logging.getLogger("app")
>>> logger.level  # No!
0
>>> logger.getEffectiveLevel()
30
>>> logger.parent

>>> logger.parent.level
30
3. Ngoài ra, việc chuyển mẫu
class Logger(Filterer):
    # ...
    def getEffectiveLevel(self):
        logger = self
        while logger:
            if logger.level:
                return logger.level
            logger = logger.parent
        return NOTSET

    def isEnabledFor(self, level):
        try:
            return self._cache[level]
        except KeyError:
            _acquireLock()
            if self.manager.disable >= level:
                is_enabled = self._cache[level] = False
            else:
                is_enabled = self._cache[level] = level >= self.getEffectiveLevel()
            _releaseLock()
        return is_enabled
5 không phải là một tùy chọn trong Python 2 và một số phương pháp
import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5 như
>>> import logging
>>> logger = logging.getLogger("app")
>>> logger.level  # No!
0
>>> logger.getEffectiveLevel()
30
>>> logger.parent

>>> logger.parent.level
30
6 sẽ chỉ chấp nhận một
(Pdb) l
1514                     exc_info = (type(exc_info), exc_info, exc_info.__traceback__)
1515                 elif not isinstance(exc_info, tuple):
1516                     exc_info = sys.exc_info()
1517             record = self.makeRecord(self.name, level, fn, lno, msg, args,
1518                                      exc_info, func, extra, sinfo)
1519 ->          self.handle(record)
1520
1521         def handle(self, record):
1522             """
1523             Call the handlers for the specified record.
1524
(Pdb) from pprint import pprint
(Pdb) pprint(vars(record))
{'args': (),
 'created': 1550671851.660067,
 'exc_info': None,
 'exc_text': None,
 'filename': '',
 'funcName': 'f',
 'levelname': 'ERROR',
 'levelno': 40,
 'lineno': 2,
 'module': '',
 'msecs': 660.067081451416,
 'msg': 'bad vibes',
 'name': 'root',
 'pathname': '',
 'process': 2360,
 'processName': 'MainProcess',
 'relativeCreated': 295145.5490589142,
 'stack_info': None,
 'thread': 4372293056,
 'threadName': 'MainThread'}
7, chứ không phải là anh em họ ____85 của nó.

Sơ bộ #2: Ghi nhật ký là an toàn cho luồng, nhưng không an toàn quá trình

Một vài dòng xuống, bạn sẽ tìm thấy khối mã ngắn sau đây, điều này rất quan trọng đối với toàn bộ gói:

import threading

_lock = threading.RLock()

def _acquireLock():
     if _lock:
        _lock.acquire()

def _releaseLock():
    if _lock:
        _lock.release()

Đối tượng

>>> import logging
>>> logger = logging.getLogger("app")
>>> logger.level  # No!
0
>>> logger.getEffectiveLevel()
30
>>> logger.parent

>>> logger.parent.level
30
9 là một khóa reentrant nằm trong không gian tên toàn cầu của mô -đun
(Pdb) l
1514                     exc_info = (type(exc_info), exc_info, exc_info.__traceback__)
1515                 elif not isinstance(exc_info, tuple):
1516                     exc_info = sys.exc_info()
1517             record = self.makeRecord(self.name, level, fn, lno, msg, args,
1518                                      exc_info, func, extra, sinfo)
1519 ->          self.handle(record)
1520
1521         def handle(self, record):
1522             """
1523             Call the handlers for the specified record.
1524
(Pdb) from pprint import pprint
(Pdb) pprint(vars(record))
{'args': (),
 'created': 1550671851.660067,
 'exc_info': None,
 'exc_text': None,
 'filename': '',
 'funcName': 'f',
 'levelname': 'ERROR',
 'levelno': 40,
 'lineno': 2,
 'module': '',
 'msecs': 660.067081451416,
 'msg': 'bad vibes',
 'name': 'root',
 'pathname': '',
 'process': 2360,
 'processName': 'MainProcess',
 'relativeCreated': 295145.5490589142,
 'stack_info': None,
 'thread': 4372293056,
 'threadName': 'MainThread'}
5. Nó làm cho khá nhiều đối tượng và hoạt động trong toàn bộ gói an toàn cho luồng
import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5, cho phép các luồng thực hiện các hoạt động đọc và viết mà không cần mối đe dọa của một điều kiện chủng tộc. Bạn có thể thấy trong mã nguồn mô -đun mà
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
02 và
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
03 có mặt khắp nơi đối với mô -đun và các lớp của nó.

Mặc dù vậy, có một cái gì đó không được tính ở đây: còn an toàn quá trình thì sao? Câu trả lời ngắn gọn là mô -đun

import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5 không được xử lý an toàn. Đây không phải là lỗi của ____ 55, nói chung, hai quy trình có thể viết vào cùng một tệp mà không cần nhiều nỗ lực chủ động thay mặt cho lập trình viên trước.

Điều này có nghĩa là bạn sẽ muốn cẩn thận trước khi sử dụng các lớp như

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
06 có liên quan. Nếu hai quy trình muốn đọc và ghi vào cùng một tệp bên dưới, thì bạn có thể chạy vào một lỗi khó chịu giữa một thói quen chạy dài.

Nếu bạn muốn vượt qua giới hạn này, thì có một công thức kỹ lưỡng trong cuốn sách nấu ăn chính thức. Bởi vì điều này đòi hỏi một lượng thiết lập kha khá, một cách khác là có mỗi nhật ký quy trình vào một tệp riêng dựa trên ID quy trình của nó, mà bạn có thể lấy với

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
07.

Kiến trúc gói: Ghi nhật ký MRO MRO

Bây giờ, chúng tôi đã đề cập đến một số mã thiết lập sơ bộ, hãy để có một cái nhìn cấp cao về cách

import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5 được đặt ra. Gói
import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5 sử dụng một liều OOP và thừa kế lành mạnh. Ở đây, một cái nhìn một phần về thứ tự phân giải phương thức (MRO) cho một số lớp quan trọng nhất trong gói:

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager

Biểu đồ cây trên không bao gồm tất cả các lớp trong mô -đun, chỉ là những lớp đáng để làm nổi bật nhất.

Litany của các lớp học này thường là một nguồn gây nhầm lẫn bởi vì có rất nhiều điều đang diễn ra, và nó tất cả đều nặng về biệt ngữ.

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
10 so với
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
11?
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12 so với
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
13? Nó có thể là một thách thức để theo dõi mọi thứ, ít hình dung hơn về cách nó phù hợp với nhau. Một bức tranh có giá trị một nghìn từ, vì vậy, đây là một sơ đồ của một kịch bản trong đó một logger với hai trình xử lý được gắn vào nó viết một thông báo nhật ký với cấp độ
(Pdb) l
1514                     exc_info = (type(exc_info), exc_info, exc_info.__traceback__)
1515                 elif not isinstance(exc_info, tuple):
1516                     exc_info = sys.exc_info()
1517             record = self.makeRecord(self.name, level, fn, lno, msg, args,
1518                                      exc_info, func, extra, sinfo)
1519 ->          self.handle(record)
1520
1521         def handle(self, record):
1522             """
1523             Call the handlers for the specified record.
1524
(Pdb) from pprint import pprint
(Pdb) pprint(vars(record))
{'args': (),
 'created': 1550671851.660067,
 'exc_info': None,
 'exc_text': None,
 'filename': '',
 'funcName': 'f',
 'levelname': 'ERROR',
 'levelno': 40,
 'lineno': 2,
 'module': '',
 'msecs': 660.067081451416,
 'msg': 'bad vibes',
 'name': 'root',
 'pathname': '',
 'process': 2360,
 'processName': 'MainProcess',
 'relativeCreated': 295145.5490589142,
 'stack_info': None,
 'thread': 4372293056,
 'threadName': 'MainThread'}
8:

Hướng dẫn python performance logging - ghi nhật ký hiệu suất python
Dòng chảy của các đối tượng ghi nhật ký (hình ảnh: Python thật)

Trong mã Python, mọi thứ trên sẽ trông như thế này:

import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)

Có một bản đồ chi tiết hơn về dòng chảy này trong việc ghi nhật ký. Những gì mà hiển thị ở trên là một kịch bản đơn giản hóa.

Mã của bạn chỉ xác định một ví dụ

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12,
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
16, cùng với hai trường hợp
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
13,
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
18 và
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
18.

Khi bạn gọi

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
20, đối tượng
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
16 đóng vai trò là bộ lọc vì nó cũng có
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
22 được liên kết với nó. Chỉ khi mức độ tin nhắn đủ nghiêm trọng, logger mới làm bất cứ điều gì với tin nhắn. Bởi vì logger có mức
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
23 và thông báo mang mức độ
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
24 cao hơn, nó sẽ tiếp tục đi trước.

Trong nội bộ,

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
16 gọi
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
26 để đặt chuỗi tin nhắn
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
27 và các đối số của nó
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
28 vào một phiên bản lớp bona fide của
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
29, chỉ là một thùng chứa cho tin nhắn và siêu dữ liệu của nó.

Đối tượng

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
16 tìm kiếm các trình xử lý của nó (các trường hợp
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
13), có thể được gắn trực tiếp với chính
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
16 hoặc với cha mẹ của nó (một khái niệm mà chúng tôi sẽ chạm vào sau). Trong ví dụ này, nó tìm thấy hai trình xử lý:

  1. Một với cấp độ
    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    24 gửi dữ liệu nhật ký vào một tệp tại
    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    34
  2. Một bản ghi vào
    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    35 nhưng chỉ khi tin nhắn đến ở cấp độ
    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    36 trở lên

Tại thời điểm này, có một vòng thử nghiệm khác. Đối với những người xử lý, viết

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
29 vào luồng của họ được gọi là phát ra nó, được chụp trong
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
41 của họ.emitting it, which is captured in their
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
41.

Tiếp theo, hãy để LỚN mổ xẻ mọi thứ từ trên cao.

Lớp CRITICAL = 50 FATAL = CRITICAL ERROR = 40 WARNING = 30 WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0 29

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
29 là gì? Khi bạn đăng nhập một tin nhắn, một thể hiện của lớp
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
29 là đối tượng bạn gửi để được ghi lại. Nó được tạo ra cho bạn bởi một ví dụ
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12 và gói gọn tất cả các thông tin thích hợp về sự kiện đó. Trong nội bộ, nó rất ít hơn một trình bao bọc xung quanh
class Logger(Filterer):
    # ...
    def getEffectiveLevel(self):
        logger = self
        while logger:
            if logger.level:
                return logger.level
            logger = logger.parent
        return NOTSET

    def isEnabledFor(self, level):
        try:
            return self._cache[level]
        except KeyError:
            _acquireLock()
            if self.manager.disable >= level:
                is_enabled = self._cache[level] = False
            else:
                is_enabled = self._cache[level] = level >= self.getEffectiveLevel()
            _releaseLock()
        return is_enabled
8 chứa các thuộc tính cho hồ sơ. Một ví dụ
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12 gửi một thể hiện
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
29 đến các phiên bản
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
13 hoặc nhiều hơn.

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
29 chứa một số siêu dữ liệu, chẳng hạn như sau:

  1. Một cái tên
  2. Thời gian sáng tạo như một dấu thời gian unix
  3. Thông điệp chính nó
  4. Thông tin về chức năng nào đã thực hiện cuộc gọi ghi nhật ký

Ở đây, một cái nhìn vào siêu dữ liệu mà nó mang theo với nó, mà bạn có thể hướng nội bằng cách bước qua một cuộc gọi

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
51 với mô -đun
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
52:

>>>

>>> import logging
>>> import pdb

>>> def f(x):
...     logging.error("bad vibes")
...     return x / 0
... 
>>> pdb.run("f(1)")

Sau khi bước qua một số chức năng cấp cao hơn, bạn sẽ kết thúc ở dòng 1517:

(Pdb) l
1514                     exc_info = (type(exc_info), exc_info, exc_info.__traceback__)
1515                 elif not isinstance(exc_info, tuple):
1516                     exc_info = sys.exc_info()
1517             record = self.makeRecord(self.name, level, fn, lno, msg, args,
1518                                      exc_info, func, extra, sinfo)
1519 ->          self.handle(record)
1520
1521         def handle(self, record):
1522             """
1523             Call the handlers for the specified record.
1524
(Pdb) from pprint import pprint
(Pdb) pprint(vars(record))
{'args': (),
 'created': 1550671851.660067,
 'exc_info': None,
 'exc_text': None,
 'filename': '',
 'funcName': 'f',
 'levelname': 'ERROR',
 'levelno': 40,
 'lineno': 2,
 'module': '',
 'msecs': 660.067081451416,
 'msg': 'bad vibes',
 'name': 'root',
 'pathname': '',
 'process': 2360,
 'processName': 'MainProcess',
 'relativeCreated': 295145.5490589142,
 'stack_info': None,
 'thread': 4372293056,
 'threadName': 'MainThread'}

Một

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
29, trong nội bộ, chứa một kho siêu dữ liệu mà sử dụng theo cách này hay cách khác.

Bạn hiếm khi cần phải đối phó trực tiếp với

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
29, vì
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12 và
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
13 làm điều này cho bạn. Nó vẫn còn đáng để biết thông tin nào được kết thúc trong một
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
29, bởi vì đây là nơi mà tất cả thông tin hữu ích đó, như dấu thời gian, đến từ khi bạn thấy các tin nhắn nhật ký ghi.

Các lớp CRITICAL = 50 FATAL = CRITICAL ERROR = 40 WARNING = 30 WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0 12 và CRITICAL = 50 FATAL = CRITICAL ERROR = 40 WARNING = 30 WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0 13

Các lớp

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12 và
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
13 đều là trung tâm của cách
import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5 hoạt động và chúng tương tác với nhau thường xuyên. A
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12, A
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
13 và A
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
29 mỗi
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
66 liên quan đến chúng.

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12 lấy
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
29 và chuyển nó đến
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
13, nhưng chỉ khi mức hiệu quả của
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
29 bằng hoặc cao hơn so với
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12. Điều tương tự cũng xảy ra với bài kiểm tra
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
29 so với
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
13. Điều này được gọi là lọc dựa trên cấp độ, trong đó
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12 và
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
13 thực hiện theo những cách hơi khác nhau.level-based filtering, which
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12 and
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
13 implement in slightly different ways.

Nói cách khác, có một bài kiểm tra hai bước (ít nhất) được áp dụng trước khi thông báo mà bạn đăng nhập sẽ đi bất cứ đâu. Để được truyền hoàn toàn từ bộ ghi sang xử lý và sau đó đăng nhập vào luồng cuối (có thể là

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
76, một tệp hoặc email qua SMTP),
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
29 phải có mức cao nhất là cả bộ ghi và trình xử lý .

PEP 282 mô tả cách thức hoạt động của nó:

Mỗi đối tượng

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12 theo dõi mức nhật ký (hoặc ngưỡng) mà nó quan tâm và loại bỏ các yêu cầu nhật ký dưới mức đó. (Nguồn)

Vậy bộ lọc dựa trên cấp độ này thực sự xảy ra ở đâu cho cả

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12 và
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
13?

Đối với lớp

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12, nó là một giả định đầu tiên hợp lý rằng logger sẽ so sánh thuộc tính
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
66 của nó với cấp độ của
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
29 và được thực hiện ở đó. Tuy nhiên, nó có liên quan nhiều hơn thế.

Lọc dựa trên cấp độ cho logger xảy ra trong

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
84, từ đó gọi
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
85. Luôn luôn sử dụng
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
86 thay vì chỉ tư vấn
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
87. Lý do liên quan đến việc tổ chức các đối tượng
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12 trong một không gian tên phân cấp. (Bạn sẽ thấy nhiều hơn về điều này sau.)

Theo mặc định, một thể hiện

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12 có mức
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
90 (
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
91). Tuy nhiên, loggers cũng có bộ ghi nhật ký cha mẹ, một trong số đó là logger gốc, có chức năng là cha mẹ của tất cả các trình ghi nhật ký khác. Một
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12 sẽ đi lên trên phân cấp của nó và có được mức độ hiệu quả của nó là cha mẹ của nó (cuối cùng có thể là
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
93 nếu không có cha mẹ nào được tìm thấy).parent loggers, one of which is the root logger, which functions as the parent of all other loggers. A
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12 will walk upwards in its hierarchy and get its effective level vis-à-vis its parent (which ultimately may be
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
93 if no other parents are found).

Ở đây, nơi mà điều này xảy ra trong lớp

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12:

class Logger(Filterer):
    # ...
    def getEffectiveLevel(self):
        logger = self
        while logger:
            if logger.level:
                return logger.level
            logger = logger.parent
        return NOTSET

    def isEnabledFor(self, level):
        try:
            return self._cache[level]
        except KeyError:
            _acquireLock()
            if self.manager.disable >= level:
                is_enabled = self._cache[level] = False
            else:
                is_enabled = self._cache[level] = level >= self.getEffectiveLevel()
            _releaseLock()
        return is_enabled

Tương ứng, ở đây, một ví dụ gọi mã nguồn mà bạn thấy ở trên:

>>>

>>> import logging
>>> logger = logging.getLogger("app")
>>> logger.level  # No!
0
>>> logger.getEffectiveLevel()
30
>>> logger.parent

>>> logger.parent.level
30

Ở đây, người ta đang bỏ đi: Don lồng dựa vào

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
66. Nếu bạn không đặt một cấp độ trên đối tượng
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
16 của bạn và bạn sẽ phụ thuộc vào
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
66 vì một số lý do, thì thiết lập đăng nhập của bạn có thể sẽ hoạt động khác với bạn mong đợi.

Còn

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
13 thì sao? Đối với người xử lý, so sánh cấp đến cấp độ đơn giản hơn, mặc dù nó thực sự xảy ra trong
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
99 từ lớp
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12:

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
0

Đối với một ví dụ

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
29 đã cho (được đặt tên
_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv
02 trong mã nguồn ở trên), một logger kiểm tra với từng trình xử lý đã đăng ký và kiểm tra nhanh trên thuộc tính
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
66 của phiên bản
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
13 đó. Nếu
_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv
05 của
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
29 lớn hơn hoặc bằng với trình xử lý, chỉ sau đó, bản ghi được truyền lại. Một tài liệu trong
import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5 đề cập đến điều này khi có điều kiện phát ra [ting] bản ghi ghi nhật ký được chỉ định.

Thuộc tính quan trọng nhất cho một thể hiện lớp con

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
13 là thuộc tính
_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv
09 của nó. Đây là đích đến cuối cùng mà nhật ký được ghi đến và có thể là khá nhiều đối tượng giống như tệp. Ở đây, một ví dụ với
_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv
10, là một luồng trong bộ nhớ (bộ đệm) cho văn bản I/O.

Đầu tiên, thiết lập một ví dụ

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12 với mức
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
23. Bạn sẽ thấy rằng, theo mặc định, nó không có trình xử lý trực tiếp:

>>>

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
1

Tiếp theo, bạn có thể phân lớp

_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv
13 để làm cho
_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv
14 gọi là không có. Chúng tôi muốn xả
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
35 hoặc
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
76, nhưng không phải là bộ đệm trong bộ nhớ trong trường hợp này:

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
2

Bây giờ, hãy khai báo chính đối tượng bộ đệm và buộc nó là

_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv
09 cho trình xử lý tùy chỉnh của bạn với mức độ
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
24, sau đó buộc trình xử lý đó vào logger:

>>>

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
3

Tiếp theo, bạn có thể phân lớp

_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv
13 để làm cho
_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv
14 gọi là không có. Chúng tôi muốn xả
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
35 hoặc
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
76, nhưng không phải là bộ đệm trong bộ nhớ trong trường hợp này:

Bây giờ, hãy khai báo chính đối tượng bộ đệm và buộc nó là

_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv
09 cho trình xử lý tùy chỉnh của bạn với mức độ
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
24, sau đó buộc trình xử lý đó vào logger:

Chunk cuối cùng này là một minh họa khác về lọc dựa trên cấp độ.

Ba tin nhắn có cấp độ CRITICAL = 50 FATAL = CRITICAL ERROR = 40 WARNING = 30 WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0 23, _nameToLevel = { 'CRITICAL': CRITICAL, 'FATAL': FATAL, 'ERROR': ERROR, 'WARN': WARNING, 'WARNING': WARNING, 'INFO': INFO, 'DEBUG': DEBUG, 'NOTSET': NOTSET, } def _checkLevel(level): if isinstance(level, int): rv = level elif str(level) == level: if level not in _nameToLevel: raise ValueError("Unknown level: %r" % level) rv = _nameToLevel[level] else: raise TypeError("Level not an integer or a valid string: %r" % level) return rv 20 và class Logger(Filterer): # ... def getEffectiveLevel(self): logger = self while logger: if logger.level: return logger.level logger = logger.parent return NOTSET def isEnabledFor(self, level): try: return self._cache[level] except KeyError: _acquireLock() if self.manager.disable >= level: is_enabled = self._cache[level] = False else: is_enabled = self._cache[level] = level >= self.getEffectiveLevel() _releaseLock() return is_enabled 4 được truyền qua chuỗi. Lúc đầu, có vẻ như họ không đi đâu cả, nhưng hai người trong số họ làm. Tất cả ba người họ làm cho nó ra khỏi cổng từ CRITICAL = 50 FATAL = CRITICAL ERROR = 40 WARNING = 30 WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0 16 (có cấp độ CRITICAL = 50 FATAL = CRITICAL ERROR = 40 WARNING = 30 WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0 23).

Tuy nhiên, chỉ có hai trong số chúng được phát ra bởi người xử lý vì nó có mức độ

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
24 cao hơn, vượt quá
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
23. Cuối cùng, bạn nhận được toàn bộ nội dung của bộ đệm dưới dạng
class Logger(Filterer):
    # ...
    def getEffectiveLevel(self):
        logger = self
        while logger:
            if logger.level:
                return logger.level
            logger = logger.parent
        return NOTSET

    def isEnabledFor(self, level):
        try:
            return self._cache[level]
        except KeyError:
            _acquireLock()
            if self.manager.disable >= level:
                is_enabled = self._cache[level] = False
            else:
                is_enabled = self._cache[level] = level >= self.getEffectiveLevel()
            _releaseLock()
        return is_enabled
5 và đóng bộ đệm để giải phóng các tài nguyên hệ thống một cách rõ ràng.

Các lớp

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
10 và
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
11

Ở trên, chúng tôi đã hỏi câu hỏi, về việc lọc dựa trên cấp độ xảy ra ở đâu? Khi trả lời câu hỏi này, nó rất dễ bị phân tâm bởi các lớp

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
10 và
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
11. Nghịch lý thay, lọc dựa trên cấp độ cho các trường hợp
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12 và
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
13 xảy ra mà không có sự trợ giúp của các lớp
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
10 hoặc
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
11.

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
4

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
10 và
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
11 được thiết kế để cho phép bạn thêm các bộ lọc dựa trên chức năng bổ sung vào đầu bộ lọc dựa trên cấp độ được thực hiện theo mặc định. Tôi thích nghĩ về nó như là bộ lọc à la carte.

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
11 là lớp cơ sở cho
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12 và
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
13 vì cả hai lớp này đều đủ điều kiện nhận các bộ lọc tùy chỉnh bổ sung mà bạn chỉ định. Bạn thêm các phiên bản
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
10 vào chúng với
_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv
41 hoặc
_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv
42, đó là những gì
_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv
43 đề cập đến trong phương pháp sau:

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
5

Đưa ra một

_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv
02 (là một ví dụ
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
29),
_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv
46 trả về
_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv
47 hoặc
_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv
48 tùy thuộc vào việc bản ghi đó có ổn từ các bộ lọc lớp này hay không.

>>>

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
6

Tiếp theo, bạn có thể phân lớp

_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv
13 để làm cho
_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv
14 gọi là không có. Chúng tôi muốn xả
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
35 hoặc
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
76, nhưng không phải là bộ đệm trong bộ nhớ trong trường hợp này:

Bây giờ, hãy khai báo chính đối tượng bộ đệm và buộc nó là _nameToLevel = { 'CRITICAL': CRITICAL, 'FATAL': FATAL, 'ERROR': ERROR, 'WARN': WARNING, 'WARNING': WARNING, 'INFO': INFO, 'DEBUG': DEBUG, 'NOTSET': NOTSET, } def _checkLevel(level): if isinstance(level, int): rv = level elif str(level) == level: if level not in _nameToLevel: raise ValueError("Unknown level: %r" % level) rv = _nameToLevel[level] else: raise TypeError("Level not an integer or a valid string: %r" % level) return rv 09 cho trình xử lý tùy chỉnh của bạn với mức độ CRITICAL = 50 FATAL = CRITICAL ERROR = 40 WARNING = 30 WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0 24, sau đó buộc trình xử lý đó vào logger:

Chunk cuối cùng này là một minh họa khác về lọc dựa trên cấp độ.

Ba tin nhắn có cấp độ CRITICAL = 50 FATAL = CRITICAL ERROR = 40 WARNING = 30 WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0 23, _nameToLevel = { 'CRITICAL': CRITICAL, 'FATAL': FATAL, 'ERROR': ERROR, 'WARN': WARNING, 'WARNING': WARNING, 'INFO': INFO, 'DEBUG': DEBUG, 'NOTSET': NOTSET, } def _checkLevel(level): if isinstance(level, int): rv = level elif str(level) == level: if level not in _nameToLevel: raise ValueError("Unknown level: %r" % level) rv = _nameToLevel[level] else: raise TypeError("Level not an integer or a valid string: %r" % level) return rv 20 và class Logger(Filterer): # ... def getEffectiveLevel(self): logger = self while logger: if logger.level: return logger.level logger = logger.parent return NOTSET def isEnabledFor(self, level): try: return self._cache[level] except KeyError: _acquireLock() if self.manager.disable >= level: is_enabled = self._cache[level] = False else: is_enabled = self._cache[level] = level >= self.getEffectiveLevel() _releaseLock() return is_enabled 4 được truyền qua chuỗi. Lúc đầu, có vẻ như họ không đi đâu cả, nhưng hai người trong số họ làm. Tất cả ba người họ làm cho nó ra khỏi cổng từ CRITICAL = 50 FATAL = CRITICAL ERROR = 40 WARNING = 30 WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0 16 (có cấp độ CRITICAL = 50 FATAL = CRITICAL ERROR = 40 WARNING = 30 WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0 23).

Tuy nhiên, chỉ có hai trong số chúng được phát ra bởi người xử lý vì nó có mức độ

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
24 cao hơn, vượt quá
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
23. Cuối cùng, bạn nhận được toàn bộ nội dung của bộ đệm dưới dạng
class Logger(Filterer):
    # ...
    def getEffectiveLevel(self):
        logger = self
        while logger:
            if logger.level:
                return logger.level
            logger = logger.parent
        return NOTSET

    def isEnabledFor(self, level):
        try:
            return self._cache[level]
        except KeyError:
            _acquireLock()
            if self.manager.disable >= level:
                is_enabled = self._cache[level] = False
            else:
                is_enabled = self._cache[level] = level >= self.getEffectiveLevel()
            _releaseLock()
        return is_enabled
5 và đóng bộ đệm để giải phóng các tài nguyên hệ thống một cách rõ ràng.

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
7

Các lớp

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
10 và
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
11

  • Ở trên, chúng tôi đã hỏi câu hỏi, về việc lọc dựa trên cấp độ xảy ra ở đâu? Khi trả lời câu hỏi này, nó rất dễ bị phân tâm bởi các lớp

    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    10 và
    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    11. Nghịch lý thay, lọc dựa trên cấp độ cho các trường hợp
    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    12 và
    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    13 xảy ra mà không có sự trợ giúp của các lớp
    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    10 hoặc
    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    11.

  • Lần lượt đối tượng

    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    93 trở thành thuộc tính lớp cho lớp
    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    12. Điều này có nghĩa là tất cả các trường hợp của
    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    12 và bản thân lớp
    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    12, tất cả đều có thuộc tính
    _nameToLevel = {
        'CRITICAL': CRITICAL,
        'FATAL': FATAL,
        'ERROR': ERROR,
        'WARN': WARNING,
        'WARNING': WARNING,
        'INFO': INFO,
        'DEBUG': DEBUG,
        'NOTSET': NOTSET,
    }
    
    def _checkLevel(level):
        if isinstance(level, int):
            rv = level
        elif str(level) == level:
            if level not in _nameToLevel:
                raise ValueError("Unknown level: %r" % level)
            rv = _nameToLevel[level]
        else:
            raise TypeError("Level not an integer or a valid string: %r" % level)
        return rv
    
    73 là logger gốc. Đây là một ví dụ khác về mô hình giống như singleton đang được thi hành trong gói
    import logging
    import sys
    
    logger = logging.getLogger("pylog")
    logger.setLevel(logging.DEBUG)
    h2 = logging.FileHandler(filename="/tmp/records.log")
    h2.setLevel(logging.INFO)
    h2 = logging.StreamHandler(sys.stderr)
    h2.setLevel(logging.ERROR)
    logger.addHandler(h2)
    logger.addHandler(h2)
    logger.info("testing %d.. %d.. %d..", 1, 2, 3)
    
    5.class attribute for the
    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    12 class. This means that all instances of
    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    12, and the
    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    12 class itself, all have a
    _nameToLevel = {
        'CRITICAL': CRITICAL,
        'FATAL': FATAL,
        'ERROR': ERROR,
        'WARN': WARNING,
        'WARNING': WARNING,
        'INFO': INFO,
        'DEBUG': DEBUG,
        'NOTSET': NOTSET,
    }
    
    def _checkLevel(level):
        if isinstance(level, int):
            rv = level
        elif str(level) == level:
            if level not in _nameToLevel:
                raise ValueError("Unknown level: %r" % level)
            rv = _nameToLevel[level]
        else:
            raise TypeError("Level not an integer or a valid string: %r" % level)
        return rv
    
    73 attribute that is the root logger. This is another example of a singleton-like pattern being enforced in the
    import logging
    import sys
    
    logger = logging.getLogger("pylog")
    logger.setLevel(logging.DEBUG)
    h2 = logging.FileHandler(filename="/tmp/records.log")
    h2.setLevel(logging.INFO)
    h2 = logging.StreamHandler(sys.stderr)
    h2.setLevel(logging.ERROR)
    logger.addHandler(h2)
    logger.addHandler(h2)
    logger.info("testing %d.. %d.. %d..", 1, 2, 3)
    
    5 package.

  • Một ví dụ

    _nameToLevel = {
        'CRITICAL': CRITICAL,
        'FATAL': FATAL,
        'ERROR': ERROR,
        'WARN': WARNING,
        'WARNING': WARNING,
        'INFO': INFO,
        'DEBUG': DEBUG,
        'NOTSET': NOTSET,
    }
    
    def _checkLevel(level):
        if isinstance(level, int):
            rv = level
        elif str(level) == level:
            if level not in _nameToLevel:
                raise ValueError("Unknown level: %r" % level)
            rv = _nameToLevel[level]
        else:
            raise TypeError("Level not an integer or a valid string: %r" % level)
        return rv
    
    58 được đặt làm thuộc tính lớp ____276 cho
    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    12. Điều này cuối cùng đi vào chơi trong
    _nameToLevel = {
        'CRITICAL': CRITICAL,
        'FATAL': FATAL,
        'ERROR': ERROR,
        'WARN': WARNING,
        'WARNING': WARNING,
        'INFO': INFO,
        'DEBUG': DEBUG,
        'NOTSET': NOTSET,
    }
    
    def _checkLevel(level):
        if isinstance(level, int):
            rv = level
        elif str(level) == level:
            if level not in _nameToLevel:
                raise ValueError("Unknown level: %r" % level)
            rv = _nameToLevel[level]
        else:
            raise TypeError("Level not an integer or a valid string: %r" % level)
        return rv
    
    78.
    _nameToLevel = {
        'CRITICAL': CRITICAL,
        'FATAL': FATAL,
        'ERROR': ERROR,
        'WARN': WARNING,
        'WARNING': WARNING,
        'INFO': INFO,
        'DEBUG': DEBUG,
        'NOTSET': NOTSET,
    }
    
    def _checkLevel(level):
        if isinstance(level, int):
            rv = level
        elif str(level) == level:
            if level not in _nameToLevel:
                raise ValueError("Unknown level: %r" % level)
            rv = _nameToLevel[level]
        else:
            raise TypeError("Level not an integer or a valid string: %r" % level)
        return rv
    
    76 thực hiện tất cả việc tạo thuận lợi cho việc tìm kiếm các trình ghi nhật ký hiện có với tên
    _nameToLevel = {
        'CRITICAL': CRITICAL,
        'FATAL': FATAL,
        'ERROR': ERROR,
        'WARN': WARNING,
        'WARNING': WARNING,
        'INFO': INFO,
        'DEBUG': DEBUG,
        'NOTSET': NOTSET,
    }
    
    def _checkLevel(level):
        if isinstance(level, int):
            rv = level
        elif str(level) == level:
            if level not in _nameToLevel:
                raise ValueError("Unknown level: %r" % level)
            rv = _nameToLevel[level]
        else:
            raise TypeError("Level not an integer or a valid string: %r" % level)
        return rv
    
    80 và tạo chúng nếu chúng không tồn tại.

Phân cấp logger

Tất cả mọi thứ là một đứa trẻ của

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
93 trong không gian tên logger, và ý tôi là tất cả mọi thứ. Điều đó bao gồm các trình ghi nhật ký mà bạn chỉ định bản thân cũng như những người từ các thư viện của bên thứ ba mà bạn nhập.

Hãy nhớ trước đó làm thế nào

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
85 cho các trường hợp
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
16 của chúng tôi là 30 (
_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv
20) mặc dù chúng tôi đã không đặt nó một cách rõ ràng? Điều đó bởi vì logger gốc nằm ở đầu phân cấp và cấp độ của nó là một dự phòng nếu bất kỳ logger lồng nhau nào có mức null là
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
91:

>>>

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
8

Logic tương tự áp dụng cho việc tìm kiếm một trình xử lý logger. Việc tìm kiếm thực sự là một tìm kiếm theo thứ tự ngược lại trên cây của cha mẹ logger.

Một thiết kế đa tay

Phân cấp logger có vẻ gọn gàng trong lý thuyết, nhưng nó có lợi như thế nào trong thực tế?

Hãy cùng nghỉ ngơi khi khám phá mã

import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5 và đưa vào việc viết ứng dụng nhỏ của riêng chúng tôi, một người tận dụng phân cấp logger theo cách giảm mã nồi hơi và giữ cho mọi thứ có thể mở rộng nếu dự án CodeBase phát triển.

Ở đây, cấu trúc dự án:

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
9

Don Tiết lo lắng về các chức năng chính của ứng dụng trong

_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv
87 và
_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv
88. Những gì chúng tôi chú ý nhiều hơn ở đây là sự tương tác trong các đối tượng
import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5 giữa các mô -đun trong
_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv
90.

Trong trường hợp này, hãy nói rằng bạn muốn thiết kế một thiết lập ghi nhật ký nhiều lần:

  • Mỗi mô -đun nhận được

    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    16 với nhiều trình xử lý.

  • Một số trình xử lý được chia sẻ giữa các trường hợp

    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    16 khác nhau trong các mô -đun khác nhau. Các trình xử lý này chỉ quan tâm đến bộ lọc dựa trên cấp độ, chứ không phải mô-đun trong đó bản ghi nhật ký phát ra từ. Có một trình xử lý cho các tin nhắn
    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    23, một cho
    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    24, một cho
    _nameToLevel = {
        'CRITICAL': CRITICAL,
        'FATAL': FATAL,
        'ERROR': ERROR,
        'WARN': WARNING,
        'WARNING': WARNING,
        'INFO': INFO,
        'DEBUG': DEBUG,
        'NOTSET': NOTSET,
    }
    
    def _checkLevel(level):
        if isinstance(level, int):
            rv = level
        elif str(level) == level:
            if level not in _nameToLevel:
                raise ValueError("Unknown level: %r" % level)
            rv = _nameToLevel[level]
        else:
            raise TypeError("Level not an integer or a valid string: %r" % level)
        return rv
    
    20, v.v.

  • Mỗi

    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    16 cũng được gắn với một trình xử lý bổ sung khác mà chỉ nhận được các trường hợp ____129 từ Lone
    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    16 đó. Bạn có thể gọi đây là một trình xử lý tệp dựa trên mô-đun.

Trực quan, những gì chúng tôi chụp cho sẽ trông giống như thế này:

Hướng dẫn python performance logging - ghi nhật ký hiệu suất python
Một thiết kế ghi nhật ký nhiều người (hình ảnh: Real Python)

Hai đối tượng màu ngọc lam là các trường hợp của

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12, được thiết lập với
import threading

_lock = threading.RLock()

def _acquireLock():
     if _lock:
        _lock.acquire()

def _releaseLock():
    if _lock:
        _lock.release()
00 cho mỗi mô -đun trong một gói. Mọi thứ khác là một ví dụ
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
13.

Suy nghĩ đằng sau thiết kế này là nó đã được ngăn cách gọn gàng. Bạn có thể nhìn thuận tiện nhìn vào các tin nhắn đến từ một logger duy nhất hoặc xem tin nhắn ở một cấp độ nhất định và ở trên đến từ bất kỳ logger hoặc mô -đun nào.

Các thuộc tính của hệ thống phân cấp logger làm cho nó phù hợp để thiết lập bố cục tay cầm logger đa nhân này. Điều đó nghĩa là gì? Ở đây, một lời giải thích ngắn gọn từ tài liệu Django:

Tại sao hệ thống phân cấp lại quan trọng? Vâng, bởi vì loggers có thể được thiết lập để tuyên truyền các cuộc gọi đăng nhập của họ đến cha mẹ của họ. Theo cách này, bạn có thể xác định một bộ xử lý duy nhất ở gốc của cây logger và nắm bắt tất cả các cuộc gọi ghi nhật ký trong phần cây con của loggers. Một trình xử lý ghi nhật ký được xác định trong không gian tên

import threading

_lock = threading.RLock()

def _acquireLock():
     if _lock:
        _lock.acquire()

def _releaseLock():
    if _lock:
        _lock.release()
02 sẽ bắt tất cả các tin nhắn ghi nhật ký được phát hành trên loggers
import threading

_lock = threading.RLock()

def _acquireLock():
     if _lock:
        _lock.acquire()

def _releaseLock():
    if _lock:
        _lock.release()
03 và
import threading

_lock = threading.RLock()

def _acquireLock():
     if _lock:
        _lock.acquire()

def _releaseLock():
    if _lock:
        _lock.release()
04. (Nguồn)

Thuật ngữ tuyên truyền đề cập đến cách một logger tiếp tục bước lên chuỗi cha mẹ của mình đang tìm kiếm người xử lý. Thuộc tính

import threading

_lock = threading.RLock()

def _acquireLock():
     if _lock:
        _lock.acquire()

def _releaseLock():
    if _lock:
        _lock.release()
05 là
_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv
47 cho một phiên bản
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12 theo mặc định:propagate refers to how a logger keeps walking up its chain of parents looking for handlers. The
import threading

_lock = threading.RLock()

def _acquireLock():
     if _lock:
        _lock.acquire()

def _releaseLock():
    if _lock:
        _lock.release()
05 attribute is
_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv
47 for a
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12 instance by default:

>>>

_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv
0

Logic tương tự áp dụng cho việc tìm kiếm một trình xử lý logger. Việc tìm kiếm thực sự là một tìm kiếm theo thứ tự ngược lại trên cây của cha mẹ logger.

_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv
1

Một thiết kế đa tay

Phân cấp logger có vẻ gọn gàng trong lý thuyết, nhưng nó có lợi như thế nào trong thực tế?

Hãy cùng nghỉ ngơi khi khám phá mã
import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5 và đưa vào việc viết ứng dụng nhỏ của riêng chúng tôi, một người tận dụng phân cấp logger theo cách giảm mã nồi hơi và giữ cho mọi thứ có thể mở rộng nếu dự án CodeBase phát triển.
Ở đây, cấu trúc dự án:
Don Tiết lo lắng về các chức năng chính của ứng dụng trong
_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv
87 và
_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv
88. Những gì chúng tôi chú ý nhiều hơn ở đây là sự tương tác trong các đối tượng
import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5 giữa các mô -đun trong
_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv
90.
Trong trường hợp này, hãy nói rằng bạn muốn thiết kế một thiết lập ghi nhật ký nhiều lần:
Mỗi mô -đun nhận được
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
16 với nhiều trình xử lý.
Một số trình xử lý được chia sẻ giữa các trường hợp
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
16 khác nhau trong các mô -đun khác nhau. Các trình xử lý này chỉ quan tâm đến bộ lọc dựa trên cấp độ, chứ không phải mô-đun trong đó bản ghi nhật ký phát ra từ. Có một trình xử lý cho các tin nhắn
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
23, một cho
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
24, một cho
_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv
20, v.v.
Mỗi
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
16 cũng được gắn với một trình xử lý bổ sung khác mà chỉ nhận được các trường hợp ____129 từ Lone
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
16 đó. Bạn có thể gọi đây là một trình xử lý tệp dựa trên mô-đun.
Trực quan, những gì chúng tôi chụp cho sẽ trông giống như thế này:

Một thiết kế ghi nhật ký nhiều người (hình ảnh: Real Python)

Hai đối tượng màu ngọc lam là các trường hợp của

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12, được thiết lập với
import threading

_lock = threading.RLock()

def _acquireLock():
     if _lock:
        _lock.acquire()

def _releaseLock():
    if _lock:
        _lock.release()
00 cho mỗi mô -đun trong một gói. Mọi thứ khác là một ví dụ
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
13.

_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv
2

Mô -đun này được nhập khi gói

import threading

_lock = threading.RLock()

def _acquireLock():
     if _lock:
        _lock.acquire()

def _releaseLock():
    if _lock:
        _lock.release()
02 được nhập. Bạn thêm một trình xử lý cho mỗi cấp độ trong
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
23 đến
class Logger(Filterer):
    # ...
    def getEffectiveLevel(self):
        logger = self
        while logger:
            if logger.level:
                return logger.level
            logger = logger.parent
        return NOTSET

    def isEnabledFor(self, level):
        try:
            return self._cache[level]
        except KeyError:
            _acquireLock()
            if self.manager.disable >= level:
                is_enabled = self._cache[level] = False
            else:
                is_enabled = self._cache[level] = level >= self.getEffectiveLevel()
            _releaseLock()
        return is_enabled
4, sau đó gắn nó vào một logger duy nhất ở đầu phân cấp.

Bạn cũng xác định chức năng tiện ích thêm một

import threading

_lock = threading.RLock()

def _acquireLock():
     if _lock:
        _lock.acquire()

def _releaseLock():
    if _lock:
        _lock.release()
32 vào logger, trong đó
import threading

_lock = threading.RLock()

def _acquireLock():
     if _lock:
        _lock.acquire()

def _releaseLock():
    if _lock:
        _lock.release()
33 của trình xử lý tương ứng với tên mô -đun nơi xác định logger. (Điều này giả sử logger được xác định với
import threading

_lock = threading.RLock()

def _acquireLock():
     if _lock:
        _lock.acquire()

def _releaseLock():
    if _lock:
        _lock.release()
12.)

Sau đó, bạn có thể thêm một số thiết lập logger nồi hơi tối thiểu trong

_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv
88 và
_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv
87. Lưu ý rằng bạn chỉ cần thêm một trình xử lý bổ sung với
import threading

_lock = threading.RLock()

def _acquireLock():
     if _lock:
        _lock.acquire()

def _releaseLock():
    if _lock:
        _lock.release()
37 từ
(Pdb) l
1514                     exc_info = (type(exc_info), exc_info, exc_info.__traceback__)
1515                 elif not isinstance(exc_info, tuple):
1516                     exc_info = sys.exc_info()
1517             record = self.makeRecord(self.name, level, fn, lno, msg, args,
1518                                      exc_info, func, extra, sinfo)
1519 ->          self.handle(record)
1520
1521         def handle(self, record):
1522             """
1523             Call the handlers for the specified record.
1524
(Pdb) from pprint import pprint
(Pdb) pprint(vars(record))
{'args': (),
 'created': 1550671851.660067,
 'exc_info': None,
 'exc_text': None,
 'filename': '',
 'funcName': 'f',
 'levelname': 'ERROR',
 'levelno': 40,
 'lineno': 2,
 'module': '',
 'msecs': 660.067081451416,
 'msg': 'bad vibes',
 'name': 'root',
 'pathname': '',
 'process': 2360,
 'processName': 'MainProcess',
 'relativeCreated': 295145.5490589142,
 'stack_info': None,
 'thread': 4372293056,
 'threadName': 'MainThread'}
6. Bạn không cần phải lo lắng về các trình xử lý định hướng cấp độ vì họ đã được thêm vào logger cha mẹ của họ có tên
import threading

_lock = threading.RLock()

def _acquireLock():
     if _lock:
        _lock.acquire()

def _releaseLock():
    if _lock:
        _lock.release()
19:

_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv
3

Ở đây, ____ ____287:

_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv
4

Hãy cùng xem cách tất cả những điều này hoạt động cùng nhau từ một phiên Python mới:

>>>

_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv
5

Bạn sẽ thấy trong các tệp nhật ký kết quả mà hệ thống lọc của chúng tôi hoạt động như dự định. Trình xử lý định hướng mô-đun hướng một logger đến một tệp cụ thể, trong khi trình xử lý định hướng cấp độ trực tiếp nhiều trình ghi nhật ký đến một tệp khác:

_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv
6

Một nhược điểm đáng nói là thiết kế này giới thiệu rất nhiều dự phòng. Một ví dụ

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
29 có thể đi đến không dưới sáu tệp. Đó cũng là một số lượng tệp I/O không đáng kể có thể cộng vào một ứng dụng quan trọng hiệu suất.

Bây giờ, bạn đã thấy một ví dụ thực tế, hãy để chuyển đổi bánh răng và đi sâu vào một nguồn nhầm lẫn có thể xảy ra trong

import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5.

Tại sao không có tin nhắn nhật ký của tôi đi đâu? Tình trạng khó xử

Có hai tình huống phổ biến với

import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5 khi nó dễ bị vấp ngã:

  1. Bạn đã đăng nhập một tin nhắn dường như không đi đến đâu và bạn không chắc tại sao.
  2. Thay vì bị đàn áp, một tin nhắn nhật ký xuất hiện ở một nơi mà bạn đã không mong đợi.

Mỗi trong số này có một hoặc hai lý do thường được liên kết với nó.

Bạn đã đăng nhập một tin nhắn dường như không đi đến đâu và bạn không chắc tại sao.

Thay vì bị đàn áp, một tin nhắn nhật ký xuất hiện ở một nơi mà bạn đã không mong đợi.effective level of a logger for which you don’t otherwise set a custom level is

_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv
20, because a logger will walk up its hierarchy until it finds the root logger with its own
_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv
20 level:

>>>

_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv
7

Bạn sẽ thấy trong các tệp nhật ký kết quả mà hệ thống lọc của chúng tôi hoạt động như dự định. Trình xử lý định hướng mô-đun hướng một logger đến một tệp cụ thể, trong khi trình xử lý định hướng cấp độ trực tiếp nhiều trình ghi nhật ký đến một tệp khác:

Thay vì bị đàn áp, một tin nhắn nhật ký xuất hiện ở một nơi mà bạn đã không mong đợi.

Mỗi trong số này có một hoặc hai lý do thường được liên kết với nó.

Don Tiết quên rằng mức độ hiệu quả của một logger mà bạn không nên đặt cấp độ tùy chỉnh là

_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv
20, bởi vì một bộ ghi sẽ đi lên thứ bậc của nó cho đến khi tìm thấy bộ ghi gốc với mức ____220 của riêng mình:

_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv
8

Vì mặc định này, cuộc gọi

import threading

_lock = threading.RLock()

def _acquireLock():
     if _lock:
        _lock.acquire()

def _releaseLock():
    if _lock:
        _lock.release()
46 không đi đến đâu.

_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv
9

Khi bạn xác định

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
16 của mình ở trên, bạn đã không thêm bất kỳ trình xử lý nào vào đó. Vì vậy, tại sao nó viết vào bảng điều khiển?

Lý do cho điều này là

import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5 Sneaking sử dụng một trình xử lý có tên là
import threading

_lock = threading.RLock()

def _acquireLock():
     if _lock:
        _lock.acquire()

def _releaseLock():
    if _lock:
        _lock.release()
49 ghi vào
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
35 nếu không tìm thấy người xử lý nào khác:

Điều này khởi động khi một logger đi tìm trình xử lý của nó:

>>>

import threading

_lock = threading.RLock()

def _acquireLock():
     if _lock:
        _lock.acquire()

def _releaseLock():
    if _lock:
        _lock.release()
0

Bạn sẽ thấy trong các tệp nhật ký kết quả mà hệ thống lọc của chúng tôi hoạt động như dự định. Trình xử lý định hướng mô-đun hướng một logger đến một tệp cụ thể, trong khi trình xử lý định hướng cấp độ trực tiếp nhiều trình ghi nhật ký đến một tệp khác:

Một nhược điểm đáng nói là thiết kế này giới thiệu rất nhiều dự phòng. Một ví dụ

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
29 có thể đi đến không dưới sáu tệp. Đó cũng là một số lượng tệp I/O không đáng kể có thể cộng vào một ứng dụng quan trọng hiệu suất.

>>>

import threading

_lock = threading.RLock()

def _acquireLock():
     if _lock:
        _lock.acquire()

def _releaseLock():
    if _lock:
        _lock.release()
1

Bạn sẽ thấy trong các tệp nhật ký kết quả mà hệ thống lọc của chúng tôi hoạt động như dự định. Trình xử lý định hướng mô-đun hướng một logger đến một tệp cụ thể, trong khi trình xử lý định hướng cấp độ trực tiếp nhiều trình ghi nhật ký đến một tệp khác:

>>>

import threading

_lock = threading.RLock()

def _acquireLock():
     if _lock:
        _lock.acquire()

def _releaseLock():
    if _lock:
        _lock.release()
2

Bạn sẽ thấy trong các tệp nhật ký kết quả mà hệ thống lọc của chúng tôi hoạt động như dự định. Trình xử lý định hướng mô-đun hướng một logger đến một tệp cụ thể, trong khi trình xử lý định hướng cấp độ trực tiếp nhiều trình ghi nhật ký đến một tệp khác:

Một nhược điểm đáng nói là thiết kế này giới thiệu rất nhiều dự phòng. Một ví dụ

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
29 có thể đi đến không dưới sáu tệp. Đó cũng là một số lượng tệp I/O không đáng kể có thể cộng vào một ứng dụng quan trọng hiệu suất.

>>>

import threading

_lock = threading.RLock()

def _acquireLock():
     if _lock:
        _lock.acquire()

def _releaseLock():
    if _lock:
        _lock.release()
3

Bạn sẽ thấy trong các tệp nhật ký kết quả mà hệ thống lọc của chúng tôi hoạt động như dự định. Trình xử lý định hướng mô-đun hướng một logger đến một tệp cụ thể, trong khi trình xử lý định hướng cấp độ trực tiếp nhiều trình ghi nhật ký đến một tệp khác:lazily rather than greedily. Here’s what that means.

Một nhược điểm đáng nói là thiết kế này giới thiệu rất nhiều dự phòng. Một ví dụ

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
29 có thể đi đến không dưới sáu tệp. Đó cũng là một số lượng tệp I/O không đáng kể có thể cộng vào một ứng dụng quan trọng hiệu suất.

import threading

_lock = threading.RLock()

def _acquireLock():
     if _lock:
        _lock.acquire()

def _releaseLock():
    if _lock:
        _lock.release()
4

Bây giờ, bạn đã thấy một ví dụ thực tế, hãy để chuyển đổi bánh răng và đi sâu vào một nguồn nhầm lẫn có thể xảy ra trong

import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5.

Tại sao không có tin nhắn nhật ký của tôi đi đâu? Tình trạng khó xử

import threading

_lock = threading.RLock()

def _acquireLock():
     if _lock:
        _lock.acquire()

def _releaseLock():
    if _lock:
        _lock.release()
5

Có hai tình huống phổ biến với

import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5 khi nó dễ bị vấp ngã:

Vì sao vấn đề này? Các cuộc gọi ghi nhật ký lặp đi lặp lại có thể làm giảm hiệu suất thời gian chạy một chút, nhưng gói

import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5 thực hiện tốt nhất để kiểm soát điều đó và kiểm tra nó. Bằng cách không hợp nhất chuỗi định dạng với các đối số của nó ngay lập tức,
import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5 đang trì hoãn định dạng chuỗi cho đến khi
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
29 được yêu cầu bởi
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
13.

Điều này xảy ra trong ____378, vì vậy chỉ sau khi

import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5 thấy rằng
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
29 sẽ thực sự được chuyển cho một người xử lý, nó mới trở thành bản thân được hợp nhất đầy đủ.

Tất cả những gì có nghĩa là gói

import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5 làm cho một số tối ưu hóa hiệu suất rất tinh chỉnh ở đúng nơi. Điều này có vẻ giống như Minutia, nhưng nếu bạn thực hiện cùng một
import threading

_lock = threading.RLock()

def _acquireLock():
     if _lock:
        _lock.acquire()

def _releaseLock():
    if _lock:
        _lock.release()
82 gọi một triệu lần trong một vòng lặp và
import threading

_lock = threading.RLock()

def _acquireLock():
     if _lock:
        _lock.acquire()

def _releaseLock():
    if _lock:
        _lock.release()
69 là các cuộc gọi chức năng, thì bản chất lười biếng của cách
import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5 định dạng chuỗi có thể tạo ra sự khác biệt.

Trước khi thực hiện bất kỳ sự hợp nhất nào của

import threading

_lock = threading.RLock()

def _acquireLock():
     if _lock:
        _lock.acquire()

def _releaseLock():
    if _lock:
        _lock.release()
60 và
import threading

_lock = threading.RLock()

def _acquireLock():
     if _lock:
        _lock.acquire()

def _releaseLock():
    if _lock:
        _lock.release()
69, một ví dụ
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12 sẽ kiểm tra
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
84 của nó để xem liệu việc hợp nhất có nên được thực hiện ngay từ đầu không.

Chức năng so với phương pháp

Về phía dưới của

(Pdb) l
1514                     exc_info = (type(exc_info), exc_info, exc_info.__traceback__)
1515                 elif not isinstance(exc_info, tuple):
1516                     exc_info = sys.exc_info()
1517             record = self.makeRecord(self.name, level, fn, lno, msg, args,
1518                                      exc_info, func, extra, sinfo)
1519 ->          self.handle(record)
1520
1521         def handle(self, record):
1522             """
1523             Call the handlers for the specified record.
1524
(Pdb) from pprint import pprint
(Pdb) pprint(vars(record))
{'args': (),
 'created': 1550671851.660067,
 'exc_info': None,
 'exc_text': None,
 'filename': '',
 'funcName': 'f',
 'levelname': 'ERROR',
 'levelno': 40,
 'lineno': 2,
 'module': '',
 'msecs': 660.067081451416,
 'msg': 'bad vibes',
 'name': 'root',
 'pathname': '',
 'process': 2360,
 'processName': 'MainProcess',
 'relativeCreated': 295145.5490589142,
 'stack_info': None,
 'thread': 4372293056,
 'threadName': 'MainThread'}
5, hãy đặt các chức năng cấp độ mô-đun được quảng cáo lên phía trước trong API công khai của
import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5. Bạn đã thấy các phương pháp
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12 như
import threading

_lock = threading.RLock()

def _acquireLock():
     if _lock:
        _lock.acquire()

def _releaseLock():
    if _lock:
        _lock.release()
46,
import threading

_lock = threading.RLock()

def _acquireLock():
     if _lock:
        _lock.acquire()

def _releaseLock():
    if _lock:
        _lock.release()
93 và
import threading

_lock = threading.RLock()

def _acquireLock():
     if _lock:
        _lock.acquire()

def _releaseLock():
    if _lock:
        _lock.release()
94. Các chức năng cấp cao nhất là các trình bao bọc xung quanh các phương thức tương ứng cùng tên, nhưng chúng có hai tính năng quan trọng:

  1. Họ luôn gọi phương thức tương ứng của họ từ logger gốc,

    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    93.

  2. Trước khi gọi các phương thức logger gốc, họ gọi

    import threading
    
    _lock = threading.RLock()
    
    def _acquireLock():
         if _lock:
            _lock.acquire()
    
    def _releaseLock():
        if _lock:
            _lock.release()
    
    55 không có đối số nếu
    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    93 không có trình xử lý. Như bạn đã thấy trước đó, đó là cuộc gọi này đặt ra một trình xử lý
    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    76 cho bộ ghi gốc.

Để minh họa, ở đây, ____ ____151:

import threading

_lock = threading.RLock()

def _acquireLock():
     if _lock:
        _lock.acquire()

def _releaseLock():
    if _lock:
        _lock.release()
6

Bạn sẽ tìm thấy cùng một mẫu cho

import threading

_lock = threading.RLock()

def _acquireLock():
     if _lock:
        _lock.acquire()

def _releaseLock():
    if _lock:
        _lock.release()
82,
import threading

_lock = threading.RLock()

def _acquireLock():
     if _lock:
        _lock.acquire()

def _releaseLock():
    if _lock:
        _lock.release()
53 và các mẫu khác là tốt. Truy tìm chuỗi các lệnh là thú vị. Cuối cùng, bạn sẽ kết thúc ở cùng một nơi, đó là nơi được gọi là
object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
02 bên trong.

Các cuộc gọi đến

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
03,
object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
04,
object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
05 và các chức năng dựa trên cấp độ khác tất cả các chức năng đến đây.
object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
06 chủ yếu có hai mục đích:

  1. Gọi

    object
    │
    ├── LogRecord
    ├── Filterer
    │   ├── Logger
    │   │   └── RootLogger
    │   └── Handler
    │       ├── StreamHandler
    │       └── NullHandler
    ├── Filter
    └── Manager
    
    07: Tạo một thể hiện
    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    29 từ
    import threading
    
    _lock = threading.RLock()
    
    def _acquireLock():
         if _lock:
            _lock.acquire()
    
    def _releaseLock():
        if _lock:
            _lock.release()
    
    60 và các đối số khác mà bạn chuyển cho nó.
    Make a
    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    29 instance from the
    import threading
    
    _lock = threading.RLock()
    
    def _acquireLock():
         if _lock:
            _lock.acquire()
    
    def _releaseLock():
        if _lock:
            _lock.release()
    
    60 and other arguments you pass to it.

  2. Gọi

    object
    │
    ├── LogRecord
    ├── Filterer
    │   ├── Logger
    │   │   └── RootLogger
    │   └── Handler
    │       ├── StreamHandler
    │       └── NullHandler
    ├── Filter
    └── Manager
    
    10: Điều này xác định những gì thực sự được thực hiện với hồ sơ. Nó được gửi ở đâu? Nó làm cho nó ở đó hoặc được lọc ra? This determines what actually gets done with the record. Where does it get sent? Does it make it there or get filtered out?

Ở đây, toàn bộ quá trình trong một sơ đồ:

Hướng dẫn python performance logging - ghi nhật ký hiệu suất python
Nội bộ của một cuộc gọi đăng nhập (hình ảnh: Python thật)

Bạn cũng có thể theo dõi ngăn xếp cuộc gọi với

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
52.

>>>

import threading

_lock = threading.RLock()

def _acquireLock():
     if _lock:
        _lock.acquire()

def _releaseLock():
    if _lock:
        _lock.release()
7

object │ ├── LogRecord ├── Filterer │ ├── Logger │ │ └── RootLogger │ └── Handler │ ├── StreamHandler │ └── NullHandler ├── Filter └── Manager 12 thực sự làm gì?

Cũng ẩn trong phần này của mã nguồn là cấp cao nhất

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
12, kết thúc
object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
14:

import threading

_lock = threading.RLock()

def _acquireLock():
     if _lock:
        _lock.acquire()

def _releaseLock():
    if _lock:
        _lock.release()
8

Đây là điểm nhập cảnh để thực thi thiết kế Singleton Logger:

  • Nếu bạn chỉ định

    object
    │
    ├── LogRecord
    ├── Filterer
    │   ├── Logger
    │   │   └── RootLogger
    │   └── Handler
    │       ├── StreamHandler
    │       └── NullHandler
    ├── Filter
    └── Manager
    
    15, thì
    object
    │
    ├── LogRecord
    ├── Filterer
    │   ├── Logger
    │   │   └── RootLogger
    │   └── Handler
    │       ├── StreamHandler
    │       └── NullHandler
    ├── Filter
    └── Manager
    
    16 bên dưới sẽ tra cứu
    class Logger(Filterer):
        # ...
        def getEffectiveLevel(self):
            logger = self
            while logger:
                if logger.level:
                    return logger.level
                logger = logger.parent
            return NOTSET
    
        def isEnabledFor(self, level):
            try:
                return self._cache[level]
            except KeyError:
                _acquireLock()
                if self.manager.disable >= level:
                    is_enabled = self._cache[level] = False
                else:
                    is_enabled = self._cache[level] = level >= self.getEffectiveLevel()
                _releaseLock()
            return is_enabled
    
    8 trên chuỗi
    object
    │
    ├── LogRecord
    ├── Filterer
    │   ├── Logger
    │   │   └── RootLogger
    │   └── Handler
    │       ├── StreamHandler
    │       └── NullHandler
    ├── Filter
    └── Manager
    
    15. Những gì điều này xuất hiện là một tra cứu trong
    object
    │
    ├── LogRecord
    ├── Filterer
    │   ├── Logger
    │   │   └── RootLogger
    │   └── Handler
    │       ├── StreamHandler
    │       └── NullHandler
    ├── Filter
    └── Manager
    
    19 của
    object
    │
    ├── LogRecord
    ├── Filterer
    │   ├── Logger
    │   │   └── RootLogger
    │   └── Handler
    │       ├── StreamHandler
    │       └── NullHandler
    ├── Filter
    └── Manager
    
    20. Đây là một từ điển của tất cả các trình ghi nhật ký đã đăng ký, bao gồm các trường hợp
    object
    │
    ├── LogRecord
    ├── Filterer
    │   ├── Logger
    │   │   └── RootLogger
    │   └── Handler
    │       ├── StreamHandler
    │       └── NullHandler
    ├── Filter
    └── Manager
    
    21 trung gian được tạo khi bạn tham chiếu một logger từ xa trong hệ thống phân cấp trước khi tham khảo cha mẹ của nó.

  • Nếu không,

    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    93 được trả lại. Chỉ có một ____ 193, ví dụ của
    _nameToLevel = {
        'CRITICAL': CRITICAL,
        'FATAL': FATAL,
        'ERROR': ERROR,
        'WARN': WARNING,
        'WARNING': WARNING,
        'INFO': INFO,
        'DEBUG': DEBUG,
        'NOTSET': NOTSET,
    }
    
    def _checkLevel(level):
        if isinstance(level, int):
            rv = level
        elif str(level) == level:
            if level not in _nameToLevel:
                raise ValueError("Unknown level: %r" % level)
            rv = _nameToLevel[level]
        else:
            raise TypeError("Level not an integer or a valid string: %r" % level)
        return rv
    
    68 đã thảo luận ở trên.

Tính năng này là những gì nằm đằng sau một mẹo có thể cho phép bạn nhìn trộm tất cả các loggers đã đăng ký:

>>>

import threading

_lock = threading.RLock()

def _acquireLock():
     if _lock:
        _lock.acquire()

def _releaseLock():
    if _lock:
        _lock.release()
9

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
12 thực sự làm gì?

Cũng ẩn trong phần này của mã nguồn là cấp cao nhất

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
12, kết thúc
object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
14:

Đây là điểm nhập cảnh để thực thi thiết kế Singleton Logger:

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
0

Nếu bạn chỉ định

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
15, thì
object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
16 bên dưới sẽ tra cứu
class Logger(Filterer):
    # ...
    def getEffectiveLevel(self):
        logger = self
        while logger:
            if logger.level:
                return logger.level
            logger = logger.parent
        return NOTSET

    def isEnabledFor(self, level):
        try:
            return self._cache[level]
        except KeyError:
            _acquireLock()
            if self.manager.disable >= level:
                is_enabled = self._cache[level] = False
            else:
                is_enabled = self._cache[level] = level >= self.getEffectiveLevel()
            _releaseLock()
        return is_enabled
8 trên chuỗi
object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
15. Những gì điều này xuất hiện là một tra cứu trong
object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
19 của
object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
20. Đây là một từ điển của tất cả các trình ghi nhật ký đã đăng ký, bao gồm các trường hợp
object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
21 trung gian được tạo khi bạn tham chiếu một logger từ xa trong hệ thống phân cấp trước khi tham khảo cha mẹ của nó.

Nếu không,

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
93 được trả lại. Chỉ có một ____ 193, ví dụ của
_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv
68 đã thảo luận ở trên.

>>>

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
1

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
12 thực sự làm gì?

Thư viện vs đăng nhập ứng dụng: object │ ├── LogRecord ├── Filterer │ ├── Logger │ │ └── RootLogger │ └── Handler │ ├── StreamHandler │ └── NullHandler ├── Filter └── Manager 42 là gì?

Điều đó đưa chúng ta đến hàng trăm dòng cuối cùng trong nguồn

(Pdb) l
1514                     exc_info = (type(exc_info), exc_info, exc_info.__traceback__)
1515                 elif not isinstance(exc_info, tuple):
1516                     exc_info = sys.exc_info()
1517             record = self.makeRecord(self.name, level, fn, lno, msg, args,
1518                                      exc_info, func, extra, sinfo)
1519 ->          self.handle(record)
1520
1521         def handle(self, record):
1522             """
1523             Call the handlers for the specified record.
1524
(Pdb) from pprint import pprint
(Pdb) pprint(vars(record))
{'args': (),
 'created': 1550671851.660067,
 'exc_info': None,
 'exc_text': None,
 'filename': '',
 'funcName': 'f',
 'levelname': 'ERROR',
 'levelno': 40,
 'lineno': 2,
 'module': '',
 'msecs': 660.067081451416,
 'msg': 'bad vibes',
 'name': 'root',
 'pathname': '',
 'process': 2360,
 'processName': 'MainProcess',
 'relativeCreated': 295145.5490589142,
 'stack_info': None,
 'thread': 4372293056,
 'threadName': 'MainThread'}
5, trong đó
object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
42 được xác định. Ở đây, định nghĩa trong tất cả vinh quang của nó:

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
2

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
42 là tất cả về sự khác biệt giữa việc đăng nhập vào thư viện so với một ứng dụng. Hãy để xem điều đó có nghĩa là gì.

Một thư viện là một gói Python có thể tổng quát, có thể khái quát, dành cho người dùng khác để cài đặt và thiết lập. Nó được xây dựng bởi một nhà phát triển với mục đích rõ ràng là được phân phối cho người dùng. Các ví dụ bao gồm các dự án nguồn mở phổ biến như Numpy,

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
46 và
object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
47.library is an extensible, generalizable Python package that is intended for other users to install and set up. It is built by a developer with the express purpose of being distributed to users. Examples include popular open-source projects like NumPy,
object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
46, and
object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
47.

Một ứng dụng (hoặc ứng dụng hoặc chương trình) được thiết kế cho mục đích cụ thể hơn và một bộ người dùng nhỏ hơn nhiều (có thể chỉ là một người dùng). Nó có một chương trình hoặc bộ chương trình được người dùng điều chỉnh cao để thực hiện một loạt mọi thứ. Một ví dụ về một ứng dụng là một ứng dụng Django nằm phía sau một trang web. Các ứng dụng thường sử dụng thư viện (

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
48) và các công cụ chúng chứa.application (or app, or program) is designed for a more specific purpose and a much smaller set of users (possibly just one user). It’s a program or set of programs highly tailored by the user to do a limited set of things. An example of an application is a Django app that sits behind a web page. Applications commonly use (
object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
48) libraries and the tools they contain.

Khi nói đến việc ghi nhật ký, có các thực tiễn tốt nhất khác nhau trong thư viện so với một ứng dụng.

Đó là nơi mà

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
42 phù hợp. Nó về cơ bản là một lớp sở hữu không có gì.

Nếu bạn đang viết một thư viện Python, bạn thực sự cần phải thực hiện một phần thiết lập tối giản này trong gói của bạn ____ ____ ____76:

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
3

Điều này phục vụ hai mục đích quan trọng.

Đầu tiên, một bộ ghi thư viện được khai báo với

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
51 (không có bất kỳ cấu hình nào khác) sẽ đăng nhập vào
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
35 theo mặc định, ngay cả khi đó không phải là những gì người dùng cuối muốn. Điều này có thể được mô tả như là một cách tiếp cận từ chối, trong đó người dùng cuối của thư viện phải đi vào và vô hiệu hóa việc đăng nhập vào bảng điều khiển của họ nếu họ không muốn nó.

Thay vào đó, trí tuệ thông thường cho biết sử dụng cách tiếp cận chọn tham gia thay thế: don lồng phát ra bất kỳ thông báo nhật ký nào theo mặc định và để người dùng cuối của thư viện xác định xem họ có muốn định cấu hình thêm trình ghi nhật ký thư viện và thêm người xử lý cho họ không. Ở đây, triết lý mà tác giả của gói

import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5, Vinay Sajip: Vinay Sajip:

Thư viện của bên thứ ba sử dụng

import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5 không nên phun ra đầu ra ghi nhật ký theo mặc định mà không thể mong muốn bởi nhà phát triển/người dùng ứng dụng sử dụng nó. (Nguồn)

Điều này để lại cho người dùng thư viện, không phải nhà phát triển thư viện, để gọi các phương thức tăng dần như

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
55 hoặc
object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
56.

Lý do thứ hai mà

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
42 tồn tại là cổ xưa hơn. Trong Python 2.7 và trước đó, cố gắng đăng nhập
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
29 từ một logger không có bộ xử lý sẽ đưa ra cảnh báo. Thêm lớp NO-OP
object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
42 sẽ ngăn chặn điều này.

Tại đây, những gì đặc biệt xảy ra trong dòng

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
60 từ trên:

  1. Python được (tạo) phiên bản

    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    12 có cùng tên với gói của bạn. Nếu bạn đang thiết kế gói
    object
    │
    ├── LogRecord
    ├── Filterer
    │   ├── Logger
    │   │   └── RootLogger
    │   └── Handler
    │       ├── StreamHandler
    │       └── NullHandler
    ├── Filter
    └── Manager
    
    62, trong vòng
    (Pdb) l
    1514                     exc_info = (type(exc_info), exc_info, exc_info.__traceback__)
    1515                 elif not isinstance(exc_info, tuple):
    1516                     exc_info = sys.exc_info()
    1517             record = self.makeRecord(self.name, level, fn, lno, msg, args,
    1518                                      exc_info, func, extra, sinfo)
    1519 ->          self.handle(record)
    1520
    1521         def handle(self, record):
    1522             """
    1523             Call the handlers for the specified record.
    1524
    (Pdb) from pprint import pprint
    (Pdb) pprint(vars(record))
    {'args': (),
     'created': 1550671851.660067,
     'exc_info': None,
     'exc_text': None,
     'filename': '',
     'funcName': 'f',
     'levelname': 'ERROR',
     'levelno': 40,
     'lineno': 2,
     'module': '',
     'msecs': 660.067081451416,
     'msg': 'bad vibes',
     'name': 'root',
     'pathname': '',
     'process': 2360,
     'processName': 'MainProcess',
     'relativeCreated': 295145.5490589142,
     'stack_info': None,
     'thread': 4372293056,
     'threadName': 'MainThread'}
    
    6, thì
    import threading
    
    _lock = threading.RLock()
    
    def _acquireLock():
         if _lock:
            _lock.acquire()
    
    def _releaseLock():
        if _lock:
            _lock.release()
    
    12 sẽ bằng
    object
    │
    ├── LogRecord
    ├── Filterer
    │   ├── Logger
    │   │   └── RootLogger
    │   └── Handler
    │       ├── StreamHandler
    │       └── NullHandler
    ├── Filter
    └── Manager
    
    65.

  2. Một ví dụ

    object
    │
    ├── LogRecord
    ├── Filterer
    │   ├── Logger
    │   │   └── RootLogger
    │   └── Handler
    │       ├── StreamHandler
    │       └── NullHandler
    ├── Filter
    └── Manager
    
    42 được gắn vào logger này. Điều đó có nghĩa là Python sẽ không mặc định sử dụng trình xử lý
    import threading
    
    _lock = threading.RLock()
    
    def _acquireLock():
         if _lock:
            _lock.acquire()
    
    def _releaseLock():
        if _lock:
            _lock.release()
    
    49.

Hãy nhớ rằng bất kỳ logger nào được tạo trong bất kỳ mô -đun

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
68 nào khác của gói sẽ là trẻ em của bộ ghi này trong hệ thống phân cấp logger và vì người xử lý này cũng thuộc về chúng, họ sẽ không cần sử dụng trình xử lý
import threading

_lock = threading.RLock()

def _acquireLock():
     if _lock:
        _lock.acquire()

def _releaseLock():
    if _lock:
        _lock.release()
49 và giành được 'T mặc định để đăng nhập vào lỗi tiêu chuẩn (
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
39).

Ví dụ nhanh, hãy để nói rằng thư viện của bạn có cấu trúc sau:

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
4

Trong

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
71, với tư cách là nhà phát triển thư viện, bạn có thể tự do thực hiện như sau:

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
5

Bây giờ, người dùng xuất hiện và cài đặt thư viện của bạn từ PYPI thông qua

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
72. Họ sử dụng
object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
73 trong một số mã ứng dụng. Người dùng này có thể tự do thao tác và định cấu hình đối tượng
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
16 từ thư viện như bất kỳ đối tượng Python nào khác, đến nội dung trái tim của họ.

Ghi nhật ký làm gì với ngoại lệ

Một điều mà bạn có thể cảnh giác là nguy cơ ngoại lệ xuất phát từ các cuộc gọi của bạn đến

import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5. Nếu bạn có một cuộc gọi
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
51 được thiết kế để cung cấp cho bạn một số thông tin gỡ lỗi dài dòng hơn, nhưng đó là một số lý do sẽ làm tăng một ngoại lệ, đó sẽ là chiều cao của sự trớ trêu, phải không?

Thông minh, nếu gói

import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5 gặp phải một ngoại lệ có liên quan đến việc ghi lại, thì nó sẽ in dấu vết nhưng không tự tăng ngoại lệ.

Ở đây, một ví dụ liên quan đến một lỗi đánh máy phổ biến: chuyển hai đối số cho một chuỗi định dạng chỉ mong đợi một đối số. Sự khác biệt quan trọng là những gì bạn thấy dưới đây không phải là một ngoại lệ được nêu ra, mà là một dấu vết in được in của ngoại lệ nội bộ, mà chính nó đã bị đàn áp:

>>>

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
6

Điều này cho phép chương trình của bạn duyên dáng tiếp tục với luồng chương trình thực tế của nó. Lý do là bạn sẽ không muốn một ngoại lệ không được nhận ra từ một cuộc gọi

import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5 và ngăn chặn một chương trình chết trong các bài hát của nó.

Tracebacks có thể lộn xộn, nhưng cái này là thông tin và tương đối đơn giản. Điều cho phép đàn áp các ngoại lệ liên quan đến

import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5 là
object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
80. Khi người xử lý gọi
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
41, đó là phương pháp mà nó cố gắng ghi lại bản ghi, nó sẽ trở lại
object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
82 nếu có điều gì đó tồi tệ. Tại đây, việc triển khai
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
41 cho lớp
import threading

_lock = threading.RLock()

def _acquireLock():
     if _lock:
        _lock.acquire()

def _releaseLock():
    if _lock:
        _lock.release()
56:

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
7

Bất kỳ ngoại lệ nào liên quan đến định dạng và văn bản đều bị bắt thay vì được nuôi dưỡng, và

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
85 duyên dáng viết dấu vết lên
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
35.

Ghi nhật ký Python Tracebacks

Nói về các trường hợp ngoại lệ và dấu vết của họ, những trường hợp chương trình của bạn gặp họ nhưng nên đăng nhập ngoại lệ và tiếp tục theo dõi trong việc thực hiện của nó?

Hãy cùng đi qua một vài cách để làm điều này.

Ở đây, một ví dụ giả định về một trình mô phỏng xổ số bằng cách sử dụng mã không có mục đích. Bạn đang phát triển một trò chơi xổ số trực tuyến, nơi người dùng có thể đặt cược vào số may mắn của họ:

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
8

Đằng sau ứng dụng Frontend nằm trong mã quan trọng dưới đây. Bạn muốn đảm bảo rằng bạn theo dõi bất kỳ lỗi nào do trang web có thể khiến người dùng mất tiền. Cách đầu tiên (tối ưu) là sử dụng

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
51 và đăng nhập hình thức
class Logger(Filterer):
    # ...
    def getEffectiveLevel(self):
        logger = self
        while logger:
            if logger.level:
                return logger.level
            logger = logger.parent
        return NOTSET

    def isEnabledFor(self, level):
        try:
            return self._cache[level]
        except KeyError:
            _acquireLock()
            if self.manager.disable >= level:
                is_enabled = self._cache[level] = False
            else:
                is_enabled = self._cache[level] = level >= self.getEffectiveLevel()
            _releaseLock()
        return is_enabled
5 của trường hợp ngoại lệ:

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
9

Điều này sẽ chỉ nhận được thông báo ngoại lệ thực tế, thay vì truy tìm. Bạn kiểm tra nhật ký trên máy chủ trang web của bạn và tìm tin nhắn khó hiểu này:

import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
0

Hmm. Là nhà phát triển ứng dụng, bạn đã gặp vấn đề nghiêm trọng và kết quả là người dùng đã bị gạt ra. Nhưng có lẽ thông điệp ngoại lệ này là rất nhiều thông tin. Sẽ rất vui khi thấy dòng dõi của dấu vết dẫn đến ngoại lệ này?

Giải pháp thích hợp là sử dụng

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
89, ghi lại một thông điệp với cấp
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
36 và cũng hiển thị truy tìm ngoại lệ. Thay thế hai dòng cuối cùng ở trên bằng những điều này:

import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
1

Bây giờ bạn nhận được một dấu hiệu tốt hơn về những gì đang diễn ra:

>>>

import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
2

Sử dụng

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
91 giúp bạn không phải tự tham khảo ngoại lệ vì
import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5 kéo nó vào với
object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
93.

Điều này làm cho mọi thứ rõ ràng hơn rằng vấn đề bắt nguồn từ

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
94, cần biết độ dài của đối tượng mà nó đang xáo trộn. Bởi vì lớp
object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
95 của chúng tôi chuyển một máy phát điện đến
object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
96, nó sẽ được giữ và tăng trước khi hồ bơi có thể bị xáo trộn, ít tạo ra một vé chiến thắng.

Trong các ứng dụng lớn, toàn diện, bạn sẽ thấy

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
89 thậm chí còn hữu ích hơn khi các dấu vết đa thư viện sâu thẳm có liên quan và bạn có thể bước vào chúng với một trình gỡ lỗi trực tiếp như
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
52.

Mã cho

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
99, và do đó
object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
89, chỉ là một dòng duy nhất:

import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
3

Nghĩa là,

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
89 chỉ gọi
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
51 với
import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
03, nếu không thì
_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

def _checkLevel(level):
    if isinstance(level, int):
        rv = level
    elif str(level) == level:
        if level not in _nameToLevel:
            raise ValueError("Unknown level: %r" % level)
        rv = _nameToLevel[level]
    else:
        raise TypeError("Level not an integer or a valid string: %r" % level)
    return rv
48 theo mặc định. Nếu bạn muốn đăng nhập một dấu vết ngoại lệ nhưng ở cấp độ khác với
import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
05, chỉ cần gọi hàm đó hoặc phương thức với
import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
03.

Hãy nhớ rằng

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
91 chỉ nên được gọi trong bối cảnh của một trình xử lý ngoại lệ, bên trong một khối
import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
08:

import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
4

Sử dụng mẫu này một cách tiết kiệm hơn là một phương tiện để đàn áp bất kỳ ngoại lệ nào. Nó có thể hữu ích nhất khi bạn gỡ lỗi một ngăn xếp gọi chức năng dài nơi bạn có thể thấy một lỗi mơ hồ, không rõ ràng và khó theo dõi.

Sự kết luận

Hãy vỗ nhẹ vào lưng, bởi vì bạn đã đi qua gần 2.000 dòng mã nguồn dày đặc. Bạn bây giờ được trang bị tốt hơn để đối phó với gói

import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5!

Hãy nhớ rằng hướng dẫn này đã không còn toàn bộ trong việc bao gồm tất cả các lớp học được tìm thấy trong gói

import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
5. Có nhiều máy móc thậm chí còn gắn kết mọi thứ lại với nhau. Nếu bạn muốn tìm hiểu thêm, thì bạn có thể xem xét các lớp
import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
11 và các mô -đun riêng biệt
import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
12 và
import logging
import sys

logger = logging.getLogger("pylog")
logger.setLevel(logging.DEBUG)
h2 = logging.FileHandler(filename="/tmp/records.log")
h2.setLevel(logging.INFO)
h2 = logging.StreamHandler(sys.stderr)
h2.setLevel(logging.ERROR)
logger.addHandler(h2)
logger.addHandler(h2)
logger.info("testing %d.. %d.. %d..", 1, 2, 3)
13.