Google Cloud Functions Python日志记录问题

beQ*_*eQr 16 logging python-3.x google-cloud-platform google-cloud-functions

我不确定该怎么说,但是,我感觉好像有些东西被Google更改了,而我却一无所知。我曾经从日志记录仪表板内Google Cloud Console中的python Cloud Functions中获取日志。现在,它刚刚停止工作。

所以我去研究了很长时间,我刚刚做了一个日志你好世界python Cloud Function:

import logging

def cf_endpoint(req):
    logging.debug('log debug')
    logging.info('log info')
    logging.warning('log warning')
    logging.error('log error')
    logging.critical('log critical')
    return 'ok'
Run Code Online (Sandbox Code Playgroud)

这是我的main.py,我将其部署为带有http触发器的Cloud Function。

由于我拥有所有“调试”级别日志的日志提取排除过滤器,因此在日志记录仪表板中什么都看不到。但是当我删除它时,我发现了这一点:

日志记录仪表板截图

因此,似乎将python内置日志记录解析为stackdriver的操作停止了对日志严重性参数的解析!对不起,如果我看起来很傻,但这是我唯一能想到的:/

你们对此有任何解释或解决方案吗?我做错了吗?

预先感谢您的帮助。

Hui*_*eng 15

我遇到了同样的问题。

在@joan Grau 分享的链接中,我还看到有一种方法可以将云记录器与 Python 日志记录模块集成,这样您就可以像往常一样使用 Python 根记录器,并且所有日志都将发送到 StackDriver Logging。

https://googleapis.github.io/google-cloud-python/latest/logging/usage.html#integration-with-python-logging-module

...

我试过了,它有效。简而言之,你可以通过两种方式做到这一点

将云记录器绑定到根日志记录的一种简单方法

from google.cloud import logging as cloudlogging
import logging
lg_client = cloudlogging.Client()
lg_client.setup_logging(log_level=logging.INFO) # to attach the handler to the root Python logger, so that for example a plain logging.warn call would be sent to Stackdriver Logging, as well as any other loggers created.
Run Code Online (Sandbox Code Playgroud)

或者,您可以设置具有更细粒度控制的记录器

from google.cloud import logging as cloudlogging
import logging
lg_client = cloudlogging.Client()

lg_handler = lg_client.get_default_handler()
cloud_logger = logging.getLogger("cloudLogger")
cloud_logger.setLevel(logging.INFO)
cloud_logger.addHandler(lg_handler)
cloud_logger.info("test out logger carrying normal news")
cloud_logger.error("test out logger carrying bad news")
Run Code Online (Sandbox Code Playgroud)

  • 第二个解决方案很有帮助,谢谢。但是,日志不区分警告和错误。 (2认同)
  • 这也不会记录异常和回溯 (2认同)

dth*_*dor 14

由于不想处理云日志记录库,我创建了一个自定义格式化程序,它会发出具有正确字段的结构化日志,正如云日志记录所期望的那样。

class CloudLoggingFormatter(logging.Formatter):
    """Produces messages compatible with google cloud logging"""
    def format(self, record: logging.LogRecord) -> str:
        s = super().format(record)
        return json.dumps(
            {
                "message": s,
                "severity": record.levelname,
                "timestamp": {"seconds": int(record.created), "nanos": 0},
            }
        )
Run Code Online (Sandbox Code Playgroud)

将此处理程序附加到记录器会导致日志被解析并在日志记录控制台中正确显示。在云函数中,我将配置根记录器以发送到标准输出并将格式化程序附加到它。

# setup logging
root = logging.getLogger()
handler = logging.StreamHandler(sys.stdout)
formatter = CloudLoggingFormatter(fmt="[%(name)s] %(message)s")
handler.setFormatter(formatter)
root.addHandler(handler)
root.setLevel(logging.DEBUG)
Run Code Online (Sandbox Code Playgroud)


Joa*_*oël 9

使用Python本机日志记录模块时,不再支持Stackdriver Logging严重性过滤器。

但是,您仍然可以使用Stackdriver Logging Client Libraries创建具有特定严重性的日志。检查该文件中提到的Python库,和这一个对于一些使用情况的案例。

请注意,为了使日志位于正确的资源下,您将必须手动配置它们,有关支持的资源类型,请参阅此列表。同样,每种资源类型都有一些必需的标签,这些标签必须出现在日志结构中。

例如,以下代码将以ERROR严重性将日志写入StackDriver Logging中的Cloud Function资源:

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

log_client = logging.Client()

# This is the resource type of the log
log_name = 'cloudfunctions.googleapis.com%2Fcloud-functions' 

# Inside the resource, nest the required labels specific to the resource type
res = Resource(type="cloud_function", 
               labels={
                   "function_name": "YOUR-CLOUD-FUNCTION-NAME", 
                   "region": "YOUR-FUNCTION-LOCATION"
               },
              )
logger = log_client.logger(log_name.format("YOUR-PROJECT-ID"))
logger.log_struct(
 {"message": "message string to log"}, resource=res, severity='ERROR')

return 'Wrote logs to {}.'.format(logger.name) # Return cloud function response
Run Code Online (Sandbox Code Playgroud)

请注意YOUR-CLOUD-FUNCTION-NAMEYOUR-FUNCTION-LOCATION和中的字符串YOUR-PROJECT-ID需要特定于您的项目/资源。

  • 感谢琼的回答。坦白说,我对此感到有些失望。这项更改对开发人员非常不友好,并且为CF日志中的基本严重性支持又迈出了一大步。该文档尚未更新,并且云功能的基本功能已变得更加冗长,不直观且配置麻烦。是否有关于此内幕消息的暂时性变更或我们将如何展望的内幕消息? (19认同)
  • 谢谢你节省了我的时间。顺便说一句,我发现使用保留环境更方便 `labels={"function_name": os.getenv('FUNCTION_NAME'), "region": os.getenv('FUNCTION_REGION')}`。另外,我尝试不使用 `.format("YOUR-PROJECT-ID")` 并且它仍然有效 (2认同)
  • 请注意,这不适用于“google-cloud-logging==2.0.0”。将与“google-cloud-logging<=2.0.0”一起使用。from google.cloud.logging.resource import Resource 不再是版本 2 中的模块 (2认同)

小智 8

从 Python 3.8 开始,您可以简单地使用带有和属性的printJSON 结构。例如:severitymessage

print(
    json.dumps(
        dict(
            severity="ERROR",
            message="This is an error message",
            custom_property="I will appear inside the log's jsonPayload field",
        )
    )
)
Run Code Online (Sandbox Code Playgroud)

官方文档:https://cloud.google.com/functions/docs/monitoring/logging#writing_structed_logs