Python 应用在不同场景下有不同的接入方式,本文介绍 Python 应用通过 OpenTelemetry 接入的详细操作,接入后可以实现自动收集Trace信息、自动生成Metric指标、以及调用链检索、日志检索等功能。
通过 OpenTelemetry 接入
OpenTelemetry 是 CNCF 的一个可观测性项目,旨在提供可观测性领域的标准化方案,解决观测数据的数据模型、采集、处理、导出等的标准化问题,提供与三方 vendor 无关的服务。
如果您的应用已经接入了 OpenTelemetry 的 SDK,APM 服务端可以接收 OpenTelemetry 上报的数据。接入 APM 后,您将获得RED指标生成能力、Trace 多维检索、单链路检索、拓扑生成等多项能力。
使用限制
- 其中,APMPlus 采用 Prometheus 作为 OpenTelemetry Metrics 的存储,支持 promql 对 metrics 进行查询,具体应用请参见 自定义看板 和 报警管理。
- OpenTelemetry Metrics 转换为 Prometheus Metrics 时,存在一定限制:
- 不支持聚合方式为 delta 的数据。请不要修改 SDK 侧的默认聚合配置,保证 SDK 侧数据的聚合方式为 cumulative。
- 工作区拥有独立的数据上报凭证,如需使用工作区进行数据管理和数据隔离,请确保 apmplus-opentelemetry-collector 组件已经升级至 v3.1.0 及以上版本。
若使用 gevent 协程,需要配置环境变量 GEVENT_ENABLE=true。例如,程序中有使用如下协程时,需要设置环境变量 GEVENT_ENABLE=true。
如果您的应用使用 Django 框架,在接入前需要注意如下事项:
- 要在 K8s 环境通过 OpenTelemetry 自动接入,需要确保 Python 版本为 3.8 及以上;
- OpenTelemetry 的引入,可能会导致 Django 应用不再使用默认的配置文件,需要通过环境变量重新指定配置文件:
- 可以在项目的启动脚本中加入此设置项,或者通过 YAML 文件添加环境变量:
自动接入
APM OpenTelemetry Collector 是 APM 基于 OpenTelemetry Collector 二次开发的数据采集器,遵守 Apache2.0 协议,支持采集 OpenTelemetry 监控数据,同时支持采集 Prometheus 指标、应用监控数据和 Kubernetes 资源指标。
- 安装 APM OpenTelemetry Collector。
- 通过 VKE 集群组件中心,白屏安装 apmplus-opentelemetry-collector 组件。前往 VKE 集群界面,选择 组件管理 -> 监控,单击 apmplus-opentelemetry-collector 组件右上角...中的安装,完成 Apmplus OpenTelemetry Collector 的部署和管理。
-
- 在服务的 Kubernetes Deployment 配置中增加instrumentation.apmplus.volcengine.com/inject-python和instrumentation.apmplus.volcengine.com/workspace注解。代码示例如下:
采用社区提供的 Opentelemetry Python SDK 手动埋点的方式上报数据,可以参考社区提供的 接入文档 和 python demo 完成 Python 项目构建。 通过 opentelemetry-instrument 完成埋点上报
opentelemetry-distro 包安装了 API、SDK,以及 opentelemetry-bootstrap 和 opentelemetry-instrument 工具。
- 如果指定数据直接上报至 ApmPlus 后端,示例如下:
- 如果指定数据上报至 Collector,则无需指定 exporter_otlp_headers,示例如下:
通过 opentelemetry-sdk 手动埋点
Opentelemetry 官方文档相关介绍参考 Instrumentation。官方文档中的 Demo 将 metrics 和 trace 打印到 console,需要上报到 collector 的数据,除了需要换用 grpc/http exporter 外,还需要设置 endPoint、 headers 等信息。 上报地址推荐使用 collector endpoint,参考 Demo 示例如下:
对于日志的上报,除了需要初始化 LoggerProvider, 建议使用 opentelemetry LoggingInstrumentor 对 logging 库进行插装,从而将 log 与 trace 关联起来。
- 初始化 LoggerProvider 并添加 LoggingInstrumentor
Python 应用的日志采集依赖 Opentelemetry,完成上述 OpenTelemetry 接入 Python 应用的全部流程,即可自动采集和上报日志信息。
Opentelemetry Python 日志通过 logging 库插桩方式实现,通过 Log 信息增强和添加对应上报 handler,将日志上报到 APMPlus 后端并关联 Trace 和 Span 等信息。因此,只有通过 logging 库打印的日志,才能采集并发送到 APMPlus,控制台等其他方式无法采集日志信息。
Python 应用中的一条日志,从诞生到通过 OpenTelemetry 发送再到上报 APMPlus 后端的完整流程如下:
采集 Python 应用日志时,需要注意以下情况。
Python logging 库存在 Log level 配置,默认为 WARNING。 当记录日志小于 level 配置时,实际不会进行日志打印操作,同样也不会上报到 APMPlus 服务端。因此,如需采集 INFO、DEBUG 等日志,必须通过 logging.basicConfig 手动设置 Log level,示例代码如下:
为了更好区分日志,业务通常不会直接使用 logging 进行日志记录,而是使用 logging.getLogger(name) 创建 logger,再通过 logger 进行日志记录。而 Opentelemetry logging 基于 root logger 进行埋点。因此,当使用 logger 进行日志记录,并且设置了 propagate = False 时,logger 记录的日志不会传播到 root logger, 也无法被 opentelemetry 采集上报。
每个通过 logging.getLogger(name) 创建的 logger 实例均存在 propagate 属性,默认为 True,工作原理如下。
- propagate = True (默认): 当 logger 处理完一条日志后,将进行 propagate 标志检查,若为 True,这条日志记录将继续向上传递给父 logger (parent logger)。此过程一直持续到 root logger。
- propagate = False: 当 logger 处理完一条日志后,将停止向上传播。其父 logger 及更高层级的祖先 logger 将完全不感知这条日志的存在。
日志记录需要关联日志所在的请求 Trace,因此,在 Opentelemetry LoggingInstrumentor 中会对 Log 信息进行增强,将获取日志打印时的上下文信息并存放在 Log 信息中。但当实际业务中采用异步方式记录日志时,可能丢失上下文信息,此时,日志无法关联到 Trace,将导致 APMPlus 日志页面的 TraceId 信息显示为空。
当日志采集时发现并没有日志数据采集时,排除注意事项中提及的情况后,可通过主动添加相应日志的方式进行问题排查。示例如下:
- 在 logging basicConfig 设置后和打印日志前添加以下代码,将可以打印出 logging 库的 handler 和 level 信息。
此时,若 LoggingInstrumentor 生效,则输出信息的 logging.root.handlers 中会包含以下 handler。
- 若使用 logger 打印日志,可使用以下代码打印日志。
此时,若 LoggingInstrumentor 生效,则输出信息的 logging.root.handlers 中会包含以下 handler。