当多个进程生成日志时,哪种方法可以收集日志并将日志发送到Google云日志?
以下是基于CloudLoggingHandler的提案,您是否愿意批评它?
import google
from multiprocessing import Process
from logging import getLogger
class Worker(Process):
def __init__(self):
super(Worker, self).__init__()
def __setup_logger(self):
handler = CloudLoggingHandler(google.cloud.logging.Client(), name='log-name')
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
google.cloud.logging.handlers.setup_logging(handler)
def run(self):
self.__setup_logger()
for i in range(10):
logging.warning("i=%d", i)
if __name__ == "__main__":
for _ in range(2):
w = Worker()
w.start()
我读到了基于队列的日志处理程序here,但CloudLoggingHandler在隔离线程中使用批处理提交,因此基于队列的处理程序会过度。我是对的吗?
Sources表示CloudLoggingHandler是线程安全的,因此所有进程共享一个CloudLoggingHandler实例可能就足够了。会有用吗?如果是这样,它是不是很严厉?
以下编辑回答@ thomas-schultz。
我坚持我的建议,主要是因为我是原型,它起作用了#34;开箱即用#34;我没有检查性能问题。我重新考虑这个选择。
实际上,根据我的理解,带有CloudLoggingHandler的BackgroundThreadTransport会阻塞主线程,直到将日志发送到日志记录端点。几乎每个日志行都会发生这种情况。实际上,只要有一个日志记录(cf source)就会发送批处理。
在我的开发环境中,当多个进程同时记录时,会发生一个进程等待最多1秒以发送日志。我想这主要是网络成本,它会缩小到#34;而不是那么多"来自谷歌数据中心。
我正在考虑定义StreamHandler,它会将所有日志记录推送到Queue。该队列将由Process读取,该{{3}}负责将日志发送到日志记录端点。如果相关,此过程可能依赖CloudLoggingHandler来执行此操作。
这有意义吗?
答案 0 :(得分:1)
我认为除非你遇到连接问题或某些需要排队的情况,否则它可能会过度杀伤。
在这种情况下,您可能使用CloudLoggingHandler
的相同实例,但这样做可能存在一些性能瓶颈。我不太确定。
这里有更多关于与Python的标准库记录器集成的内容。 https://googlecloudplatform.github.io/google-cloud-python/stable/logging-usage.html#integration-with-python-logging-module
我很好奇你是否得到了不同的答案?
答案 1 :(得分:0)
以下是我计划从多个流程登录Google Cloud Logging的方法。此解决方案仅使用python 3内置日志记录处理程序(doc)。在下面的示例中,我测量主进程记录消息所需的时间。结果显示,此解决方案允许在将日志发送到日志记录端点时避免主进程阻塞。当然,只有在主要过程中没有完成耗时的任务时,它才有用。
您对此方法有何看法?
Queue: avg log call duration: 0.00004s
Queue: min log call duration: 0.00002s
Queue: max log call duration: 0.00018s
Cloud: avg log call duration: 0.03019s
Cloud: min log call duration: 0.00003s
Cloud: max log call duration: 0.16630s
下面是一个全面的例子。
import sys
import os
import time
import google
import logging
import multiprocessing
from logging.handlers import QueueHandler, QueueListener
from google.cloud.logging.handlers import CloudLoggingHandler
def do(i):
"""
Dummy function that times the log insertion.
"""
t = time.time()
logging.info('%dth message.' % i)
return time.time() - t
if __name__ == '__main__':
# The standard google cloud logging handler sends logs to the clooud logging endpoint.
client = google.cloud.logging.Client()
cloud_handler = CloudLoggingHandler(client=client, name="xyz")
# A local handler is used to have feedbacks on what is going on.
local_handler = logging.StreamHandler(sys.stdout)
# Log records are put in the log queue.
log_queue = multiprocessing.Queue()
# The listener dequeues log records from the log queue. Each handler registered in the
# listener processes the log records.
queue_listener = QueueListener(log_queue, local_handler, cloud_handler)
queue_listener.start()
# The queue handler pushes the log records to the log queue.
queue_handler = QueueHandler(log_queue)
# Setup the root loger to the handler we defined.
root_logger = logging.getLogger()
root_logger.setLevel(logging.INFO)
root_logger.addHandler(queue_handler)
n = 10
# Emits logs and measure how fast it is with the
durations = [do(i) for i in range(n)]
print('Queue: avg log call duration: %.5fs' % (sum(durations) / n))
print('Queue: min log call duration: %.5fs' % min(durations))
print('Queue: max log call duration: %.5fs' % max(durations))
# Stop the queue listener.
queue_listener.stop()
# Remove the queue handler from the root logger.
root_logger.removeHandler(queue_handler)
# Setup the root loger to use CloudLoggingHandler.
root_logger.setLevel(logging.INFO)
root_logger.addHandler(local_handler)
root_logger.addHandler(cloud_handler)
# Emits logs and measure how fast it is with the
durations = [do(i) for i in range(n)]
print('Queue: avg log call duration: %.5fs' % (sum(durations) / n))
print('Queue: min log call duration: %.5fs' % min(durations))
print('Queue: max log call duration: %.5fs' % max(durations))