ведение журнала python не может работать при запуске нового процесса

#python #python-3.x

Вопрос:

Я сталкиваюсь со странным вопросом о logging библиотеке при использовании multiprocessing .

Первый пример (неверный):

 import multiprocessing
import logging
import time


class A:
    def __init__(self):
        self.logger = None
        self.v = "v1"

    def run(self):
        # start a new process here
        p = multiprocessing.Process(target=self.work, name="sub-process")
        p.start()

    def work(self):
        i = 0
        # print info of logger object 
        print(f"v: {self.v}; logger: {self.logger}; handler:{self.logger.handlers}")
        while True and i < 10:
            name = multiprocessing.current_process().name
            self.logger.info(f"current name: {name}   v : {self.v}")
            time.sleep(0.5)
            i  = 1


class B(A):
    def __init__(self):
        super(B, self).__init__()
        self.v = "v2"
        
        # if init logger object inside class
        # then something wrong happens...
        logger = logging.getLogger()
        ch = logging.FileHandler("test.log")
        ch.setFormatter(logging.Formatter('%(asctime)s %(levelname)s %(funcName)s(): %(message)s'))
        ch.setLevel(logging.DEBUG)
        logger.setLevel(logging.DEBUG)
        logger.addHandler(ch)
        logger.addHandler(logging.StreamHandler())

        self.logger = logger
        self.logger.info("B init success")


if __name__ == '__main__':
    b = B()
    b.run()
 

и он выводит неверно:

 B init success   # this line is the output of logger in __init__
v: v2; logger: <RootLogger root (WARNING)>; handler: []   # this line is the output of print function in work
 

Мы видим, что logger во время работы метода он изменился на необработанный объект корневого регистратора(с обработчиком по умолчанию WARNING и пустым обработчиком) work .

Но все идет хорошо, когда я меняю местоположение инициализации регистратора.

 import multiprocessing
import logging
import time

# if init logger object outside class
# then all goes well
logger = logging.getLogger()
ch = logging.FileHandler("test.log")
ch.setFormatter(logging.Formatter('%(asctime)s %(levelname)s %(funcName)s(): %(message)s'))
ch.setLevel(logging.DEBUG)
logger.setLevel(logging.DEBUG)
logger.addHandler(ch)
logger.addHandler(logging.StreamHandler())


class A:
    def __init__(self):
        self.logger = None
        self.v = "v1"

    def run(self):
        # start a new process here
        p = multiprocessing.Process(target=self.work, name="sub-process")
        p.start()

    def work(self):
        i = 0
        # print info of logger object
        print(f"v: {self.v}; logger: {self.logger}; handler:{self.logger.handlers}")
        while True and i < 10:
            name = multiprocessing.current_process().name
            self.logger.info(f"current name: {name}   v : {self.v}")
            time.sleep(0.5)
            i  = 1


class B(A):
    def __init__(self):
        super(B, self).__init__()
        self.v = "v2"

        self.logger = logger
        self.logger.info("B init success")


if __name__ == '__main__':
    b = B()
    b.run()

 

И на этот раз результаты верны!( logger объект просто я определяю в коде)

 B init success
# the following line is output of print function
current name: sub-process   v : v2
v: v2; logger: <RootLogger root (DEBUG)>; handler:[<FileHandler /Users/zjj/test.log (DEBUG)>, <StreamHandler <stderr> (NOTSET)>]
current name: sub-process   v : v2
current name: sub-process   v : v2
current name: sub-process   v : v2
current name: sub-process   v : v2
current name: sub-process   v : v2
current name: sub-process   v : v2
current name: sub-process   v : v2
current name: sub-process   v : v2
current name: sub-process   v : v2
 

Но в моем проекте я должен инициализировать объект регистратора, пока не получу некоторые параметры от __init__ метода,есть ли способ устранить эту проблему(неправильная версия)?

Спасибо!

Комментарии:

1. в Linux Mint обе версии дают один и тот же результат с v: v2; logger: <RootLogger root (DEBUG)>; handler:[<FileHandler /Users/zjj/test.log (DEBUG)>, <StreamHandler <stderr> (NOTSET)>]

2. Я подтверждаю, что первый сценарий дает «неправильные» результаты под Windows, и он работает, как и ожидалось, на Raspian. В Windows, в методе работы, мы используем другой регистратор, подтвержденный печатью(идентификатор(self.logger)). В Raspbian идентификаторы те же самые. Понятия не имею, почему.

3. Моя система-m1 Mac, так что это системно. Mac и Windows дадут неправильные результаты, система Linux может поступить правильно.