Google Cloud Functions Python 日志记录问题

Posted

技术标签:

【中文标题】Google Cloud Functions Python 日志记录问题【英文标题】:Google Cloud Functions Python Logging issue 【发布时间】:2019-06-06 10:22:51 【问题描述】:

我不知道该怎么说,但我感觉 Google 在我不知情的情况下更改了某些内容。我曾经在日志仪表板的 Google Cloud Console 中从我的 python Cloud Functions 获取我的日志。而现在,它刚刚停止工作。

于是调查了半天,刚刚做了一个log hello world 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'

这是我的 main.py,我将其部署为带有 h​​ttp 触发器的云函数。

因为我有一个包含所有“调试”级别日志的日志提取排除过滤器,所以我在日志仪表板中看不到任何内容。但是当我删除它时,我发现了这个:

所以似乎将python内置日志记录解析到stackdriver中的东西停止了解析日志严重性参数!如果我看起来很愚蠢,我很抱歉,但这是我唯一能想到的:/

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

提前感谢您的帮助。

【问题讨论】:

同样的问题,级别不再设置 - 曾经工作。 print() 也没有将级别(严重性)设置为 INFO。应该是 cloud.google.com/functions/docs/monitoring/logging#writing_logs 你已经向 issuetracker 报告了吗? 我也是;我什至尝试使用“severity”:“INFO,ERROR,etc.”的 json 格式日志有效负载,但无济于事。都以无用的“任何”级别显示。 仅供参考 - issuetracker.google.com/issues/124403972 + 我创建了一个 GCP 支持案例,因为这对我来说显然是一个错误。 【参考方案1】:

使用 Python 原生 logging 模块时,不再支持 Stackdriver Logging 严重性过滤器。

但是,您仍然可以使用Stackdriver Logging Client Libraries 创建具有特定严重性的日志。检查this documentation 参考Python 库,并检查this one 一些用例示例。

请注意,为了让日志位于正确的资源下,您必须手动配置它们,请参阅this list 了解支持的资源类型。 同样,每种资源类型都有一些required labels 需要出现在日志结构中。

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

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

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

【讨论】:

感谢琼的回答。坦率地说,我对谷歌在这方面有点失望。此更改对开发人员非常不友好,并且对 CF 日志中的基本严重性支持迈出了一大步。文档尚未更新,云功能的一个基本功能已变得更加冗长、不直观且配置繁琐。是否有任何关于这是否是临时变化或我们应该如何预期未来变化的内部信息? 除了记录(令人不安)之外,打印到标准或错误控制台也不会影响严重性。 G 是否也删除了该功能,并且仅适用于 Python ?使用 Logging 库不仅麻烦,而且在本地测试/开发功能时还需要监控 SD 日志,这很荒谬。 感谢您节省了我的时间。顺便说一句,我发现使用保留环境更方便labels="function_name": os.getenv('FUNCTION_NAME'), "region": os.getenv('FUNCTION_REGION')。另外,我试过没有.format("YOUR-PROJECT-ID"),它仍然有效 请注意,这不适用于google-cloud-logging==2.0.0。将与google-cloud-logging<=2.0.0 合作。 from google.cloud.logging.resource import Resource 不再是版本 2 中的模块 @Rose True,但似乎我无法再从google-cloud-logging<=2.0.0 导入资源。尽管this doc 仍在 2.6.0(最新)中导入资源【参考方案2】:

我遇到了同样的问题。

在@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.

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

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")

【讨论】:

第二种解决方案很有帮助,谢谢。但是,日志不区分警告和错误。 这也不会记录异常和回溯 第二种方法对我有用,即使它并不完美。我只能获取信息和错误级别才能工作【参考方案3】:

不想处理云日志库,我创建了一个自定义格式化程序,它发出 structured log 和 right fields,正如云日志所期望的那样。

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,
            
        )

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

# 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)

【讨论】:

【参考方案4】:

从 Python 3.8 开始,您可以简单地 print 一个带有 severitymessage 属性的 JSON 结构。例如:

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

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

【讨论】:

以上是关于Google Cloud Functions Python 日志记录问题的主要内容,如果未能解决你的问题,请参考以下文章

? Google Cloud Functions ?????? MongoDB Atlas ??

Google Cloud Functions 部署问题

如何从 Cloud Functions 连接 Google Cloud SQL?

Google Cloud Functions 通知 iOS

Google Cloud Functions Cron 作业不工作

在本地测试 Python Google Cloud Functions