Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e6f1e43

Browse files
committed
Improved logging cookbook for logging with multiprocessing.
1 parent 0d4bcf4 commit e6f1e43

1 file changed

Lines changed: 100 additions & 0 deletions

File tree

Doc/howto/logging-cookbook.rst

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -807,6 +807,106 @@ the basis for code meeting your own specific requirements::
807807
if __name__ == '__main__':
808808
main()
809809

810+
A variant of the above script keeps the logging in the main process, in a
811+
separate thread::
812+
813+
import logging
814+
import logging.config
815+
import logging.handlers
816+
from multiprocessing import Process, Queue
817+
import random
818+
import threading
819+
import time
820+
821+
def logger_thread(q):
822+
while True:
823+
record = q.get()
824+
if record is None:
825+
break
826+
logger = logging.getLogger(record.name)
827+
logger.handle(record)
828+
829+
830+
def worker_process(q):
831+
qh = logging.handlers.QueueHandler(q)
832+
root = logging.getLogger()
833+
root.setLevel(logging.DEBUG)
834+
root.addHandler(qh)
835+
levels = [logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR,
836+
logging.CRITICAL]
837+
loggers = ['foo', 'foo.bar', 'foo.bar.baz',
838+
'spam', 'spam.ham', 'spam.ham.eggs']
839+
for i in range(100):
840+
lvl = random.choice(levels)
841+
logger = logging.getLogger(random.choice(loggers))
842+
logger.log(lvl, 'Message no. %d', i)
843+
844+
if __name__ == '__main__':
845+
q = Queue()
846+
d = {
847+
'version': 1,
848+
'formatters': {
849+
'detailed': {
850+
'class': 'logging.Formatter',
851+
'format': '%(asctime)s %(name)-15s %(levelname)-8s %(processName)-10s %(message)s'
852+
}
853+
},
854+
'handlers': {
855+
'console': {
856+
'class': 'logging.StreamHandler',
857+
'level': 'INFO',
858+
},
859+
'file': {
860+
'class': 'logging.FileHandler',
861+
'filename': 'mplog.log',
862+
'mode': 'w',
863+
'formatter': 'detailed',
864+
},
865+
'foofile': {
866+
'class': 'logging.FileHandler',
867+
'filename': 'mplog-foo.log',
868+
'mode': 'w',
869+
'formatter': 'detailed',
870+
},
871+
'errors': {
872+
'class': 'logging.FileHandler',
873+
'filename': 'mplog-errors.log',
874+
'mode': 'w',
875+
'level': 'ERROR',
876+
'formatter': 'detailed',
877+
},
878+
},
879+
'loggers': {
880+
'foo': {
881+
'handlers' : ['foofile']
882+
}
883+
},
884+
'root': {
885+
'level': 'DEBUG',
886+
'handlers': ['console', 'file', 'errors']
887+
},
888+
}
889+
workers = []
890+
for i in range(5):
891+
wp = Process(target=worker_process, name='worker %d' % (i + 1), args=(q,))
892+
workers.append(wp)
893+
wp.start()
894+
logging.config.dictConfig(d)
895+
lp = threading.Thread(target=logger_thread, args=(q,))
896+
lp.start()
897+
# At this point, the main process could do some useful work of its own
898+
# Once it's done that, it can wait for the workers to terminate...
899+
for wp in workers:
900+
wp.join()
901+
# And now tell the logging thread to finish up, too
902+
q.put(None)
903+
lp.join()
904+
905+
This variant shows how you can e.g. apply configuration for particular loggers
906+
- e.g. the ``foo`` logger has a special handler which stores all events in the
907+
``foo`` subsystem in a file ``mplog-foo.log``. This will be used by the logging
908+
machinery in the main process (even though the logging events are generated in
909+
the worker processes) to direct the messages to the appropriate destinations.
810910

811911
Using file rotation
812912
-------------------

0 commit comments

Comments
 (0)