2 回答

TA貢獻1851條經驗 獲得超4個贊
首先,讓我們先看看發生了什么,然后再著手解決問題。
logger = logging.getLogger(__name__) :當你這樣做時,你正在獲取或創建一個名為'main'. 由于這是第一次調用,它將創建該記錄器。
other_logger = init_other_logger(__name__): 當你這樣做時,你再次獲取或創建一個名為 的記錄器'main'。由于這是第二次調用,它將獲取上面創建的記錄器。所以你并沒有真正實例化一個新的記錄器,但是你得到了對上面創建的同一個記錄器的引用。您可以在調用init_other_logger表格后通過打印來檢查這一點:) print(logger is other_logger。
接下來發生的事情是將 aFileHandler和 a添加Formatter到'main'記錄器(在init_other_logger函數內部),然后通過方法調用 2 個日志調用info()。但是您正在使用相同的 logger進行操作。
所以這:
logger.info('Hello World')
other_logger.info('Goodbye World')
本質上與此相同:
logger.info('Hello World')
logger.info('Goodbye World')
現在,兩個記錄器都輸出到文件和流中,這并不奇怪了。
解決方案
所以顯而易見的事情就是init_other_logger用另一個名字稱呼你。
我會建議反對另一個答案提出的解決方案,因為當您需要一個獨立的記錄器時,這 不是應該做的事情。文檔很好地說明了您永遠不應該直接實例化記錄器,而總是通過模塊的功能getLogger。logging
正如我們在上面發現的那樣,當你調用它時,logging.getLogger(logger_name)要么使用. 因此,當您也想要一個獨特的記錄器時,這非常有效。但是請記住,此函數是冪等的,這意味著它只會在您第一次調用它時創建一個具有給定名稱的記錄器,如果您使用相同的名稱調用它,無論您調用多少次,它都會返回該記錄器。logger_name
因此,例如:
表單的第一次調用logging.getLogger('the_rock')- 創建您獨特的記錄器
表單的第二次調用logging.getLogger('the_rock')- 獲取上述記錄器
例如,如果您執行以下操作,您會發現這特別有用:
Formatters在項目中的某個位置配置一個記錄器Filters,例如在project_root/main_package/__init__.py.
想要在位于project_root/secondary_package/__init__.py.
您可以對secondary_package/__init__.py表單進行簡單的調用:logger = logging.getLogger('main_package')您將使用該記錄器及其所有的花里胡哨。
注意力!
即使此時您將使用您的init_other_logger函數創建一個唯一的記錄器,它仍然會輸出到文件和控制臺。將此行替換other_logger = init_other_logger(__name__)為other_logger = init_other_logger('the_rock')以創建唯一的記錄器并再次運行代碼。您仍然會看到輸出寫入控制臺和文件。
為什么 ?
因為它將同時使用FileHandler和StreamHandler。
為什么 ?
因為伐木機械的工作方式。您的記錄器將通過其處理程序發出其消息,然后它將一直傳播到根記錄器,在那里它將使用StreamHandler您通過basicConfig調用附加的記錄器。因此,propagate您發現的屬性實際上就是您想要的,因為您正在創建一個自定義記錄器,您只想通過其手動附加的處理程序發出消息,而不是進一步發出任何消息。在創建唯一記錄器后取消注釋logger.propagate = False,您會看到一切都按預期工作。

TA貢獻1816條經驗 獲得超6個贊
您的兩個處理程序都安裝在同一個記錄器上。這就是他們不分開的原因。
logger is other_logger
因為logging.getLogger(__name__) is logging.getLogger(__name__)
要么直接為第二個日志創建一個記錄器logging.Logger(name)
(我知道文檔說永遠不要這樣做,但如果你想要一個完全獨立的記錄器,這是如何做到的),或者在調用時為第二個日志使用不同的名稱logging.getLogger()
。
添加回答
舉報