Google Cloud日志记录,Python3.8标准环境,按跟踪ID分组相关请求日志

问题描述

在Google App Engine标准环境中针对python3.8的Google Cloud Logging设置过程中,我遇到了问题。 我将FastAPI与独角兽一起使用。我的代码记录配置:

import logging.config
import sys

from google.cloud import logging as google_logging

from app.settings import ENV,_settings


if _settings.ENV == ENV.LOCAL:
    MAIN_LOGGER = 'console'
    LOGGER_CONF_DICT = {
        'class': 'logging.StreamHandler','formatter': 'verbose','stream': sys.stdout,'level': _settings.LOG_LEVEL.upper(),}
else:
    log_client = google_logging.Client()
    MAIN_LOGGER = 'stackdriver_logging'
    LOGGER_CONF_DICT = {
        'class': 'app.gcloud_logs.GCLHandler','client': log_client,'name': 'appengine.googleapis.com%2Frequest_log'
        # I've tried other names: stdout,%2FA instead of / symbol,appengine.googleapis.com/stdout
        # the same result or no logs at all
    }

LOGGING = {
    'version': 1,'disable_existing_loggers': False,'formatters': {
        'verbose': {
            'format': '%(log_color)s%(asctime)s [%(levelname)s] [%(name)s] %(message)s (%(filename)s:%(lineno)d)','()': 'colorlog.ColoredFormatter','log_colors': {
                'DEBUG': 'cyan','INFO': 'green','WARNING': 'yellow','ERROR': 'red','CRITICAL': 'bold_red',},}
    },'handlers': {
        MAIN_LOGGER: {**LOGGER_CONF_DICT},'blackhole': {'level': 'DEBUG','class': 'logging.NullHandler'},'loggers': {
        'fastapi': {'level': 'INFO','handlers': [MAIN_LOGGER]},'uvicorn.error': {'level': 'INFO','handlers': [MAIN_LOGGER],'propagate': False},'uvicorn.access': {'level': 'INFO','uvicorn': {'level': 'INFO','google.cloud.logging.handlers.transports.background_thread': {'level': 'DEBUG','handlers': ['blackhole'],'': {
            'level': _settings.LOG_LEVEL.upper(),'propagate': True,}
}

logging.config.dictConfig(LOGGING)

我的日志记录处理程序代码

import os
from typing import Any,Dict,Optional

from google.cloud.logging.handlers import CloudLoggingHandler
from google.cloud.logging.resource import Resource
from starlette.requests import Request
from starlette_context import context

from app.settings import _settings


class GCLHandler(CloudLoggingHandler):
    def emit(self,record):
        message = super(GCLHandler,self).format(record)
        request: Optional[Request] = None
        trace: Optional[str] = None
        span_id: Optional[str] = None
        user_id: Optional[int] = None
        resource = Resource(
            type='gae_app',labels={
                'module_id': os.environ['GAE_SERVICE'],'project_id': _settings.PROJECT_NAME,'version_id': os.environ['GAE_VERSION'],'zone': 'us16'  # tried without zone - the same result
            }
        )

        labels: Dict[str,Any] = {}

        if context.exists():  # I'm sure that it works
            request = context.get('request')  # I'm sure that it works
            user_id = context.get('user_id')  # I'm sure that it works

        if user_id is not None:
            labels['user_id'] = user_id

        if request:
            if request.headers.get('X-Cloud-Trace-Context'):
                cloud_trace = request.headers.get('X-Cloud-Trace-Context').split('/')
                if len(cloud_trace) > 1:
                    span_id = cloud_trace[1].split(';')[0]

                trace = f'projects/{_settings.PROJECT_NAME}/traces/{cloud_trace[0]}'
                labels['logging.googleapis.com/trace'] = cloud_trace[0]  # Found in some guides,not sure that its neccessary
                labels['appengine.googleapis.com/trace_id'] = cloud_trace[0]  # Found in some guides,not sure that its neccessary

        self.transport.send(
            record,message,resource=resource,labels=labels,trace=trace,span_id=span_id
        )

在日志查看器中我得到了一些奇怪的结果,即我的日志与请求日志具有相同的跟踪,但是没有将它们分组

enter image description here

有什么想法吗?

解决方法

App Engine中有两种日志类型:

  • 请求日志:发送到您的应用程序的请求的日志。 App Engine会在请求日志中自动创建条目。

  • 应用程序日志:按照此页面上的说明记录您写入支持的框架或文件的条目。

这两个日志均由App Engine标准自动发送到 Cloud Logging Agent

在第一次请求时,应用程序日志和请求日志不相关,这就是为什么未在组中显示的原因,这是known issue stated in App Engine Official Documentation。但是,在第二个请求中,您可以看到日志显示在一个组中。

已经为此行为在Public Issue Tracker中创建了功能请求,您将在其中获得有关此修复程序的所有更新。

,
S = list(range(2008,2020))

将名称更改为log_client = google_logging.Client() MAIN_LOGGER = 'stackdriver_logging' LOGGER_CONF_DICT = { 'class': 'app.gcloud_logs.GCLHandler','client': log_client,'name': 'app' } 会有帮助