@@ -4499,6 +4499,212 @@ msgid ""
4499
4499
"if __name__ == '__main__':\n"
4500
4500
" main()"
4501
4501
msgstr ""
4502
+ "import logging\n"
4503
+ "import logging.config\n"
4504
+ "import logging.handlers\n"
4505
+ "from multiprocessing import Process, Queue, Event, current_process\n"
4506
+ "import os\n"
4507
+ "import random\n"
4508
+ "import time\n"
4509
+ "\n"
4510
+ "class MyHandler:\n"
4511
+ " \"\"\" \n"
4512
+ " A simple handler for logging events. It runs in the listener process and\n"
4513
+ " dispatches events to loggers based on the name in the received record,\n"
4514
+ " which then get dispatched, by the logging system, to the handlers\n"
4515
+ " configured for those loggers.\n"
4516
+ " \"\"\" \n"
4517
+ "\n"
4518
+ " def handle(self, record):\n"
4519
+ " if record.name == \" root\" :\n"
4520
+ " logger = logging.getLogger()\n"
4521
+ " else:\n"
4522
+ " logger = logging.getLogger(record.name)\n"
4523
+ "\n"
4524
+ " if logger.isEnabledFor(record.levelno):\n"
4525
+ " # 进程名称经过变换以演示是由监听器来执行\n"
4526
+ " # 记录日志到文件和控制台\n"
4527
+ " record.processName = '%s (for %s)' % (current_process().name, record.processName)\n"
4528
+ " logger.handle(record)\n"
4529
+ "\n"
4530
+ "def listener_process(q, stop_event, config):\n"
4531
+ " \"\"\" \n"
4532
+ " This could be done in the main process, but is just done in a separate\n"
4533
+ " process for illustrative purposes.\n"
4534
+ "\n"
4535
+ " This initialises logging according to the specified configuration,\n"
4536
+ " starts the listener and waits for the main process to signal completion\n"
4537
+ " via the event. The listener is then stopped, and the process exits.\n"
4538
+ " \"\"\" \n"
4539
+ " logging.config.dictConfig(config)\n"
4540
+ " listener = logging.handlers.QueueListener(q, MyHandler())\n"
4541
+ " listener.start()\n"
4542
+ " if os.name == 'posix':\n"
4543
+ " # 在 POSIX 系统上,setup 日志记录器将会在\n"
4544
+ " # 父进程中完成配置,但应当在 dictConfig 调用\n"
4545
+ " # 之后即已被禁用。\n"
4546
+ " # 在 Windows 上,由于不会使用 fork,setup 日志记录器\n"
4547
+ " # 将不会在子进程中退出,因此它将被创建并且显示消息\n"
4548
+ " # —— 对应 \" if posix\" 子句。\n"
4549
+ " logger = logging.getLogger('setup')\n"
4550
+ " logger.critical('Should not appear, because of disabled logger ...')\n"
4551
+ " stop_event.wait()\n"
4552
+ " listener.stop()\n"
4553
+ "\n"
4554
+ "def worker_process(config):\n"
4555
+ " \"\"\" \n"
4556
+ " A number of these are spawned for the purpose of illustration. In\n"
4557
+ " practice, they could be a heterogeneous bunch of processes rather than\n"
4558
+ " ones which are identical to each other.\n"
4559
+ "\n"
4560
+ " This initialises logging according to the specified configuration,\n"
4561
+ " and logs a hundred messages with random levels to randomly selected\n"
4562
+ " loggers.\n"
4563
+ "\n"
4564
+ " A small sleep is added to allow other processes a chance to run. This\n"
4565
+ " is not strictly needed, but it mixes the output from the different\n"
4566
+ " processes a bit more than if it's left out.\n"
4567
+ " \"\"\" \n"
4568
+ " logging.config.dictConfig(config)\n"
4569
+ " levels = [logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR,\n"
4570
+ " logging.CRITICAL]\n"
4571
+ " loggers = ['foo', 'foo.bar', 'foo.bar.baz',\n"
4572
+ " 'spam', 'spam.ham', 'spam.ham.eggs']\n"
4573
+ " if os.name == 'posix':\n"
4574
+ " # 在 POSIX 系统上,setup 日志记录器将会在\n"
4575
+ " # 父进程中完成配置,但应当在 dictConfig 调用\n"
4576
+ " # 之后已被禁用。\n"
4577
+ " # 在 Windows 上,由于不会使用 fork,setup 日志记录器\n"
4578
+ " # 将不会在子进程中退出,因此它将被创建并且显示消息\n"
4579
+ " # —— 对应 \" if posix\" 子句。\n"
4580
+ " logger = logging.getLogger('setup')\n"
4581
+ " logger.critical('Should not appear, because of disabled logger ...')\n"
4582
+ " for i in range(100):\n"
4583
+ " lvl = random.choice(levels)\n"
4584
+ " logger = logging.getLogger(random.choice(loggers))\n"
4585
+ " logger.log(lvl, 'Message no. %d', i)\n"
4586
+ " time.sleep(0.01)\n"
4587
+ "\n"
4588
+ "def main():\n"
4589
+ " q = Queue()\n"
4590
+ " # 主进程将获得一个打印到控制台的简单配置。\n"
4591
+ " config_initial = {\n"
4592
+ " 'version': 1,\n"
4593
+ " 'handlers': {\n"
4594
+ " 'console': {\n"
4595
+ " 'class': 'logging.StreamHandler',\n"
4596
+ " 'level': 'INFO'\n"
4597
+ " }\n"
4598
+ " },\n"
4599
+ " 'root': {\n"
4600
+ " 'handlers': ['console'],\n"
4601
+ " 'level': 'DEBUG'\n"
4602
+ " }\n"
4603
+ " }\n"
4604
+ " # 工作进程配置就是一个附加到根日志记录器的 QueueHandler,\n"
4605
+ " # 它允许所有消息被发送至队列 。\n"
4606
+ " # 我们禁用现有的日志记录器以禁用在父进程中使用的 \" setup\" \n"
4607
+ " # 日志记录器。 这在 POSIX 中是必需的因为日志记录器将会在\n"
4608
+ " # fork() 之后出现在子进程中。\n"
4609
+ " config_worker = {\n"
4610
+ " 'version': 1,\n"
4611
+ " 'disable_existing_loggers': True,\n"
4612
+ " 'handlers': {\n"
4613
+ " 'queue': {\n"
4614
+ " 'class': 'logging.handlers.QueueHandler',\n"
4615
+ " 'queue': q\n"
4616
+ " }\n"
4617
+ " },\n"
4618
+ " 'root': {\n"
4619
+ " 'handlers': ['queue'],\n"
4620
+ " 'level': 'DEBUG'\n"
4621
+ " }\n"
4622
+ " }\n"
4623
+ " # 监听器进程配置显示可以使用日志记录配置的\n"
4624
+ " # 完整适应性以便以你希望的方式将事件分发给\n"
4625
+ " # 处理器。\n"
4626
+ " # 我们禁用现有的日志记录器以禁用在父进程中使用的\n"
4627
+ " # \" setup\" 日志记录器。 这在 POSIX 中是必需的因为\n"
4628
+ " # 日志记录器将会在 fork() 之后出现在子进程中。\n"
4629
+ " config_listener = {\n"
4630
+ " 'version': 1,\n"
4631
+ " 'disable_existing_loggers': True,\n"
4632
+ " 'formatters': {\n"
4633
+ " 'detailed': {\n"
4634
+ " 'class': 'logging.Formatter',\n"
4635
+ " 'format': '%(asctime)s %(name)-15s %(levelname)-8s %(processName)-10s %(message)s'\n"
4636
+ " },\n"
4637
+ " 'simple': {\n"
4638
+ " 'class': 'logging.Formatter',\n"
4639
+ " 'format': '%(name)-15s %(levelname)-8s %(processName)-10s %(message)s'\n"
4640
+ " }\n"
4641
+ " },\n"
4642
+ " 'handlers': {\n"
4643
+ " 'console': {\n"
4644
+ " 'class': 'logging.StreamHandler',\n"
4645
+ " 'formatter': 'simple',\n"
4646
+ " 'level': 'INFO'\n"
4647
+ " },\n"
4648
+ " 'file': {\n"
4649
+ " 'class': 'logging.FileHandler',\n"
4650
+ " 'filename': 'mplog.log',\n"
4651
+ " 'mode': 'w',\n"
4652
+ " 'formatter': 'detailed'\n"
4653
+ " },\n"
4654
+ " 'foofile': {\n"
4655
+ " 'class': 'logging.FileHandler',\n"
4656
+ " 'filename': 'mplog-foo.log',\n"
4657
+ " 'mode': 'w',\n"
4658
+ " 'formatter': 'detailed'\n"
4659
+ " },\n"
4660
+ " 'errors': {\n"
4661
+ " 'class': 'logging.FileHandler',\n"
4662
+ " 'filename': 'mplog-errors.log',\n"
4663
+ " 'mode': 'w',\n"
4664
+ " 'formatter': 'detailed',\n"
4665
+ " 'level': 'ERROR'\n"
4666
+ " }\n"
4667
+ " },\n"
4668
+ " 'loggers': {\n"
4669
+ " 'foo': {\n"
4670
+ " 'handlers': ['foofile']\n"
4671
+ " }\n"
4672
+ " },\n"
4673
+ " 'root': {\n"
4674
+ " 'handlers': ['console', 'file', 'errors'],\n"
4675
+ " 'level': 'DEBUG'\n"
4676
+ " }\n"
4677
+ " }\n"
4678
+ " # 记录一些初始事件,以便显示父进程中的日志记录\n"
4679
+ " # 工作正常。\n"
4680
+ " logging.config.dictConfig(config_initial)\n"
4681
+ " logger = logging.getLogger('setup')\n"
4682
+ " logger.info('About to create workers ...')\n"
4683
+ " workers = []\n"
4684
+ " for i in range(5):\n"
4685
+ " wp = Process(target=worker_process, name='worker %d' % (i + 1),\n"
4686
+ " args=(config_worker,))\n"
4687
+ " workers.append(wp)\n"
4688
+ " wp.start()\n"
4689
+ " logger.info('Started worker: %s', wp.name)\n"
4690
+ " logger.info('About to create listener ...')\n"
4691
+ " stop_event = Event()\n"
4692
+ " lp = Process(target=listener_process, name='listener',\n"
4693
+ " args=(q, stop_event, config_listener))\n"
4694
+ " lp.start()\n"
4695
+ " logger.info('Started listener')\n"
4696
+ " # 我们现在要等待工作进程完成其工作。\n"
4697
+ " for wp in workers:\n"
4698
+ " wp.join()\n"
4699
+ " # 工作进程全部结束,现在可以停止监听。\n"
4700
+ " # 父进程中的日志记录仍然正常进行。\n"
4701
+ " logger.info('Telling listener to stop ...')\n"
4702
+ " stop_event.set()\n"
4703
+ " lp.join()\n"
4704
+ " logger.info('All done.')\n"
4705
+ "\n"
4706
+ "if __name__ == '__main__':\n"
4707
+ " main()"
4502
4708
4503
4709
#: ../../howto/logging-cookbook.rst:2432
4504
4710
msgid "Inserting a BOM into messages sent to a SysLogHandler"
0 commit comments