Làm cách nào để vô hiệu hóa và kích hoạt lại đăng nhập bảng điều khiển trong Python?


154

Tôi đang sử dụng mô đun ghi nhật ký của Python và tôi muốn vô hiệu hóa việc ghi nhật ký bàn điều khiển một thời gian nhưng nó không hoạt động.

#!/usr/bin/python
import logging

logger = logging.getLogger() # this gets the root logger
# ... here I add my own handlers 
#logger.removeHandler(sys.stdout)
#logger.removeHandler(sys.stderr)

print logger.handlers 
# this will print [<logging.StreamHandler instance at ...>]
# but I may have other handlers there that I want to keep

logger.debug("bla bla")

Đoạn mã trên hiển thị bla blathiết bị xuất chuẩn và tôi không biết làm cách nào để vô hiệu hóa trình xử lý bảng điều khiển một cách an toàn. Làm thế nào tôi có thể chắc chắn rằng tôi tạm thời gỡ bỏ giao diện điều khiển StreamHandler chứ không phải một cái khác?


Đối với những người thắc mắc tại sao mọi người muốn tắt ghi nhật ký: Bạn sẽ không muốn đăng nhập dữ liệu riêng tư như mật khẩu hoặc khóa API.
Stevoisiak

4
@StevenVascellaro. Tại sao những người được gửi đến một logger ở nơi đầu tiên sau đó? Điều đó không đúng ...
Nhà vật lý điên

1
@MadPhysicist Tôi có một ứng dụng gửi yêu cầu XML đến API bên ngoài. Theo mặc định, các yêu cầu này được ghi vào một tập tin. Tuy nhiên, đăng nhập ban đầu yêu cầu xác thực bằng tên người dùng và mật khẩu mà tôi không muốn đăng nhập.
Stevoisiak

@StevenVascellaro. Tôi hiểu rồi. Cảm ơn đã giải thích.
Nhà vật lý điên

Bạn không hiển thị cách / nơi bạn thêm trình xử lý của mình. Nếu họ đã được thêm vào logger gốc này sẽ ngăn chặn khai thác gỗ từ việc thêm mặc định StreamHandler như đã mô tả ở docs.python.org/3/library/logging.html#logging.basicConfig Ngoài ra, theo mô tả liên kết, mặc định StreamHandler chỉ thêm vào trong quá đầu tiên cuộc gọi phát ra thông điệp nhật ký vì vậy khi bạn in logger.handlersnó sẽ trống (vì nó đi trước logger.debug()cuộc gọi). Mã trong câu hỏi chỉ hiển thị [](danh sách xử lý trống). Được xác minh bằng Python 2.7.15 và Python 3.6.6.
Piotr Dobrogost

Câu trả lời:


197

Tôi tìm thấy một giải pháp cho việc này:

logger = logging.getLogger('my-logger')
logger.propagate = False
# now if you use logger it will not log to console.

Điều này sẽ ngăn việc đăng nhập được gửi đến bộ ghi trên bao gồm ghi nhật ký giao diện điều khiển.


8
Tôi không nghĩ rằng đây là một giải pháp tốt. Không tuyên truyền đến logger cao hơn có thể có những hậu quả không mong muốn khác.
lfk

2
Nếu bạn muốn chỉ lọc tin nhắn dưới một mức nhật ký nhất định (giả sử, tất cả các INFOtin nhắn), bạn có thể thay đổi dòng thứ hai thành một cái gì đó nhưlogger.setLevel(logging.WARNING)
Hartley Brody

2
Làm thế nào bạn sẽ kích hoạt lại nhật ký sau đó?
Stevoisiak

4
Không phải là một câu trả lời như chặn tuyên truyền có hiệu quả vô hiệu hóa tất cả các bộ xử lý của logger gốc và câu hỏi rõ ràng bang (...) nhưng tôi có thể xử lý khác có mà tôi muốn giữ điều này cho thấy mục đích là để vô hiệu hóa StreamHandler mặc định của logger gốc chỉ .
Piotr Dobrogost

Dừng truyền bá thông điệp là không đủ. Kể từ Python 3.2 , logging.lastResorttrình xử lý vẫn sẽ ghi nhật ký các mức độ nghiêm trọng logging.WARNINGvà lớn hơn sys.stderrtrong trường hợp không có các trình xử lý khác. Xem câu trả lời của tôi .
Maggyero

106

Tôi sử dụng:

logger = logging.getLogger()
logger.disabled = True
... whatever you want ...
logger.disabled = False

9
điều này cũng hoạt động ở loggingcấp độ mô-đun để vô hiệu hóa ghi nhật ký hoàn toàn , ví dụ import logging; logging.disable(logging.CRITICAL);:: docs.python.org/2/l Library / llo.html.htmllogging.disable
lsh

1
Điều này tốt hơn nhiều so với việc vô hiệu hóa lan truyền.
Mátray Márk

6
Không phải là một câu trả lời - câu hỏi hỏi làm thế nào để vô hiệu hóa StreamHandler mặc định chỉ .
Piotr Dobrogost

1
Các disabledthuộc tính không phải là một phần của API công cộng. Xem bug.python.org/su36318 .
Maggyero

69

Bạn có thể dùng:

logging.basicConfig(level=your_level)

trong đó your_level là một trong số đó:

      'debug': logging.DEBUG,
      'info': logging.INFO,
      'warning': logging.WARNING,
      'error': logging.ERROR,
      'critical': logging.CRITICAL

Vì vậy, nếu bạn đặt your_level để logging.CRITICAL , bạn sẽ nhận được tin nhắn duy nhất quan trọng gửi bởi:

logging.critical('This is a critical error message')

Thiết your_level để logging.DEBUG sẽ hiển thị tất cả các cấp khai thác gỗ.

Để biết thêm chi tiết, xin vui lòng xem các ví dụ đăng nhập.

Theo cách tương tự để thay đổi cấp độ cho mỗi Handler, hãy sử dụng hàm Handler.setLevel () .

import logging
import logging.handlers

LOG_FILENAME = '/tmp/logging_rotatingfile_example.out'

# Set up a specific logger with our desired output level
my_logger = logging.getLogger('MyLogger')
my_logger.setLevel(logging.DEBUG)

# Add the log message handler to the logger
handler = logging.handlers.RotatingFileHandler(
          LOG_FILENAME, maxBytes=20, backupCount=5)

handler.setLevel(logging.CRITICAL)

my_logger.addHandler(handler)

6
Đây thường là thông tin hữu ích, nhưng câu hỏi hỏi làm thế nào để vô hiệu hóa ghi nhật ký giao diện điều khiển, không phải cách thêm trình xử lý bổ sung. nếu bạn đã kiểm tra my_logger.handlers với mã trên được áp dụng cho ví dụ ban đầu, bạn sẽ thấy hai trình xử lý - trình xử lý tệp mới của bạn và trình xử lý luồng gốc.
Joe

TIÊU CHÍ là từ tôi đang tìm kiếm. Cảm ơn.
Nishant

Tôi rất thích nhìn thấy một mức độ gỡ lỗi TẮT. Nó rõ ràng và đơn giản.
Không phải máy

46

(câu hỏi đã chết từ lâu, nhưng dành cho những người tìm kiếm trong tương lai)

Gần hơn với mã / mục đích của người gửi ban đầu, điều này hoạt động với tôi theo python 2.6

#!/usr/bin/python
import logging

logger = logging.getLogger() # this gets the root logger

lhStdout = logger.handlers[0]  # stdout is the only handler initially

# ... here I add my own handlers 
f = open("/tmp/debug","w")          # example handler
lh = logging.StreamHandler(f)
logger.addHandler(lh)

logger.removeHandler(lhStdout)

logger.debug("bla bla")

Gotcha tôi phải làm việc là loại bỏ trình xử lý xuất sắc sau khi thêm một trình xử lý mới; mã logger xuất hiện để tự động thêm lại thiết bị xuất chuẩn nếu không có trình xử lý nào xuất hiện.


2
Trình tự logger = logging.getLogger(); lhStdout = logger.handlers[0]sai vì bộ ghi gốc ban đầu không có trình xử lý - python -c "import logging; assert not logging.getLogger().handlers". Được xác minh bằng Python 2.7.15 và Python 3.6.6.
Piotr Dobrogost

42

Quản lý bối cảnh

import logging 
class DisableLogger():
    def __enter__(self):
       logging.disable(logging.CRITICAL)
    def __exit__(self, a, b, c):
       logging.disable(logging.NOTSET)

Ví dụ sử dụng:

with DisableLogger():
    do_something()

Tôi thực sự thích thành ngữ này, nhưng tôi muốn có thể vô hiệu hóa một không gian tên cụ thể. Ví dụ, tôi chỉ muốn logger gốc tạm thời bị vô hiệu hóa. Mặc dù sử dụng thành ngữ này, chúng ta sẽ có thể chỉ cần thêm / xóa tạm thời các trình xử lý và như vậy.
Chris

1
Câu hỏi đặt ra yêu cầu làm thế nào để vô hiệu hóa StreamHandler mặc định chỉ .
Piotr Dobrogost

1
Bạn không cần phải cuộn lớp của riêng mình, bạn có thể sử dụng @contextmanager từ bối cảnh và viết một hàm cho năng suất
KristianR

Nếu bạn đang vào trái cây kỳ lạ trên bánh pizza của bạn. Chắc chắn rồi.
dùng3504575

34

Để vô hiệu hóa hoàn toàn việc đăng nhập :

logging.disable(sys.maxint) # Python 2

logging.disable(sys.maxsize) # Python 3

Để cho phép đăng nhập :

logging.disable(logging.NOTSET)

Các câu trả lời khác cung cấp công việc xung quanh mà không giải quyết được hoàn toàn vấn đề, chẳng hạn như

logging.getLogger().disabled = True

và, đối với một số nlớn hơn 50,

logging.disable(n)

Vấn đề với giải pháp đầu tiên là nó chỉ hoạt động cho bộ ghi gốc. Các logger khác được tạo bằng cách sử dụng, giả sử, logging.getLogger(__name__)không bị vô hiệu hóa bởi phương thức này.

Giải pháp thứ hai không ảnh hưởng đến tất cả các bản ghi. Nhưng nó giới hạn đầu ra ở các mức trên mức đã cho, vì vậy người ta có thể ghi đè lên nó bằng cách đăng nhập với mức lớn hơn 50.

Điều đó có thể được ngăn chặn bởi

logging.disable(sys.maxint)

mà theo như tôi có thể nói (sau khi xem lại nguồn ) là cách duy nhất để vô hiệu hóa hoàn toàn việc ghi nhật ký.


1
Downvote như câu hỏi hỏi làm thế nào để vô hiệu hóa StreamHandler tiêu chuẩn chỉ
Piotr Dobrogost

27

Có một số câu trả lời thực sự hay ở đây, nhưng rõ ràng là đơn giản nhất không được xem xét quá nhiều (chỉ từ infinito).

root_logger = logging.getLogger()
root_logger.disabled = True

Điều này vô hiệu hóa logger gốc, và do đó tất cả các logger khác. Tôi chưa thực sự thử nghiệm nhưng nó cũng phải nhanh nhất.

Từ mã đăng nhập trong python 2.7 tôi thấy điều này

def handle(self, record):
    """
    Call the handlers for the specified record.

    This method is used for unpickled records received from a socket, as
    well as those created locally. Logger-level filtering is applied.
    """
    if (not self.disabled) and self.filter(record):
        self.callHandlers(record)

Điều đó có nghĩa là khi nó bị vô hiệu hóa, không có trình xử lý nào được gọi và sẽ hiệu quả hơn khi lọc thành giá trị rất cao hoặc đặt trình xử lý no-op chẳng hạn.


1
Trừ khi tôi đang làm gì đó sai, điều này chỉ vô hiệu hóa trình ghi nhật ký gốc chứ không phải bất kỳ thứ gì được tạo như thếlog = logging.getLogger(__name__)
starfry

2
Điều này có thể có vấn đề nếu bạn đang xử lý nhiều logger hoặc nhiều trình xử lý. Ví dụ, nếu bạn vẫn muốn đăng nhập vào một tệp nhưng muốn tắt trình xử lý luồng trong trường hợp cụ thể.
Joe

1
Điều này vô hiệu hóa trình ghi nhật ký gốc, và do đó tất cả các trình ghi nhật ký khác - nói một cách nghiêm túc việc vô hiệu hóa trình ghi nhật ký gốc không vô hiệu hóa bất kỳ trình ghi nhật ký nào khác. Bên cạnh những câu hỏi yêu cầu về việc vô hiệu hóa StreamHandler mặc định chỉ .
Piotr Dobrogost

Các disabledthuộc tính không phải là một phần của API công cộng. Xem bug.python.org/su36318 .
Maggyero

10

Không cần phải chuyển hướng stdout. Đây là cách tốt hơn để làm điều đó:

import logging
class MyLogHandler(logging.Handler):
    def emit(self, record):
        pass

logging.getLogger().addHandler(MyLogHandler())

Một cách thậm chí đơn giản hơn là:

logging.getLogger().setLevel(100)

4
Trong Python 2.7+, điều này có sẵn dưới dạng NullHandler ()
Pierre

1
Lý do tại sao điều này hoạt động (vô hiệu hóa StreamHandler mặc định) có thể được nhìn thấy khi đọc mô tả logging.basicConfig()chức năng (nhấn mạnh của tôi): Có cấu hình cơ bản cho hệ thống ghi nhật ký bằng cách tạo StreamHandler với Formatter mặc định và thêm nó vào bộ ghi gốc. Các hàm gỡ lỗi (), thông tin (), cảnh báo (), lỗi () và quan trọng () sẽ tự động gọi basicConfig () nếu không có trình xử lý nào được xác định cho trình ghi nhật ký gốc . - docs.python.org/3/lvern/logging.html#logging.basicConfig
Piotr Dobrogost

2

Tôi không biết rõ về mô-đun ghi nhật ký, nhưng tôi đang sử dụng nó theo cách mà tôi thường chỉ muốn vô hiệu hóa các thông báo gỡ lỗi (hoặc thông tin). Bạn có thể sử dụng Handler.setLevel()để đặt mức ghi nhật ký thành TIÊU CHUẨN hoặc cao hơn.

Ngoài ra, bạn có thể thay thế sys.stderr và sys.stdout bằng một tệp mở để viết. Xem http://docs.python.org/l Library / sys.html # sys. xuất sắc . Nhưng tôi không khuyến khích điều đó.


Điều này có thể hoạt động nếu logger.handlers sẽ chứa một cái gì đó, hiện tại là [].
sorin

2

Bạn cũng có thể:

handlers = app.logger.handlers
# detach console handler
app.logger.handlers = []
# attach
app.logger.handlers = handlers

Tại sao bạn đang sử dụng app.loggermà bạn thậm chí không chỉ định thay vì bộ ghi gốc được đề cập rõ ràng trong câu hỏi ( logging.getLogger()) và hầu hết các câu trả lời? Làm thế nào để bạn biết bạn có thể sửa đổi handlerstài sản một cách an toàn thay vì Logger.addHandlerphương thức gọi ?
Piotr Dobrogost

2
import logging

log_file = 'test.log'
info_format = '%(asctime)s - %(levelname)s - %(message)s'
logging.config.dictConfig({
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'info_format': {
            'format': info_format
        },
    },
    'handlers': {
        'console': {
            'level': 'INFO',
            'class': 'logging.StreamHandler',
            'formatter': 'info_format'
        },
        'info_log_file': {
            'class': 'logging.handlers.RotatingFileHandler',
            'level': 'INFO',
            'filename': log_file,
            'formatter': 'info_format'
        }
    },
    'loggers': {
        '': {
            'handlers': [
                'console',
                'info_log_file'
            ],
            'level': 'INFO'
        }
    }
})


class A:

    def __init__(self):
        logging.info('object created of class A')

        self.logger = logging.getLogger()
        self.console_handler = None

    def say(self, word):
        logging.info('A object says: {}'.format(word))

    def disable_console_log(self):
        if self.console_handler is not None:
            # Console log has already been disabled
            return

        for handler in self.logger.handlers:
            if type(handler) is logging.StreamHandler:
                self.console_handler = handler
                self.logger.removeHandler(handler)

    def enable_console_log(self):
        if self.console_handler is None:
            # Console log has already been enabled
            return

        self.logger.addHandler(self.console_handler)
        self.console_handler = None


if __name__ == '__main__':
    a = A()
    a.say('111')
    a.disable_console_log()
    a.say('222')
    a.enable_console_log()
    a.say('333')

Bảng điều khiển đầu ra:

2018-09-15 15:22:23,354 - INFO - object created of class A
2018-09-15 15:22:23,356 - INFO - A object says: 111
2018-09-15 15:22:23,358 - INFO - A object says: 333

nội dung tập tin test.log:

2018-09-15 15:22:23,354 - INFO - object created of class A
2018-09-15 15:22:23,356 - INFO - A object says: 111
2018-09-15 15:22:23,357 - INFO - A object says: 222
2018-09-15 15:22:23,358 - INFO - A object says: 333

2
Thêm một số mô tả về mã. Nó sẽ giúp tốt hơn nhiều
Mathews Sunny

2

Bằng cách thay đổi một cấp độ trong "log.config.dictConfig", bạn sẽ có thể đưa toàn bộ cấp độ đăng nhập lên một cấp độ mới.

logging.config.dictConfig({
'version': 1,
'disable_existing_loggers': False,
'formatters': {
    'console': {
        'format': '%(name)-12s %(levelname)-8s %(message)s'
    },
    'file': {
        'format': '%(asctime)s %(name)-12s %(levelname)-8s %(message)s'
    }
},
'handlers': {
    'console': {
        'class': 'logging.StreamHandler',
        'formatter': 'console'
    },
#CHANGE below level from DEBUG to THE_LEVEL_YOU_WANT_TO_SWITCH_FOR
#if we jump from DEBUG to INFO
# we won't be able to see the DEBUG logs in our logging.log file
    'file': {
        'level': 'DEBUG',
        'class': 'logging.FileHandler',
        'formatter': 'file',
        'filename': 'logging.log'
    },
},
'loggers': {
    '': {
        'level': 'DEBUG',
        'handlers': ['console', 'file'],
        'propagate': False,
    },
}

})


1

Tìm thấy một giải pháp tao nhã bằng cách sử dụng các trình trang trí , giải quyết vấn đề sau: nếu bạn đang viết một mô-đun với một số chức năng, mỗi chức năng có một số thông báo gỡ lỗi và bạn muốn tắt đăng nhập trong tất cả các chức năng nhưng bạn đang tập trung vào?

Bạn có thể làm điều đó bằng cách sử dụng trang trí:

import logging, sys
logger = logging.getLogger()
logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)


def disable_debug_messages(func):
    def wrapper(*args, **kwargs):
        prev_state = logger.disabled
        logger.disabled = True
        result = func(*args, **kwargs)
        logger.disabled = prev_state
        return result
    return wrapper

Sau đó, bạn có thể làm:

@disable_debug_messages
def function_already_debugged():
    ...
    logger.debug("This message won't be showed because of the decorator")
    ...

def function_being_focused():
    ...
    logger.debug("This message will be showed")
    ...

Ngay cả khi bạn gọi function_already_debuggedtừ bên trong function_being_focused, các thông báo gỡ lỗi từ function_already_debuggedsẽ không được hiển thị. Điều này đảm bảo bạn sẽ chỉ thấy các thông báo gỡ lỗi từ chức năng bạn đang tập trung vào.

Hy vọng nó giúp!


0

Nếu bạn muốn vô hiệu hóa một logger nhất định ở đây là những gì đã làm.

Nhật ký mẫu

2019-10-02 21:28:45,663 django.request PID: 8  Internal Server Error: /service_portal/get_all_sites

django_request_logger = logging.getLogger('django.request')
django_request_logger.disabled = True
django_request_logger.disabled = False

0

Trong thư viện Ghi nhật ký Python, người ta hoàn toàn có thể vô hiệu hóa ghi nhật ký (cho tất cả các cấp) cho một trình ghi nhật ký cụ thể bằng cách thực hiện một trong các thao tác sau:

  1. Thêm vào logger một logging.NullHandler()trình xử lý (để ngăn logging.lastResorttrình xử lý ghi nhật ký các sự kiện nghiêm trọng logging.WARNINGvà lớn hơn sys.stderr) và đặt propagatethuộc tính của logger đóFalse (để ngăn logger truyền các sự kiện cho các trình xử lý của logger tổ tiên của nó).

    • Sử dụng API chính:

      import logging
      
      logging.getLogger("foo").addHandler(logging.NullHandler())
      logging.getLogger("foo").propagate = False
    • Sử dụng API cấu hình:

      import logging.config
      
      logging.config.dictConfig({
          "version": 1,
          "handlers": {
              "null": {
                  "class": "logging.NullHandler"
              }
          },
          "loggers": {
              "foo": {
                  "handlers": ["null"],
                  "propagate": False
              }
          }
      })
  2. Thêm vào logger một lambda record: Falsebộ lọc.

    • Sử dụng API chính:

      import logging
      
      logging.getLogger("foo").addFilter(lambda record: False)
    • Sử dụng API cấu hình:

      import logging.config
      
      logging.config.dictConfig({
          "version": 1,
          "filters": {
              "all": {
                  "()": lambda: (lambda record: False)
              }
          },
          "loggers": {
              "foo": {
                  "filters": ["all"]
              }
          }
      })

Cảnh báo. - Trái ngược với giải pháp thứ 1, giải pháp thứ 2 không vô hiệu hóa ghi nhật ký từ logger con (ví dụ logging.getLogger("foo.bar")), do đó, người ta chỉ nên sử dụng nó để vô hiệu hóa ghi nhật ký cho một logger.

Ghi chú. - Đặt disabledthuộc tính của logger Truekhông phải là giải pháp thứ 3, vì nó không phải là một phần của API công khai. Xem https://bugs.python.org/su36318 :

import logging

logging.getLogger("foo").disabled = True  # DO NOT DO THAT

-1

phân lớp trình xử lý mà bạn muốn có thể tắt tạm thời:

class ToggledHandler(logging.StreamHandler):
"""A handler one can turn on and off"""

def __init__(self, args, kwargs):
    super(ToggledHandler, self).__init__(*args, **kwargs)
    self.enabled = True  # enabled by default

def enable(self):
    """enables"""
    self.enabled = True

def disable(self):
    """disables"""
    self.enabled = False

def emit(self, record):
    """emits, if enabled"""
    if self.enabled:
        # this is taken from the super's emit, implement your own
        try:
            msg = self.format(record)
            stream = self.stream
            stream.write(msg)
            stream.write(self.terminator)
            self.flush()
        except Exception:
            self.handleError(record)

Tìm trình xử lý theo tên khá dễ dàng:

_handler = [x for x in logging.getLogger('').handlers if x.name == your_handler_name]
if len(_handler) == 1:
    _handler = _handler[0]
else:
    raise Exception('Expected one handler but found {}'.format(len(_handler))

một khi được tìm thấy:

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