如何对相关请求日志条目进行分组GAE python 3.7 standard env

时间:2019-05-13 13:39:31

标签: python-3.x google-app-engine logging google-cloud-platform stackdriver

我正在使用Google App Engine python 3.7标准,并且试图对相关的请求日志条目进行分组。 根据{{​​3}}文档,我应该:

  

在应用程序日志的LogEntry跟踪字段中设置跟踪标识符   条目。预期格式为   项目/ [PROJECT_ID] /跟踪/ [TRACE_ID]

在何处/如何使用LogEntry?

Writing Application Logs并未显示出这种可能性。我想念什么吗?

代码示例将不胜感激。

[更新] 根据{{​​3}}的建议,我尝试了以下操作,但没有成功:

    trace_id = request.headers.get('X-Cloud-Trace-Context', 'no_trace_id').split('/')[0]
    client = logging.Client()
    logger = client.logger('appengine.googleapis.com%2Fstdout')  # Not shown
    # logger = client.logger('projects/{}/logs/stdout'.format(GOOGLE_CLOUD_PROJECT)) # error
    # logger = client.logger('projects/{}/logs/appengine.googleapis.com%2Fstdout'.format(GOOGLE_CLOUD_PROJECT)) # error

    logger.log_text('log_message', trace=trace_id)

日志未出现在Stackdriver Logging documentation

4 个答案:

答案 0 :(得分:1)

Stackdriver Logging Client Library可用于实现此目的。 logger.log_text函数将LogEntry对象发送到API。示例:

from google.cloud import logging

client = logging.Client()
logger = client.logger('appengine.googleapis.com%2Fstdout')
logger.log_text('log_message', trace=trace_id)

应该从请求标头中检索trace_id,如文档所述。这样做的方法取决于您如何处理请求,但是例如在Flask中,它很简单,例如trace_id = request.headers['X-Cloud-Trace-Context'].split('/')[0]

答案 1 :(得分:1)

您可能想看看我提供的答案here

(此答案解决了如何将日志记录严重性添加到写入Stackdriver的Cloud Functions日志中,但是基本工作流程相同)

报价:

  

[...],您仍然可以使用   Stackdriver Logging Client Libraries。   选中this documentation   参考Python库,以及this one   有关一些用例示例。

     

请注意,为了使日志位于正确的资源下,   您将需要手动配置它们,请参见this list   支持的资源类型。同样,每种资源类型都有   一些required labels   需要在日志结构中显示的内容。

编辑:

使用App Engine的示例更新上一个答案:

from google.cloud import logging
from google.cloud.logging.resource import Resource
from flask import Flask

app = Flask(__name__)

@app.route('/')
def logger():
    log_client = logging.Client()
    log_name = 'appengine.googleapis.com%2Fstdout'

    res = Resource( type='gae_app',
                    labels={
                        "project_id": "MY-PROJECT-ID",
                        "module_id": "MY-SERVICE-NAME"
                       })

    logger = log_client.logger(log_name)

    logger.log_struct({"message": "message string to log"}, resource=res, severity='ERROR') # As an example log message with a ERROR warning level

    return 'Wrote logs to {}.'.format(logger.name)

以该代码为例,将日志的资源类型更改为appengine.googleapis.com%2Fstdout应该可以,并且将Resource字段更改为与所描述的gae_app标签中的相同在here中。

答案 2 :(得分:1)

使用Google Cloud Logging中的AppEngineHandler可以提供许多基础架构。这允许将其附加到python日志记录模块,以便进行标准的日志记录导入。

设置起来很简单:

    # Setup google  cloud logging.
    import logging
    import google.cloud.logging  # Don't conflict with standard logging
    from google.cloud.logging.handlers import AppEngineHandler, setup_logging

    client = google.cloud.logging.Client()
    handler = AppEngineHandler(client, name='stdout')
    logging.getLogger().setLevel(logging.INFO)
    setup_logging(handler)

https://googleapis.dev/python/logging/latest/usage.html#cloud-logging-handler上的文档建议非常相似,但不是使用AppEngineHandler,而是使用“ CloudLoggingHandler”。它还指出“ AppEngineHandler”用于灵活的环境,但这在标准的python3环境中有效。

答案 3 :(得分:0)

这是我的基本解决方案:

    trace_id = request.headers.get('X-Cloud-Trace-Context', 'no_trace_id').split('/')[0]
    trace_str = "projects/{}/traces/{}".format(os.getenv('GOOGLE_CLOUD_PROJECT'), trace_id)
    log_client = logging.Client()

    # This is the resource type of the log
    log_name = 'stdout'

    # Inside the resource, nest the required labels specific to the resource type
    labels = {
        'module_id': os.getenv('GAE_SERVICE'),
        'project_id': os.getenv('GOOGLE_CLOUD_PROJECT'),
        'version_id': os.getenv('GAE_VERSION')
    }
    res = Resource(type="gae_app",
                   labels=labels,
                   )
    logger = log_client.logger(log_name)
    logger.log_text("MESSAGE_STRING_TO_LOG", resource=res, severity='ERROR', trace=trace_str)

工作之后,我将其包装在一个文件中,以使其类似于Google的python2.7记录器。

这是my_gae_logging.py:

import logging as python_logging
import os

from flask import request
from google.cloud import logging as gcp_logging
from google.cloud.logging.resource import Resource

# From GCP logging lib for Python2.7
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0

_levelNames = {
    CRITICAL: 'CRITICAL',
    ERROR: 'ERROR',
    WARNING: 'WARNING',
    INFO: 'INFO',
    DEBUG: 'DEBUG',
    NOTSET: 'NOTSET',
    'CRITICAL': CRITICAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}


def get_trace_id():
    trace_str = None
    try:
        trace_id = request.headers.get('X-Cloud-Trace-Context', 'no_trace_id').split('/')[0]
        trace_str = "projects/{project_id}/traces/{trace_id}".format(
            project_id=os.getenv('GOOGLE_CLOUD_PROJECT'),
            trace_id=trace_id)
    except:
        pass
    return trace_str


class Logging:
def __init__(self):
    self._logger = None

@property
def logger(self):
    if self._logger is not None:
        return self._logger

    log_client = gcp_logging.Client()

    # This is the resource type of the log
    log_name = 'appengine.googleapis.com%2Fstdout'

    # Inside the resource, nest the required labels specific to the resource type

    self._logger = log_client.logger(log_name)
    return self._logger

@property
def resource(self):
    resource = Resource(
        type="gae_app",
        labels={
            'module_id': os.getenv('GAE_SERVICE'),
            'project_id': os.getenv('GOOGLE_CLOUD_PROJECT'),
            'version_id': os.getenv('GAE_VERSION')
        }
    )
    return resource

def log(self, text):
    text = str(text)
    self.logger.log_text(text, resource=self.resource, trace=get_trace_id())

def debug(self, text):
    text = str(text)
    self.logger.log_text(text, resource=self.resource, severity=_levelNames.get(DEBUG), trace=get_trace_id())

def info(self, text):
    text = str(text)
    self.logger.log_text(text, resource=self.resource, severity=_levelNames.get(INFO), trace=get_trace_id())

def warning(self, text):
    text = str(text)
    self.logger.log_text(text, resource=self.resource, severity=_levelNames.get(WARNING), trace=get_trace_id())

def warn(self, text):
    return self.warning(text)

def error(self, text):
    text = str(text)
    self.logger.log_text(text, resource=self.resource, severity=_levelNames.get(ERROR), trace=get_trace_id())

def critical(self, text):
    text = str(text)
    self.logger.log_text(text, resource=self.resource, severity=_levelNames.get(CRITICAL), trace=get_trace_id())


if os.getenv('GAE_VERSION'):  # check if running under gcp env
    logging = Logging()
else:
    # when not running under gcp env, use standard python_logging
    logging = python_logging

用法:

from my_gae_logging import logging

logging.warn('this is my warning')