Đăng nhập python vào tập tin

Gói Python

import logging
import sys

logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
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 riêng bạn thực hiện. Việc 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 lệnh gọi
import logging
import sys

logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
6 không cần thiết

Tuy nhiên, gói

import logging
import sys

logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5 của Python có thể phức tạp ở một số điểm nhất định. Trình xử lý, trình ghi nhật ký, cấp độ, không gian tên, bộ lọc. 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 để giải quyết các vấn đề còn lỏng lẻo trong hiểu biết của bạn về

import logging
import sys

logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5 là xem qua mã nguồn CPython của nó. Mã Python đằng sau
import logging
import sys

logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5 ngắn gọn và theo mô-đun, và việc đọc qua mã này có thể giúp bạn có được giây phút sảng khoái đó

Bài viết này nhằm bổ sung cho tài liệu HOWTO ghi nhật ký cũng như Ghi nhật ký bằng Python, đây là 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]
    h1 = logging.FileHandler[filename="/tmp/records.log"]
    h1.setLevel[logging.INFO]
    h2 = logging.StreamHandler[sys.stderr]
    h2.setLevel[logging.ERROR]
    logger.addHandler[h1]
    logger.addHandler[h2]
    logger.info["testing %d. %d. %d..", 1, 2, 3]
    
    5 cấp độ và cách chúng hoạt động
  • An toàn luồng so với an toàn quy trình trong
    import logging
    import sys
    
    logger = logging.getLogger["pylog"]
    logger.setLevel[logging.DEBUG]
    h1 = logging.FileHandler[filename="/tmp/records.log"]
    h1.setLevel[logging.INFO]
    h2 = logging.StreamHandler[sys.stderr]
    h2.setLevel[logging.ERROR]
    logger.addHandler[h1]
    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]
    h1 = logging.FileHandler[filename="/tmp/records.log"]
    h1.setLevel[logging.INFO]
    h2 = logging.StreamHandler[sys.stderr]
    h2.setLevel[logging.ERROR]
    logger.addHandler[h1]
    logger.addHandler[h2]
    logger.info["testing %d. %d. %d..", 1, 2, 3]
    
    5 từ góc độ OOP
  • Đăng nhập vào thư viện so với ứng dụng
  • Các phương pháp hay nhất và các mẫu thiết kế để sử dụng
    import logging
    import sys
    
    logger = logging.getLogger["pylog"]
    logger.setLevel[logging.DEBUG]
    h1 = logging.FileHandler[filename="/tmp/records.log"]
    h1.setLevel[logging.INFO]
    h2 = logging.StreamHandler[sys.stderr]
    h2.setLevel[logging.ERROR]
    logger.addHandler[h1]
    logger.addHandler[h2]
    logger.info["testing %d. %d. %d..", 1, 2, 3]
    
    5

Đối với hầu hết các trường hợp, chúng ta sẽ đi từng dòng mô-đun cốt lõi trong gói

import logging
import sys

logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5 của Python để xây dựng một bức tranh về cách nó được trình bày

Tiền thưởng miễn phí. 5 Suy nghĩ về Làm chủ Python, một khóa học miễn phí dành cho các nhà phát triển Python cho bạn thấy lộ trình và tư duy mà bạn sẽ cần để đưa các kỹ năng Python của mình lên một tầm cao mới

Làm thế nào để theo cùng

Vì mã nguồn

import logging
import sys

logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5 là trọng tâm của bài viết này, nên bạn có thể cho rằng bất kỳ khối mã hoặc liên kết nào đều dựa trên một cam kết cụ thể trong Python 3. 7 Kho lưu trữ CPython, cụ thể là cam kết
>>> import logging
>>> import pdb

>>> def f[x]:
..     logging.error["bad vibes"]
..     return x / 0
.. 
>>> pdb.run["f[1]"]
6. Bạn có thể tìm thấy gói
import logging
import sys

logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5 trong thư mục
>>> import logging
>>> import pdb

>>> def f[x]:
..     logging.error["bad vibes"]
..     return x / 0
.. 
>>> pdb.run["f[1]"]
8 trong nguồn CPython

Trong gói

import logging
import sys

logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5, hầu hết công việc nặng nhọc diễn ra 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'}
0, đây 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 đó, chúng ta hãy nhảy vào

Loại bỏ các quảng cáo

sơ bộ

Trước khi chúng ta chuyển sang hạng nặng, hàng trăm dòng trên cùng 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'}
1 giới thiệu một số khái niệm tinh tế nhưng quan trọng

Sơ bộ #1. Trình độ 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'}
2

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'}
3 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'}
4 có vẻ hơi mờ. Các biến nội bộ này là gì và chúng được định nghĩa như thế nào?

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

import logging
import sys

logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5 của Python, tạo thành một tập hợp các cấp số giống như enum

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

[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 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'}
7? . Họ cũng được đặt tên để cho họ mượn ý nghĩa ngữ nghĩa. Nói rằng một thông báo 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 độ
[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 cho bạn biết rằng bạn đã có một đèn đỏ nhấp nháy ở đâu đó trong chương trình của mình

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

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
0 ở 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
1. 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
2, mà cuối cùng sẽ thực hiện 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
3 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'}
2 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 chọn cái nào? . Ngoài ra, việc chuyển biểu 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
0 không phải là một tùy chọn trong Python 2 và một số phương thức
import logging
import sys

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

>>> logger.parent.level
30
1 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'}
2, không phải người anh em họ
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
0 của nó

Sơ bộ #2. Ghi nhật ký an toàn cho luồng nhưng không an toàn cho quy trình

Sau một vài dòng, bạn sẽ tìm thấy đoạn 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
4 là một nằm trong không gian tên chung 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'}
0. Nó làm cho gần như mọi đối tượng và hoạt động trong toàn bộ gói
import logging
import sys

logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5 an toàn cho luồng, cho phép các luồng thực hiện các thao tác đọc và ghi mà không có mối đe dọa về điều kiện chạy đua. Bạn có thể thấy trong mã nguồn mô-đun rằng
>>> import logging
>>> logger = logging.getLogger["app"]
>>> logger.level  # No!
0
>>> logger.getEffectiveLevel[]
30
>>> logger.parent

>>> logger.parent.level
30
7 và
>>> import logging
>>> logger = logging.getLogger["app"]
>>> logger.level  # No!
0
>>> logger.getEffectiveLevel[]
30
>>> logger.parent

>>> logger.parent.level
30
8 phổ biến đối với mô-đun và các lớp của nó

Tuy nhiên, có một cái gì đó không được tính ở đây. những gì về quá trình an toàn? . Đây vốn dĩ không phải là lỗi của

import logging
import sys

logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5—nói chung, hai quy trình không thể ghi vào cùng một tệp nếu không có 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
01 có liên quan đến đa xử lý. Nếu hai quy trình muốn đọc và ghi đồng thời vào cùng một tệp cơ bản, thì bạn có thể gặp phải một lỗi khó chịu giữa chừng trong một quy trình dài hạn

Nếu bạn muốn khắc phục hạn chế này, có một hướng dẫn kỹ lưỡng trong Sổ ghi nhật ký chính thức. Bởi vì điều này đòi hỏi một số lượng lớn thiết lập, nên một giải pháp thay thế là mỗi quy trình ghi nhật ký vào một tệp riêng biệt dựa trên ID quy trình của nó, mà bạn có thể lấy bằng

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

Bây giờ, chúng tôi đã đề cập đến một số mã thiết lập sơ bộ, hãy cùng xem xét cách trình bày của

import logging
import sys

logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5. Gói
import logging
import sys

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

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

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

Ghi chú. Bạn có thể sử dụng thuộc tính dunder

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
05 để xem chuỗi thừa kế. Có thể tìm thấy hướng dẫn cụ thể về MRO trong tài liệu Python 2, mặc dù hướng dẫn này cũng có thể áp dụng cho Python 3

Chuỗi lớp học này thường là một nguồn gây nhầm lẫn vì có rất nhiều thứ đang diễn ra và 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
06 so với
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
07? . Một bức tranh đáng giá ngàn lời nói, vì vậy đây là sơ đồ của một tình huống trong đó một người ghi nhật ký có hai trình xử lý được gắn vào nó viết một thông điệp nhật ký có cấp độ _______15_______3

Luồng đối tượng khai thác gỗ [Hình ảnh. Trăn 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]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
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. Những gì hiển thị ở trên là một kịch bản đơn giản hóa

Mã của bạn chỉ định nghĩa một phiên bản

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08,
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12, cùng với hai phiên bản
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
09,
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
14 và
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
15

Khi bạn gọi

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

Trong nội bộ, các cuộc gọi

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12 để đặt chuỗi thông báo
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
23 và các đối số của nó
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
24 vào một thể hiện lớp thực sự của một
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
25, chỉ là một vùng chứa cho thông báo 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
12 tìm kiếm các bộ xử lý của nó [ví dụ về
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
09], có thể được liên kết trực tiếp với chính
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12 hoặc với cha mẹ của nó [một khái niệm mà chúng ta sẽ đề cập 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
    
    20 kết xuất 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
    
    30
  2. Một thư gửi tới
    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    31 nhưng chỉ khi thư đến ở cấp độ
    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    32 trở lên

Tại thời điểm này, có một đợt kiểm tra khác bắt đầu. Bởi vì

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
25 và thông báo của nó chỉ mang cấp độ ____22_______20, nên bản ghi được ghi vào Trình xử lý 1 [mũi tên xanh lục], chứ không phải luồng
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
35 của Trình xử lý 2 [mũi tên đỏ]. Đối với Trình xử lý, việc ghi
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
25 vào luồng của họ được gọi là phát ra nó, được ghi lại trong

Tiếp theo, hãy mổ xẻ thêm mọi thứ từ phía trên

Loại bỏ các quảng cáo

Lớp học
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
25

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
25 là gì? . Nó được tạo cho bạn bởi một phiên bản
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08 và gói gọn tất cả thông tin thích hợp về sự kiện đó. Bên trong, nó không chỉ là một trình bao bọc xung quanh một
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
3 chứa các thuộc tính cho bản ghi. Phiên bản
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08 gửi phiên bản
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
25 về 0 hoặc nhiều hơn phiên bản
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
09

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
25 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 tạo dưới dạng dấu thời gian Unix
  3. Bản thân tin 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ý

Dưới đây là thông tin sơ lược về siêu dữ liệu mà nó mang theo, bạn có thể xem xét nội dung này bằng cách thực hiện cuộc gọi

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

>>>

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

[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
25, bên trong, chứa một kho siêu dữ liệu được sử dụng theo cách này hay cách khác

Bạn sẽ hiếm khi cần phải giải quyết trực tiếp với

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
25, vì
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08 và
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
09 sẽ làm việc này cho bạn. Vẫn đáng để biết thông tin nào được gói gọn trong một
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
25, bởi vì đây là nơi mà tất cả thông tin hữu ích đó, chẳng hạn như dấu thời gian, đến từ khi bạn xem thông báo nhật ký bản ghi

Ghi chú. Bên dưới lớp

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
25, bạn cũng sẽ tìm thấy các hàm xuất xưởng
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
55,
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
56 và
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
57. Bạn sẽ không cần những thứ này trừ khi bạn muốn sử dụng một lớp tùy chỉnh thay vì
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
25 để đóng gói các thông điệp tường trình và siêu dữ liệu của chúng

Lớp học
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08 và
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
09

Các lớp

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08 và
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
09 đều là trung tâm của cách thức hoạt động của
import logging
import sys

logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5 và chúng tương tác với nhau thường xuyên. Một
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08, một
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
09, và một
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
25, mỗi người có một
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
67 liên kết với chúng

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08 lấy
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
25 và chuyển nó cho
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
09, 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
25 bằng hoặc cao hơn mức của
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08. Đ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
25 so với
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
09. Đây được gọi là lọc theo cấp độ, mà
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08 và
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
09 thực hiện theo những cách hơi khác nhau

Nói cách khác, có một [ít nhất] thử nghiệm hai bước được áp dụng trước khi thông báo mà bạn đăng nhập được gửi đi bất cứ đâu. Để được chuyển hoàn toàn từ trình ghi nhật ký sang trình xử lý và sau đó được ghi 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
77, tệp hoặc email qua SMTP], một
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
25 phải có cấp ít nhất cao bằng cả trình 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
08 theo dõi cấp độ 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ý bên dưới cấp độ đó. [Nguồn]

Vậy việc 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
08 và
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
09?

Đối với lớp

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08, giả định đầu tiên hợp lý là bộ ghi nhật ký sẽ so sánh thuộc tính
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
67 của nó với cấp độ của lớp
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
25 và được thực hiện ở đó. Tuy nhiên, nó liên quan nhiều hơn thế một chút

Quá trình lọc dựa trên cấp độ dành cho trình ghi nhật ký diễn ra trong

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
85, từ đó gọi tới ____22_______86. Luôn sử dụng
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
87 thay vì chỉ hỏi ý kiến ​​của
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
88. 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
08 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, phiên bản

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08 có cấp độ 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
92]. Tuy nhiên, các logger cũng có các logger cha, một trong số đó là logger gốc, có chức năng như cha của tất cả các logger khác. Một
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08 sẽ đi lên trong hệ thống phân cấp của nó và đạt được cấp độ hiệu quả so với cha mẹ của nó [cuối cùng có thể là ____22_______94 nếu không tìm thấy cha mẹ nào khác]

Đây là trong lớp

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

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 là 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 là bài học rút ra. đừng dựa vào

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
67. Nếu bạn chưa đặt một mức độ rõ ràng cho đối tượng
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12 của mình và bạn đang phụ thuộc vào
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
67 vì một số lý do, thì thiết lập ghi nhật ký của bạn có thể sẽ hoạt động khác với mong đợi của bạn.

Còn về

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
09 thì sao?

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

Đối với một phiên bản

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
25 nhất định [có tê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
03 trong mã nguồn ở trên], trình ghi nhật ký kiểm tra với từng trình xử lý đã đăng ký của nó và kiểm tra nhanh thuộc tính
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
67 của phiên bản
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
09 đó. 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
06 của
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
25 lớn hơn hoặc bằng của người xử lý, chỉ khi đó bản ghi mới được chuyển qua. A trong
import logging
import sys

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

Trình xử lý và những nơi chúng đếnHiển thị/Ẩn

Thuộc tính quan trọng nhất đối với thể hiện của lớp con

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
09 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
10 của nó. Đây là điểm đến cuối cùng nơi các bản ghi được ghi vào và có thể là bất kỳ đối tượng giống như tệp nào. Đây là một ví dụ với , là luồng trong bộ nhớ [bộ đệm] cho văn bản I/O

Đầu tiên, thiết lập một phiên bản

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08 với cấp độ là
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
19. 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
14 để thực hiện cuộc gọ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
15 không hoạt động. Chúng tôi muốn xóa
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
31 hoặc
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
77, nhưng không phải 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à gắn nó dưới dạ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
10 cho trình xử lý tùy chỉnh của bạn với cấp độ là
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
20, sau đó buộc trình xử lý đó vào bộ ghi

>>>

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

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

Ba thông điệp cấp độ

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
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
21 và
[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 chuyển qua chuỗi. Lúc đầu, có vẻ như họ không đi đâu cả, nhưng hai trong số họ thì có. Cả ba người họ đều ra khỏi cổng từ
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12 [có cấp độ
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
19]

Tuy nhiên, chỉ có hai trong số chúng được phát ra bởi trình xử lý vì nó có cấp độ cao hơn là

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
20, vượt quá
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
19. 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
0 và đóng bộ đệm để giải phóng tài nguyên hệ thống một cách rõ ràng

Loại bỏ các quảng cáo

Lớp học
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
06 và
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
07

Ở trên, chúng tôi đã đặt câu hỏi, "Lọc theo cấp độ xảy ra ở đâu?" . 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
08 và
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
09 xảy ra mà không có sự trợ giúp của một trong hai lớp
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
06 hoặc
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
07

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
06 và
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
07 đượ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 bên trên 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ư một bộ lọc gọi món

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
07 là lớp cơ sở cho
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08 và
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
09 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 của
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
06 vào chúng bằ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
42 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
43, đó là những gì mà
_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
44 đề 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
4

Đư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
03 [là một phiên bản
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
25],
_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 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
48 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
49 tùy thuộc vào việc bản ghi đó có được bộ lọc của lớp này chấp nhận hay không

Đây là. Lần lượt 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
50, cho các lớp
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08 và
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
09

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

Cả

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08 và
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
09 đều không đi kèm với bất kỳ bộ lọc bổ sung nào theo mặc định, nhưng đây là một ví dụ nhanh về cách bạn có thể thêm một bộ lọc

>>>

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

Ở trên, bạn định nghĩa một 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
55 và ghi đè 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
47 của nó. 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
57, bạn cũng có thể chuyển một hàm có thể gọi được, chẳng hạn như một hàm hoặc lambda hoặc một lớp định nghĩ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
58

Lớp họ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
59

Còn một diễn viên hậu trường của

import logging
import sys

logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5 đáng để động vào. 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
59. Điều quan trọng nhất không phải là 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
59 mà là một phiên bản duy nhất của nó hoạt động như một thùng chứa cho hệ thống phân cấp ngày càng tăng của các trình ghi nhật ký được xác định trên các gói. Bạn sẽ thấy trong phần tiếp theo làm thế nào mà chỉ một phiên bản duy nhất của lớp này là trung tâm để gắn mô-đun lại với nhau và cho phép các phần của nó giao tiếp với nhau

Trình ghi gốc cực kỳ quan trọng

Khi nói đến

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08 trường hợp, một trường hợp nổi bật. Nó được gọi là bộ ghi gốc

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

Ba dòng cuối cùng của khối mã này là một trong những thủ thuật khéo léo được sử dụng bởi gói

import logging
import sys

logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5. Dưới đây là một vài điểm

  • Bộ ghi gốc chỉ là một đối tượng Python đơn giản với mã định danh

    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    94. Nó có cấp độ 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
    
    66 và cấp độ 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
    
    67 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
    
    68. Đối với 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
    
    69, cái tên duy nhất này là tất cả những gì đặc biệt về nó

  • Đối tượng

    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    94 lần lượt trở thành một 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
    
    08. Điều này có nghĩa là tất cả các phiên bản của
    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    08 và chính lớp
    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    08 đều có một 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
    
    74 là trình ghi nhật ký gốc. Đây là một ví dụ khác về mẫu giống như singleton được thi hành trong gói
    import logging
    import sys
    
    logger = logging.getLogger["pylog"]
    logger.setLevel[logging.DEBUG]
    h1 = logging.FileHandler[filename="/tmp/records.log"]
    h1.setLevel[logging.INFO]
    h2 = logging.StreamHandler[sys.stderr]
    h2.setLevel[logging.ERROR]
    logger.addHandler[h1]
    logger.addHandler[h2]
    logger.info["testing %d. %d. %d..", 1, 2, 3]
    
    5

  • Phiên bả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
    
    59 được đặt làm thuộc tính 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
    
    77 cho
    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    08. Điều này cuối cùng phát huy tác 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
    
    79.
    _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
    
    77 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
    
    81 và tạo chúng nếu chúng không tồn tại

Hệ thống phân cấp Logger

Mọi thứ đều là con của

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

Hãy nhớ lại trước đó cách mà

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
86 cho các trường hợp
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12 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
21] mặc dù chúng tôi đã không đặt nó một cách rõ ràng?

>>>

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 trình xử lý của trình ghi nhật ký. Tìm kiếm thực sự là tìm kiếm theo thứ tự đảo ngược trên cây của cha mẹ của người khai thác gỗ

Loại bỏ các quảng cáo

Thiết kế nhiều tay cầm

Hệ thống phân cấp logger có vẻ gọn gàng về mặt lý thuyết, nhưng nó có lợi như thế nào trong thực tế?

Hãy tạm dừng việc khám phá mã

import logging
import sys

logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5 và chuyển sang viết ứng dụng nhỏ của riêng chúng ta—một ứng dụng tận dụng hệ thống phân cấp trình ghi nhật ký theo cách làm giảm mã soạn sẵn và giữ cho mọi thứ có thể mở rộng nếu cơ sở mã của dự án phát triển

Đây là cấu trúc dự án

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

Đừng 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
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
89. Điều chúng ta 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]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
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
91

Trong trường hợp này, giả sử bạn muốn thiết kế một thiết lập ghi nhật ký nhiều nhánh

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

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

  • Một số trình xử lý được chia sẻ giữa các phiên bản

    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    12 khác nhau trong các mô-đun khác nhau. Những trình xử lý này chỉ quan tâm đến việc lọc dựa trên cấp độ chứ không phải mô-đun nơi bản ghi nhật ký bắt nguồn từ đó. Có một trình xử lý cho các thư
    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    19, một cho
    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    20, 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
    
    21, v.v.

  • Mỗi

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

Trực quan, những gì chúng ta đang chụp sẽ trông giống như thế này

Một thiết kế khai thác gỗ nhiều nhánh [Hình ảnh. Trăn thật]

Hai đối tượng màu ngọc lam là các phiên bản của

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

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
01 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
09

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

Các thuộc tính của hệ thống phân cấp bộ ghi làm cho nó phù hợp để thiết lập bố cục trình xử lý bộ ghi nhiều nhánh này. Điều đó nghĩa là gì?

Tại sao thứ bậc lại quan trọng? . Theo cách này, bạn có thể xác định một bộ trình xử lý duy nhất ở gốc của cây ghi nhật ký và nắm bắt tất cả các lệnh gọi ghi nhật ký trong cây con của trình ghi nhật ký. 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[]
03 sẽ bắt tất cả các thông báo ghi nhật ký được phát hành trên bộ ghi nhật ký
import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
04 và
import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
05. [Nguồn]

Thuật ngữ tuyên truyền đề cập đến cách một người khai thác gỗ tiếp tục đi lên chuỗi cha mẹ của nó để tìm kiếm người xử lý. Theo mặc định, thuộc tính

import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
06 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
48 cho phiên bản
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08

>>>

_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

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
00, nếu
import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
10 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
48, mỗi cha kế tiếp được gán lại cho biến cục bộ
import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
12 cho đến khi hệ thống phân cấp cạn kiệ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
1

Đây là ý nghĩa của nó. bởi vì biến dunder

import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
13 trong 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'}
1 của gói chỉ là tên của gói, một trình ghi nhật ký ở đó sẽ trở thành cha mẹ của bất kỳ trình ghi nhật ký nào có trong các mô-đun khác trong cùng một gói

Dưới đây là kết quả 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
67 từ việc gán cho
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
12 với
import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
01

Module

_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
67 Attribute
import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
19
import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
20
import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
21
import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
22
import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
23
import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
24

Bởi vì những người khai thác gỗ

import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
22 và
import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
24 là con của
import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
20, chúng sẽ bám lấy không chỉ những người xử lý trực tiếp của chúng mà còn với bất kỳ người xử lý nào được gắn với
import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
20

Hãy xây dựng các mô-đun. Đến trướ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'}
1

_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[]
03 đượ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
19 đế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'}
9, sau đó đính kèm nó vào một trình ghi nhật ký duy nhất ở đầu hệ thống phân cấp

Bạn cũng xác định một hàm tiện ích bổ sung thêm một

import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
33 vào bộ ghi nhật ký, trong đó
import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
34 của trình xử lý tương ứng với tên mô-đun nơi bộ ghi được xác định. [Điều này giả sử bộ ghi nhật ký được xác định bằng
import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
13. ]

Sau đó, bạn có thể thêm một số thiết lập bộ ghi soạn sẵn 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
89 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. 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[]
38 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 không cần phải lo lắng về các trình xử lý định hướng theo cấp độ vì chúng đã được thêm vào trình ghi gốc của chúng có tên là
import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
20

_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 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
88

_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 xem cách tất cả những thứ 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ý thu được rằng hệ thống lọc của chúng tôi hoạt động như dự kiến. Trình xử lý hướng mô-đun hướng một trình ghi tới một tệp cụ thể, trong khi trình xử lý hướng cấp hướng nhiều trình ghi tới 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ư thừa. Một phiên bản

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
25 có thể chuyển đến không ít hơn sáu tệp. Đó cũng là một lượng tệp I/O không đáng kể có thể tăng lên trong một ứng dụng quan trọng về hiệu suất

Bây giờ, bạn đã xem một ví dụ thực tế, hãy chuyển hướng và tìm hiểu nguyên nhân có thể gây nhầm lẫn trong

import logging
import sys

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

Loại bỏ các quảng cáo

Thông báo “Tại sao Thông điệp Nhật ký của tôi không đi đến đâu?”

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

import logging
import sys

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

  1. Bạn đã ghi một tin nhắn dường như chẳng đi đến đâu và bạn không chắc tại sao
  2. Thay vì bị chặn, một thông báo tường trình xuất hiện ở một nơi mà bạn không ngờ tớ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 đã ghi một tin nhắn dường như chẳng đi đến đâu và bạn không chắc tại sao

Đừng quên rằng cấp độ hiệu quả của trình ghi nhật ký mà bạn không đặt mức tùy chỉnh theo cách khác 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
21, bởi vì trình ghi nhật ký sẽ đi lên cấp bậc của nó cho đến khi tìm thấy trình ghi nhật ký gốc có cấ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
21 của chính 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
7

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[]
47 không đi đến đâu

Thay vì bị chặn, một thông báo tường trình xuất hiện ở một nơi mà bạn không ngờ tới

Khi bạn xác định

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

Lý do cho điều này là vì một trình xử lý tên là

import logging
import sys

logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5 có tên là
import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
50 sẽ viết thư cho
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
31 nếu không tìm thấy trình xử lý nào 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
8

Điều này khởi động khi một người ghi nhật ký đi tìm người xử lý của 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
9

Nếu trình ghi nhật ký từ bỏ việc tìm kiếm trình xử lý [cả trình xử lý trực tiếp của chính nó và thuộc tính của trình ghi nhật ký mẹ], thì nó sẽ chọn trình xử lý

import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
50 và sử dụng trình đó

Có một chi tiết tinh tế hơn đáng để biết về. Phần này chủ yếu nói về các phương thức cá thể [các phương thức mà một lớp định nghĩa] hơn là các hàm cấp mô-đun của gói

import logging
import sys

logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5 có cùng tên

Nếu bạn sử dụng các hàm, chẳng hạn như

import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
54 thay vì
import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
55, thì nội bộ sẽ xảy ra điều gì đó hơi khác một chút. Hàm gọi
import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
56, hàm này thêm một số
import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
57 để ghi vào
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
31. Cuối cùng, hành vi hầu như giống nhau

>>>

import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
0

Tận dụng lợi thế của định dạng lười biếng

Đã đến lúc chuyển hướng và xem xét kỹ hơn cách bản thân các tin nhắn được kết hợp với dữ liệu của chúng. Mặc dù nó đã được thay thế bởi và chuỗi f, nhưng có lẽ bạn đã sử dụng định dạng kiểu phần trăm của Python để làm điều gì đó như thế này

>>>

import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
1

Kết quả là, bạn có thể bị cám dỗ làm điều tương tự trong một cuộc gọi

import logging
import sys

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

>>>

import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
2

Điều này sử dụng toàn bộ chuỗi định dạng và các đối số của nó làm đối số

import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
61 cho
import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
62

Đây là giải pháp thay thế được đề xuất,

>>>

import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
3

Nó trông hơi kỳ lạ, phải không? . Đây là ý nghĩa của nó

Chữ ký phương thức cho

import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
64 trông như thế này

import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
4

Điều tương tự cũng áp dụng cho các phương pháp khác, chẳng hạn như

import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
47. Khi bạn gọi
import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
66, cả
import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
67 và
import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
68 đều bị bắt là
import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
69 và, trong phạm vi nội dung của phương thức,
import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
70 bằng với
import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
71

Tương phản điều này với cuộc gọi đầu tiên ở trên

import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
5

Ở dạng này, mọi thứ trong ngoặc đơn ngay lập tức được hợp nhất với nhau thành

import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
72 và được chuyển thành
import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
61, trong khi
import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
70 là một bộ trống

Vì sao vấn đề này? . 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]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
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
25 được yêu cầu bởi một
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
09

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

import logging
import sys

logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5 xét thấy rằng
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
25 sẽ thực sự được chuyển cho một trình xử lý thì nó mới trở thành chính nó được hợp nhất hoàn toàn

Tất cả điều đó có nghĩa là gói

import logging
import sys

logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5 thực hiện một số tối ưu hóa hiệu suất rất tinh vi ở đúng nơi. Điều này có vẻ như là chi tiết vụn vặt, nhưng nếu bạn đang thực hiện cùng một lệnh gọi
import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
83 hàng 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[]
70 là các lệnh gọi hàm, thì bản chất lười biếng của cách định dạng chuỗi của ___________ có thể tạo ra sự khác biệt

Trước khi thực hiện bất kỳ việc 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[]
61 và
import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
70, một phiên bản
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08 sẽ kiểm tra
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
85 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

Loại bỏ các quảng cáo

Hàm vs Phương thức

Về phía cuố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'}
0 là các chức năng cấp mô-đun được quảng cáo trước trong API công khai của
import logging
import sys

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

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
47,
import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
94 và
import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
95. Các hàm cấp cao nhất là các hàm bao 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 từ bộ ghi gốc,

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

  2. Trước khi gọi các phương thức ghi nhật ký gốc, chúng gọi

    import threading
    
    _lock = threading.RLock[]
    
    def _acquireLock[]:
         if _lock:
            _lock.acquire[]
    
    def _releaseLock[]:
        if _lock:
            _lock.release[]
    
    56 mà không có đối số nếu
    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    94 không có bất kỳ trình xử lý nào. Như bạn đã thấy trước đó, lệnh gọi này thiết lập trình xử lý
    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    77 cho trình ghi nhật ký gốc

Để minh họa, đây là

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 mẫu tương tự cho

import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
83,
import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

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

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

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

  1. Gọi _______53_______08. Tạo một ví dụ

    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    25 từ
    import threading
    
    _lock = threading.RLock[]
    
    def _acquireLock[]:
         if _lock:
            _lock.acquire[]
    
    def _releaseLock[]:
        if _lock:
            _lock.release[]
    
    61 và các đối số khác mà bạn chuyển đến nó

  2. Gọi

    object
    │
    ├── LogRecord
    ├── Filterer
    │   ├── Logger
    │   │   └── RootLogger
    │   └── Handler
    │       ├── StreamHandler
    │       └── NullHandler
    ├── Filter
    └── Manager
    
    11. Đ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 đi đâu?

Đây là toàn bộ quá trình trong một sơ đồ

Nội bộ của một cuộc gọi ghi nhật ký [Hình ảnh. Trăn 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
48

Theo dõi cuộc gọi để ghi nhật ký. cảnh báo[]Hiện/Ẩn

>>>

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
13 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
13, bao bọc
object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
15

import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
8

Đây là điểm khởi đầu để thực thi thiết kế bộ ghi đơn

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

    object
    │
    ├── LogRecord
    ├── Filterer
    │   ├── Logger
    │   │   └── RootLogger
    │   └── Handler
    │       ├── StreamHandler
    │       └── NullHandler
    ├── Filter
    └── Manager
    
    16, thì ____53_______17 bên dưới sẽ thực hiện tra cứu ____27_______3 trên chuỗi _______53_______16. Điều này dẫn đến việc tra cứu trong
    object
    │
    ├── LogRecord
    ├── Filterer
    │   ├── Logger
    │   │   └── RootLogger
    │   └── Handler
    │       ├── StreamHandler
    │       └── NullHandler
    ├── Filter
    └── Manager
    
    20 của
    object
    │
    ├── LogRecord
    ├── Filterer
    │   ├── Logger
    │   │   └── RootLogger
    │   └── Handler
    │       ├── StreamHandler
    │       └── NullHandler
    ├── Filter
    └── Manager
    
    21. Đây là từ điển của tất cả các trình ghi nhật ký đã đăng ký, bao gồm các phiên bản trung gian
    object
    │
    ├── LogRecord
    ├── Filterer
    │   ├── Logger
    │   │   └── RootLogger
    │   └── Handler
    │       ├── StreamHandler
    │       └── NullHandler
    ├── Filter
    └── Manager
    
    22 được tạo khi bạn tham chiếu trình ghi nhật ký ở xa trong hệ thống phân cấp trước khi tham chiếu cha mẹ của nó

  • Mặt khác,

    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    94 được trả lại. Chỉ có một
    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    94—trường hợp 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
    
    69 đã thảo luận ở trên

Tính năng này là thứ nằm sau một thủ thuật có thể cho phép bạn xem qua tất cả những người ghi nhật ký đã đăng ký

>>>

import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
9

Chờ đã. Điều gì đang xảy ra ở đây?

Đầu tiên, hãy nhớ lại rằng

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
27 là một thuộc tính của lớp, trong đó một thể hiện 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
59 được gắn vào lớp
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08.
object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
30 được thiết kế để theo dõi và quản lý tất cả các phiên bản đơn lẻ của
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
08. Chúng được đặt trong
object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
32

Bây giờ, khi bạn nhập

import logging
import sys

logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5 lần đầu tiên, từ điển này trống. Nhưng sau khi bạn nhập
object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
34, cùng một từ điển sẽ có ba trình ghi nhật ký. Đây là một ví dụ về một mô-đun thiết lập các thuộc tính của một mô-đun khác tại chỗ. Chắc chắn rồi, bên trong
object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
35, bạn sẽ tìm thấy những thứ sau

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

Cặp khóa-giá trị nằm trong

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
36 để
object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
30 có thể giám sát toàn bộ không gian tên của logger. Điều này có nghĩa là đối tượng
object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
38 được đăng ký trong từ điển logger thuộc gói
import logging
import sys

logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5. Điều tương tự cũng xảy ra với gói
object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
40, được nhập bởi
object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
34

Bạn có thể thấy sức mạnh của thiết kế đơn lẻ trong một thử nghiệm tương đương

>>>

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

Sự so sánh này minh họa [che đậy một vài chi tiết] cuối cùng thì

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
13 làm gì

Loại bỏ các quảng cáo

Ghi nhật ký thư viện và ứng dụng.
object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
43 là gì?

Điều đó đưa chúng ta đến khoảng một 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'}
0, trong đó
object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
43 được định nghĩa. Đây là đị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
43 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 ứng dụng. Hãy xem điều đó có nghĩa là gì

Thư viện là một gói Python có thể mở rộng, có thể khái quát hóa, dành cho những 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à phân phối cho người dùng. 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
47 và
object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
48

Ứ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à nhóm người dùng nhỏ hơn nhiều [có thể chỉ một người dùng]. Đó là một chương trình hoặc bộ chương trình được người dùng tùy chỉnh cao để thực hiện một số việc hạn chế. Một ví dụ về ứng dụng là ứng dụng Django nằm phía sau trang web. Các ứng dụng thường sử dụng [

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
49] thư viện và các công cụ chứa trong đó

Khi nói đến ghi nhật ký, có các phương pháp hay nhất khác nhau trong thư viện so với ứng dụng

Đó là nơi mà

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
43 phù hợp. Về cơ bản, nó là một lớp sơ khai không làm gì cả

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

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 trình ghi nhật ký thư viện được khai báo với

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
52 [không có bất kỳ cấu hình nào khác] sẽ đăng nhập vào ____22_______31 theo mặc định, ngay cả khi đó không phải là điều người dùng cuối muốn. Điều này có thể được mô tả như một phương pháp từ chối, trong đó người dùng cuối của thư viện phải truy cập 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.

Thay vào đó, sự khôn ngoan thông thường nói rằng hãy sử dụng phương pháp chọn tham gia. khô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 các trình ghi nhật ký của thư viện hay không và thêm các trình xử lý cho chúng. Đây là triết lý được diễn đạt thẳng thắn hơn bởi tác giả của gói

import logging
import sys

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

Theo mặc định, thư viện của bên thứ ba sử dụng

import logging
import sys

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

Điều này cho phép người dùng thư viện, chứ 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
56 hoặc
object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
57

Lý do thứ hai mà

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
43 tồn tại cổ xưa hơn. Trong Python 2. 7 trở về trước, việc cố gắng ghi nhật ký
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
25 từ trình ghi nhật ký không có bộ xử lý sẽ. Thêm lớp no-op
object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
43 sẽ ngăn chặn điều này

Đây là những gì cụ thể xảy ra trong dòng

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
61 từ phía trên

  1. Python nhận [tạo] phiên bản

    CRITICAL = 50
    FATAL = CRITICAL
    ERROR = 40
    WARNING = 30
    WARN = WARNING
    INFO = 20
    DEBUG = 10
    NOTSET = 0
    
    08 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
    
    63, trong khoả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'}
    
    1, thì
    import threading
    
    _lock = threading.RLock[]
    
    def _acquireLock[]:
         if _lock:
            _lock.acquire[]
    
    def _releaseLock[]:
        if _lock:
            _lock.release[]
    
    13 sẽ bằng với
    object
    │
    ├── LogRecord
    ├── Filterer
    │   ├── Logger
    │   │   └── RootLogger
    │   └── Handler
    │       ├── StreamHandler
    │       └── NullHandler
    ├── Filter
    └── Manager
    
    66

  2. Phiên bản

    object
    │
    ├── LogRecord
    ├── Filterer
    │   ├── Logger
    │   │   └── RootLogger
    │   └── Handler
    │       ├── StreamHandler
    │       └── NullHandler
    ├── Filter
    └── Manager
    
    43 được đính kèm với bộ ghi 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[]
    
    50

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

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
69 nào khác của gói sẽ là con của trình ghi nhật ký này trong hệ thống phân cấp trình ghi nhật ký và vì trình xử lý này cũng thuộc về họ nên 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[]
50 và giành chiến thắng

Ví dụ nhanh, giả sử 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
72, với tư cách là nhà phát triển thư viện, bạn được tự do thực hiện những việc sau

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

Bây giờ, một người dùng đã đến và cài đặt thư viện của bạn từ PyPI qua

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
73. Họ sử dụng
object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
74 trong một số mã ứng dụng. Người dùng này được 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
12 từ thư viện giống như bất kỳ đối tượng Python nào khác, theo ý muốn của họ

Loại bỏ các quảng cáo

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à sự nguy hiểm của các trường hợp ngoại lệ xuất phát từ các cuộc gọi của bạn tới

import logging
import sys

logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
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
47 đượ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 bản thân cuộc gọi đó vì lý do nào đó lại tạo ra một ngoại lệ, đó sẽ là đỉnh điểm của sự trớ trêu, phải không?

Khéo léo, nếu gói

import logging
import sys

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

Đây là 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 nhìn thấy bên dưới không phải là một ngoại lệ được nêu ra, mà là một dấu vết được in đẹp hơn của ngoại lệ bên trong, chính ngoại lệ này đã bị chặn

>>>

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 tiếp tục một cách duyên dáng với luồng chương trình thực tế của nó. Cơ sở lý luận là bạn sẽ không muốn một ngoại lệ chưa được phát hiện đến từ chính lệnh gọi

import logging
import sys

logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5 và dừng một chương trình đang chết dở

Tracbacks có thể lộn xộn, nhưng điều này là thông tin và tương đối đơn giản. Điều gì cho phép loại bỏ các trường hợp ngoại lệ liên quan đến

import logging
import sys

logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5 là
object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
81. Khi trình xử lý gọi
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
37, đây là phương thức mà nó cố gắng ghi lại bản ghi, nó sẽ quay trở lại
object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
83 nếu có gì đó không ổn. Đây là triển khai của
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
37 cho lớp
import threading

_lock = threading.RLock[]

def _acquireLock[]:
     if _lock:
        _lock.acquire[]

def _releaseLock[]:
    if _lock:
        _lock.release[]
57

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à cách viết đều bị bắt thay vì được nêu ra và

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
86 viết truy nguyên một cách duyên dáng tới
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
31

Ghi nhật ký Truy nguyên Python

Nói về ngoại lệ và dấu vết của chúng, còn các trường hợp chương trình của bạn gặp phải chúng nhưng nên ghi lại ngoại lệ và tiếp tục thực hiện thì sao?

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

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

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

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

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
47 và ghi lại biểu 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
0 của chính trường hợp ngoại lệ

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

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

import logging
import sys

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

Hừm. Là nhà phát triển ứng dụng, bạn đã gặp phải một vấn đề nghiêm trọng và kết quả là một người dùng đã bị gạt. Nhưng có lẽ bản thân thông báo ngoại lệ này không có nhiều thông tin. Thật tuyệt khi thấy dòng truy nguyên dẫn đến ngoại lệ này phải không?

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

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

import logging
import sys

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

Bây giờ bạn có một dấu hiệu tốt hơn về những gì đang xảy ra

>>>

import logging
import sys

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

Việc sử dụng

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

logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
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
94

Đ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
95, 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
96 của chúng tôi chuyển một trình tạo cho
object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
97, nó sẽ được giữ và tăng trước khi nhóm có thể được xáo trộn, ít tạo ra vé trúng thưởng hơn nhiều

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
90 thậm chí còn hữu ích hơn khi có liên quan đến truy nguyên sâu, nhiều thư viện và bạn không thể can thiệp vào chúng bằng 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
48

Mã cho

import logging
import sys

logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
00, và do đó là
object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
90, chỉ là một dòng duy nhất

import logging
import sys

logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
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
90 chỉ gọi
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
47 với
import logging
import sys

logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
04, nếu không thì 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
49 theo mặc định. Nếu bạn muốn ghi lại một truy nguyên ngoại lệ nhưng ở cấp độ khác với
import logging
import sys

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

Hãy nhớ rằng chỉ nên gọi

object
│
├── LogRecord
├── Filterer
│   ├── Logger
│   │   └── RootLogger
│   └── Handler
│       ├── StreamHandler
│       └── NullHandler
├── Filter
└── Manager
92 trong ngữ cảnh của trình xử lý ngoại lệ, bên trong khối
import logging
import sys

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

import logging
import sys

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

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

Loại bỏ các quảng cáo

Phần kết luận

Hãy tự vỗ về mình vì bạn vừa xem qua gần 2.000 dòng mã nguồn dày đặc. Bây giờ bạn đã đượ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]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5

Hãy nhớ rằng hướng dẫn này vẫn chưa đầy đủ trong việc bao gồm tất cả các lớp có trong gói

import logging
import sys

logger = logging.getLogger["pylog"]
logger.setLevel[logging.DEBUG]
h1 = logging.FileHandler[filename="/tmp/records.log"]
h1.setLevel[logging.INFO]
h2 = logging.StreamHandler[sys.stderr]
h2.setLevel[logging.ERROR]
logger.addHandler[h1]
logger.addHandler[h2]
logger.info["testing %d. %d. %d..", 1, 2, 3]
5. Thậm chí còn có nhiều máy móc dán 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 các lớp học
import logging
import sys

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

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

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

Đánh dấu là đã hoàn thành

🐍 Thủ thuật Python 💌

Nhận một Thủ thuật Python ngắn và hấp dẫn được gửi đến hộp thư đến của bạn vài ngày một lần. Không có thư rác bao giờ. Hủy đăng ký bất cứ lúc nào. Được quản lý bởi nhóm Real Python

Gửi cho tôi thủ thuật Python »

Giới thiệu về Brad Solomon

Brad là một kỹ sư phần mềm và là thành viên của Nhóm hướng dẫn Python thực sự

» Thông tin thêm về Brad

Mỗi hướng dẫn tại Real Python được tạo bởi một nhóm các nhà phát triển để nó đáp ứng các tiêu chuẩn chất lượng cao của chúng tôi. Các thành viên trong nhóm đã làm việc trong hướng dẫn này là

Aldren

Jim

Joanna

Bậc thầy Kỹ năng Python trong thế giới thực Với quyền truy cập không giới hạn vào Python thực

Tham gia với chúng tôi và có quyền truy cập vào hàng nghìn hướng dẫn, khóa học video thực hành và cộng đồng các Pythonistas chuyên gia

Nâng cao kỹ năng Python của bạn »

Chuyên gia Kỹ năng Python trong thế giới thực
Với quyền truy cập không giới hạn vào Python thực

Tham gia với chúng tôi và có quyền truy cập vào hàng ngàn hướng dẫn, khóa học video thực hành và cộng đồng Pythonistas chuyên gia

Nâng cao kỹ năng Python của bạn »

Bạn nghĩ sao?

Đánh giá bài viết này

Tweet Chia sẻ Chia sẻ Email

Bài học số 1 hoặc điều yêu thích mà bạn đã học được là gì?

Mẹo bình luận. Những nhận xét hữu ích nhất là những nhận xét được viết với mục đích học hỏi hoặc giúp đỡ các sinh viên khác. và nhận câu trả lời cho các câu hỏi phổ biến trong cổng thông tin hỗ trợ của chúng tôi

Chủ Đề