如何获取Python Azure函数的异常信息(错误消息与堆栈跟踪)
我完全理解你的困扰——明明代码里有明确会抛出异常的地方,但Azure函数的日志流里只显示执行失败,看不到具体的错误消息和堆栈跟踪,排查问题简直像摸黑走路。下面我结合你的代码情况,给你几个实用的解决办法:
一、调整host.json的日志配置,开启详细日志输出
你当前的host.json日志配置比较基础,没有设置足够详细的日志级别,也没有配置让Python运行时输出更详细的错误信息。你可以修改host.json为以下内容:
{ "version": "2.0", "logging": { "applicationInsights": { "samplingSettings": { "isEnabled": true, "excludedTypes": "Request", "loggingLevel": { "default": "Information", "Function.zsdbi": "Debug" } } }, "logLevel": { "default": "Information", "azure.functions": "Information", "python_logging": { "level": "DEBUG", "redirectStandardOutput": true } } }, "extensionBundle": { "id": "Microsoft.Azure.Functions.ExtensionBundle", "version": "[4.*, 5.0.0)" } }
这里的关键调整:
- 开启了
python_logging的DEBUG级别,并且重定向标准输出到日志系统,确保print和异常信息能被捕获 - 给你的目标函数
Function.zsdbi单独设置了Debug级别日志,确保它的细节能被完整记录
二、在代码中主动捕获异常并记录完整堆栈
Azure函数对于未处理的异常,有时候不会自动把完整堆栈推送到日志流或Application Insights里。你可以修改你的函数代码,主动捕获异常,并用logging.exception来记录——这个方法会自动把完整的堆栈跟踪记录下来:
import azure.functions as func import logging import traceback import zsbiconfig app = func.FunctionApp() @app.timer_trigger(schedule="0 */1 * * * *", arg_name="myTimer", run_on_startup=True, use_monitor=False) def zsdbi(myTimer: func.TimerRequest) -> None: if myTimer.past_due: logging.info('The timer is past due!') logging.info('27 Python timer trigger function executed.') try: config = zsbiconfig.MyConfig(azure=True) print('config.ftp_host:', config.ftp_host) print('config.ftp_username:', config.ftp_username) print('config.ftp_password:', config.ftp_password) print('config.ftp_nonsense:', config.nonsense) # I will produce a Exception # err = triggerfunc.triggerfunc(config) except Exception as e: # 使用logging.exception会自动记录完整的堆栈跟踪 logging.exception("函数执行过程中抛出异常") # 也可以手动打印标准错误输出(配合host.json的重定向设置) traceback.print_exc() # 如果需要终止函数执行,可以重新抛出异常 raise return
另外要提醒你:你的zsbiconfig.MyConfig类里只定义了私有属性(比如_ftp_host),但你在代码里直接访问config.ftp_host其实是有问题的!Python不会自动把私有属性映射为公共属性,你需要给类添加@property装饰器的getter方法,不然访问config.ftp_host的时候,和访问config.nonsense一样都会抛出AttributeError。修改后的zsbiconfig.py可以参考:
import os class MyConfig: def __init__(self, ftp_host=None, ftp_username=None, ftp_password=None, sharepoint_url=None, sharepoint_clientid=None, sharepoint_clientsecret=None, azure=False): # 直接在初始化时合并传入参数和环境变量 self._ftp_host = ftp_host or os.getenv('FTP_HOST') self._ftp_username = ftp_username or os.getenv('FTP_USERNAME') self._ftp_password = ftp_password or os.getenv('FTP_PASSWORD') self._sharepoint_url = sharepoint_url or os.getenv('SHAREPOINT_URL') self._sharepoint_clientid = sharepoint_clientid or os.getenv('SHAREPOINT_CLIENTID') self._sharepoint_clientsecret = sharepoint_clientsecret or os.getenv('SHAREPOINT_CLIENTSECRET') self._azure = azure # 添加对应的@property getter方法,让外部可以访问属性 @property def ftp_host(self): return self._ftp_host @property def ftp_username(self): return self._ftp_username @property def ftp_password(self): return self._ftp_password # 其他需要访问的属性,也需要对应添加getter
三、在Application Insights中查询完整异常日志
当你调整了配置和代码之后,就可以在Application Insights里用Kusto查询来获取完整的异常信息了。打开你的函数应用对应的Application Insights资源,进入“日志”页面,执行以下查询:
exceptions | where operation_Name == "zsdbi" | order by timestamp desc | project timestamp, operation_Name, type, message, details
这个查询会列出你的zsdbi函数抛出的所有异常,包括完整的错误消息和堆栈跟踪细节。
四、本地调试时直接查看终端输出
如果你在本地调试Azure函数,记得留意终端输出——本地调试时Python会直接把未处理异常的完整堆栈打印到终端,这是最快速定位问题的方式之一。
备注:内容来源于stack exchange,提问作者mbieren

