在 AWS Lambda 中使用 python 日志记录
Posted
技术标签:
【中文标题】在 AWS Lambda 中使用 python 日志记录【英文标题】:Using python Logging with AWS Lambda 【发布时间】:2016-10-08 18:53:34 【问题描述】:正如 AWS 文档所建议的那样:
import logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)
def my_logging_handler(event, context):
logger.info('got event'.format(event))
logger.error('something went wrong')
现在我做了:
import logging
logging.basicConfig(level = logging.INFO)
logging.info("Hello World!")
第一个 sn-p 代码打印在 Cloud Watch
控制台中,但第二个没有。
我没有看到任何区别,因为两个 sn-ps 使用的是根记录器。
【问题讨论】:
你缺少“return 'Hello World!'” 为什么不和第一个代码sn-p一样呢?获取已经实例化的记录器,然后使用该记录器。 @HEADLESS_0NE:我可以使用第一个。但我想了解为什么会出现这种行为。 还可以在pypi.org/project/python-cloud-logger 上查看 python-cloud-logger。它提供了具有上下文日志记录的选项,其中 requestId 和其他上下文变量可以保存到线程的上下文中。从那时起,每条日志都会携带上下文。 【参考方案1】:日志记录似乎不起作用的原因是 AWS Lambda Python 运行时pre-configures a logging handler,根据所选运行时的版本,它可能会修改所记录消息的格式,并且还可能将一些元数据添加到记录(如果有)。 not 预配置的是日志级别。这意味着无论您尝试发送哪种类型的日志消息,它都不会实际打印。
作为AWS documents themselves,要在AWS Lambda上下文中正确使用logging
库,您只需要设置root-logger的日志级别:
import logging
logging.getLogger().setLevel(logging.INFO)
如果您希望您的 Python 脚本既可以在 AWS Lambda 上执行,又可以通过您的本地 Python 解释器执行,您可以检查是否配置了处理程序,然后回退到 basicConfig
(它会创建默认的 stderr -handler) 否则:
if len(logging.getLogger().handlers) > 0:
# The Lambda environment pre-configures a handler logging to stderr. If a handler is already configured,
# `.basicConfig` does not execute. Thus we set the level directly.
logging.getLogger().setLevel(logging.INFO)
else:
logging.basicConfig(level=logging.INFO)
【讨论】:
用len(logging.getLogger().handlers) > 0
代替logging.getLogger().hasHandlers()
可能会更好。
@ebk 这是一个很好的观点,但 hasHandlers
仅在 Python 3.2 之后才可用。由于AWS still supports the Python 2.7 runtime,使用len(...handlers)
是目前最便携的解决方案。
你是对的。我应该添加“for Python 3.2+”:)
python if logging.getLogger().handlers: 怎么样?读起来类似于 3.2+ 版本,而且更惯用。【参考方案2】:
直接从问题@StevenBohrer 的答案链接中的最高答案复制到(这对我有用,用我自己的配置替换最后一行):
root = logging.getLogger()
if root.handlers:
for handler in root.handlers:
root.removeHandler(handler)
logging.basicConfig(format='%(asctime)s %(message)s',level=logging.DEBUG)
【讨论】:
谢谢,太好了。我把它放在我的 import 语句之后,然后我的整个 lambda/module 可以访问我自己的个人记录器:) 刚刚在 basicConfig 之后添加了这一行:logger = logging.getLogger() 从 python 3.8 开始,有一个新参数force
与您上面描述的完全一样:logging.basicConfig(level = logging.INFO, force=True)
。 docs.python.org/3/library/logging.html#logging.basicConfig【参考方案3】:
我遇到了类似的问题,我怀疑 lambda 容器正在调用 logging.basicConfig 以在导入 lambda 代码之前添加处理程序。这似乎是一种糟糕的形式......
解决方法是查看是否配置了根记录器处理程序,如果是,则删除它们,添加我的格式化程序和所需的日志级别(使用 basicConfig),然后恢复处理程序。
看这篇文章Python logging before you run logging.basicConfig?
【讨论】:
【参考方案4】:我一直在努力解决这个确切的问题。适用于本地和 AWS CloudWatch 的解决方案是像这样设置您的日志记录:
import logging
# Initialize you log configuration using the base class
logging.basicConfig(level = logging.INFO)
# Retrieve the logger instance
logger = logging.getLogger()
# Log your output to the retrieved logger instance
logger.info("Python for the win!")
【讨论】:
这对我不起作用。不得不使用OP发布的第一个块代码。 哪个方面没用?在 AWS CloudWatch 上登录还是在本地登录? 本地记录按预期工作。除非出现错误,否则无法在 cloudwatch 上查看日志。 和@Gru有同样的经历【参考方案5】:实际上可能没有引用同一个记录器。
在第一个 sn-p 中,记录返回:logging.Logger.manager.loggerDict
它将返回已初始化的记录器的dict
。
另外,来自logging
文档,关于logging.basicConfig
的重要说明:
通过使用默认格式化程序创建 StreamHandler 并将其添加到根记录器来为日志记录系统进行基本配置。如果没有为根记录器定义处理程序,函数 debug()、info()、warning()、error() 和 critical() 将自动调用 basicConfig()。
如果根记录器已经为其配置了处理程序,则此函数不执行任何操作。
来源:https://docs.python.org/2/library/logging.html#logging.basicConfig
【讨论】:
sn-ps 是分开的。所以第二个 sn -p 没有配置日志记录,所以它将配置根记录器。如果我调用 logging.info 它将使用根记录器。对我来说,和第一个 sn-p 没什么区别。 @HEADLESS_0NE 就在这里。似乎在 lambda 中已经配置了一个记录器。如果我执行上述操作但将级别设置为 DEBUG,那么我看到的日志比我产生的要多(我自己没有产生任何这些日志):[DEBUG] 2016-10-29T09:01:28.376Z 45e6c8bd-9db6-11e6-aa56-43d43acb066b Acquiring 0 [DEBUG] 2016-10-29T09:01:28.389Z 45e6c8bd-9db6-11e6-aa56-43d43acb066b IOWriteTask('offset': 0) about to wait for the following futures [] [DEBUG] 2016-10-29T09:01:28.389Z 45e6c8bd-9db6-11e6-aa56-43d43acb066b IOWriteTask('offset': 0) done waiting for dependent futures
【参考方案6】:
基本上,AWS 日志记录猴子补丁需要以非常特殊的方式处理,其中:
-
日志级别从脚本的 TOP 级别设置(例如,在导入时)
您感兴趣的日志语句是从 lambda 函数中调用的
由于在 Python 模块导入中不运行任意代码通常被认为是一种很好的形式,因此您通常应该能够重组代码,以便仅在 lambda 函数内部进行繁重的工作。
【讨论】:
【参考方案7】: LOGGER = logging.getLogger()
HANDLER = LOGGER.handlers[0]
HANDLER.setFormatter(
logging.Formatter(“[%(asctime)s] %(levelname)s:%(name)s:%(message)s”, “%Y-%m-%d %H:%M:%S”)
)
【讨论】:
正如目前所写,您的答案尚不清楚。请edit 添加其他详细信息,以帮助其他人了解这如何解决所提出的问题。你可以找到更多关于如何写好答案的信息in the help center。以上是关于在 AWS Lambda 中使用 python 日志记录的主要内容,如果未能解决你的问题,请参考以下文章
在单个AWS Lambda中使用两个python函数boto3
如何在 AWS Lambda 中使用 Python 自定义包
在 AWS Lambda 的子目录中打包 Python 依赖项