How can I create my own log instance for each thread?
For example, I have these files with classes that I want to use (just an example may not work)
# helper_one.py
import logging
logger = logging.getLogger('HelperOne')
class HelperOne:
def __init__(self, data):
self.data = data
def run(self):
logger.debug('HelperOne::Run function with data: ' + self.data)
return True
...
# controller_one.py
import logging
from helper_one import HelperOne
logger = logging.getLogger('ControllerOne')
class ControllerOne:
def __init__(self, data):
self.data = data
def run(self):
logger.debug('ControllerOne::Run function with data: ' + self.data)
ho = HelperOne(self.data + '_data')
return ho.run()
And I have a file that creates Threads
import logging
from controller_one import ControllerOne
# this function creates threads (its just an example)
def run_task(task_id, data):
logging.basicConfig(
filename=os.path.join('logs', str(task_id) + '.log'),
level=logging.DEBUG,
format='%(asctime)s\t%(name)s\t%(levelname)s\t%(message)s'
)
result = ControllerOne(data)
logging.debug('run_task: ' + result)
If I create a log instance like in my example, the entire log is written to one file. How can I create its own logging instance for each thread, logging its own file?
Best regards, Alex.
source to share
The registrar name (the string passed to the function getLogger
) can be whatever you want. As the docs explain:
name
- a potentially hierarchical meaning separated by a period, for examplefoo.bar.baz
(although it could also be just simplefoo
, for example) Registrars that are lower in the hierarchical list are children of the registrars higher in the list. For example, when registering a registrar with a name,foo
registrars with namesfoo.bar
,foo.bar.baz
andfoo.bam
are descendantsfoo
. The log name hierarchy is similar to and identical to the Python package hierarchy if you organize the loggers on a per module basis using the recommended constructionlogging.getLogger(__name__)
. That's because in module__name__
is the name of modules in the Python package namespace.
So, using __name__
as a name is recommended, but not required. And in fact you are already explicitly breaking this:
logger = logging.getLogger('ControllerOne')
So, you can just use a separate name for each thread by putting the thread id or name in the log name. For example:
logger = logging.getLogger('ControllerOne.{}'.format(threading.get_ident())
Or, in your case, since you seem to have a unique one task_id
for each thread, you can simply use that instead of the thread id.
Of course, this means that you must actually use a registrar; you cannot just call logging.debug
. And you cannot rely on basicConfig
; you will need to explicitly configure the logger on each thread. Since each thread creates its own independent instance ControllerOne
, the obvious place to do this is in ControllerOne.__init__
; in this function you can call getLogger
with the name of the log that includes the thread or task id, create and set FileHandler
, which also includes the thread or the task id in the name and save it as self.logger
. Then when you need to record something, you just do self.logger.debug(…)
.
If this all sounds like gobbledegook to you because you don't know what it is FileHandler
, you probably need to read at least a basic tutorial in the HOWTO, but the advanced tutorial and cookbook are very helpful too.
source to share