自动测量是一种魔法:使用OpenTelemetry Python和Lightstep

663 阅读11分钟

如果你是一个Golang开发者,这一切都很好,但如果你使用Python呢?好吧,我的朋友,你很幸运,因为今天,我将看看如何用Python将OpenTelemetry数据发送到Lightstep。

与OTel Golang的帖子一样,我们可以通过三种方式之一将OTel数据发送到Lightstep(或者任何其他支持OpenTelemetry协议(OTLP)的Observability工具)。

在这篇文章中,我将详细介绍这三种方法中的每一种,并附上代码片段,解释如何将数据送入Lightstep Observability。让我们开始吧!

OpenTelemetry和Lightstep

Lightstep Observability支持本地OpenTelemetry协议(OTLP)。它可以通过HTTPgRPC接收OTLP格式的数据。你需要在你的代码中指定你希望使用的方法,我们将在接下来的代码片段中看到。

如果你对OpenTelemetry使用gRPC和HTTP感到好奇,请查看这些文档

注意。其他支持 OTLP 的可观察性工具包括HoneycombGrafanaJaeger

自动仪表和Python

使用 OTel 来检测你的 Python 代码,有一件事超级酷,那就是 Python 提供了自动(auto)检测。这意味着什么呢?在高层次上,它意味着你可以运行一个Python OpenTelemetry代理,它包裹着你的Python应用程序,以自动检测它。🪄

更具体地说,自动仪表使用垫片或字节码仪表代理,在运行时或编译时拦截你的代码,为你依赖的库和框架添加跟踪和度量仪表。自动监测的好处是它需要最少的努力。坐下来,放松,享受表演。许多流行的Python库都有自动仪表功能,包括FlaskDjango。你可以在这里找到完整的列表。

手动仪表需要在你的代码中添加跨度、上下文传播、属性等。这类似于对你的代码进行注释或编写测试。

这是否意味着你不应该手动检测?完全不是!这意味着你不应该手动测试。如果有自动仪器,就从自动仪器开始。如果自动仪表对你的用例来说还不够(通常是不够的),那就加入手动仪表。例如,自动仪表不知道你的业务逻辑--它只知道框架和语言--在这种情况下,你会想手动仪表你的业务逻辑,这样你就能获得这种可见性。

前提条件

在开始我们的教程之前,有一些你需要的东西。

如果你想运行完整的代码示例,你还需要。

如果你开始用OpenTelemetry来测量你的应用程序,这可能是大多数初学者最常采取的途径。顾名思义,我们是直接从我们的应用程序代码中向一个特定的Observability后端发送数据。

otel-to-ls-direct

我们的示例应用程序是一个Flask应用程序。我们将同时利用自动和手动仪表。

下面让我们来详细了解一下。

1- 设置你的环境

让我们来设置我们的工作目录和Python虚拟环境

mkdir otel_python
cd otel_python

python3 -m venv .
source ./bin/activate
touch server.py

打开server.py ,并粘贴以下内容。

from flask import Flask, request
from opentelemetry import trace
from random import randint
tracer = trace.get_tracer_provider().get_tracer(__name__)

app = Flask(__name__)

@app.route("/rolldice")
def roll_dice():
    return str(do_roll())

@tracer.start_as_current_span("do_roll")
def do_roll():
    res = randint(1, 6)
    current_span = trace.get_current_span()
    current_span.set_attribute("roll.value", res)
    current_span.set_attribute("operation.name", "Saying hello!")
    current_span.set_attribute("operation.other-stuff", [1, 2, 3])
    return res

if __name__ == "__main__":
    app.run(port=8082, debug=True, use_reloader=False)

2- 安装所需的 OTel 库

这些是将数据发送到一个 观察力后端(例如Lightstep)。

有几个值得注意的项目。

  • 安装opentelemetry-distro 将安装其他一些用于仪器化代码的依赖包,包括opentelemetry-apiopentelemetry-sdk
  • opentelemetry-instrumentation-flask 包用于对 Flask 应用程序进行自动仪表化。
  • opentelemetry-exporter-otlp-proto-grpc 包用于通过 gRPC 将 OTel 数据发送到你的 Observability 后端(例如 Lightstep)。

3- 安装自动仪表

在上面的步骤中,我们添加了opentelemetry-instrumentation-flask 库,它用于自动测量我们的 Python Flask 应用程序;但是,我们仍然缺少一块拼图。你可能还记得,在这篇文章的前面,Python的自动仪表使用了一个代理,它包装了我们的Python应用程序并自动为我们添加了一些高级仪表。这与opentelemetry-instrumentation-flask 库相结合,使这种神奇成为可能。

我们像这样安装代理。

opentelemetry-bootstrap -a install

这就安装了一个叫做opentelemetry-instrument 的二进制文件,这就是所有魔法发生的地方。

4- 运行应用程序

这里是有趣的地方!通常情况下,为了运行这个应用程序,我们会像这样运行它。

但如果我们这样做,我们就不会向Lightstep发送任何OTel数据。所以我们必须这样做。

export OTEL_EXPORTER_OTLP_TRACES_HEADERS="lightstep-access-token="
opentelemetry-instrument \
    --traces_exporter console,otlp_proto_grpc \
    --metrics_exporter console,otlp_proto_grpc \
    --service_name test-py-auto-otlp-grpc-server \
    --exporter_otlp_traces_endpoint "ingest.lightstep.com:443" \
    python server.py

一些值得注意的事项。

  • 用你自己的Lightstep Access Token替换 。
  • --traces_exporter 告诉我们要把我们的痕迹发送到哪里。在这种情况下,我们要把它发送到 (stdout)和 。 选项告诉 ,我们想把它发送到一个通过gRPC接受OTLP的端点。你也可以用 代替,因为它是 的一个别名。 的可用选项的完整列表可以console otlp_proto_grpc otlp_proto_grpc opentelemetry-instrument otlp otlp_proto_grpc --traces_exporter 在这里找到。
  • --exporter_otlp_traces_endpoint 告诉 OTLP 端点,将我们的痕迹直接发送到 Lightstep,地址是 。opentelemetry-instrument ingest.lightstep.com:443
  • --service_name 设置我们服务的名称。这是我们将在Lightstep服务资源管理器中看到的值。
  • 注意,最后一行是python server.py ,这是我们运行我们的应用程序的地方。在这里,opentelemetry-instrument ,包裹着对python server.py

样本输出。

Screen captuere of Python server app sample output

想使用HTTP而不是gRPC?首先,你需要确保已经安装了pip包opentelemetry-exporter-otlp-proto-http (应该作为安装opentelemetry-exporter-otlp 的一部分自动安装)。

接下来,你的opentelemetry-instrument 命令将看起来像这样。

opentelemetry-instrument \
   --traces_exporter console,otlp_proto_http \
   --metrics_exporter console,otlp_proto_http \
   --service_name test-py-auto-otlp-server \
   --exporter_otlp_traces_endpoint "https://ingest.lightstep.com/traces/otlp/v0.9" \
   python server.py

注意HTTP端点是不同的,我们在--traces_exporter 标志中使用otlp_proto_http 而不是otlp_proto_grpc

5- 调用/rolldice服务

打开一个新的终端窗口,并运行以下内容。

curl http://localhost:8082/rolldice

运行上面这一行将返回一个1到6之间的随机数字。没有什么太突出的地方。但如果你看一下server.py 的终端窗口,你会注意到输出中的一些东西。

Screen capture of Python server output after client call

我们看到了来自server.py 的跟踪!为什么我们会在这里看到这个?因为我们把--traces_exporter 标志设置为console,otlp_proto_grpc ,它通过 OTLP 输出到 Lightstep输出到控制台。

6- 在Lightstep中看到它

python-server-otlp-ls Screen capture of trace in Lightstep - OTLP direct

OpenTelemetry收集器

向 Observability 后端发送数据的下一个方法是通过OpenTelemetry Collector。对于非开发设置,这是将 OpenTelemetry 数据发送到 Observability 后端的推荐方法。

otel-to-ls-via-collector

通过 OTel 采集器发送 OTel 数据与我们在上述直接来自应用程序的示例中的做法几乎相同。唯一的区别是。

  • 我们需要运行一个 OTel 采集器
  • 当我们运行opentelemetry-instrument ,我们的选项略有不同

让我们在下面更详细地了解一下。

1- 按照 "直接来自应用程序"的例子中的步骤1-3进行操作

2- 运行收集器

首先,我们需要配置我们的收集器,以便向Lightstep发送数据。我们通过从Lightstep的opentelemetry-examples repo中抓取collector.yml 来做到这一点。

git clone git@github.com:lightstep/opentelemetry-examples.git

打开一个新的终端窗口。首先,你需要编辑collector.yml 文件。请确保用你自己的Lightstep访问令牌替换${LIGHTSTEP_ACCESS_TOKEN}

现在你可以启动采集器了。

cd opentelemetry-examples/collector/vanilla
docker run -it --rm -p 4317:4317 -p 4318:4318 \
    -v $(pwd)/collector.yml:/otel-config.yaml \
    --name otelcol otel/opentelemetry-collector-contrib:0.53.0  \
    "/otelcol-contrib" \
    "--config=otel-config.yaml"

样本输出。

collector-startup

3- 运行该应用程序

opentelemetry-instrument \
   --traces_exporter console,otlp \
   --metrics_exporter console,otlp \
   --service_name test-py-auto-collector-server \
   python server_uninstrumented.py

一些值得注意的事项。

  • 上面的命令与我们的Direct from Application例子非常相似,只是我们缺少了--exporter_otlp_endpoint 选项。这是因为如果我们漏掉这个选项,那么opentelemetry-instrument 就会假定它正在连接到 OTel Collector 的端点localhost:4317
  • 我们不需要设置OTEL_EXPORTER_OTLP_TRACES_HEADERS ,因为这已经在采集器的config.yml文件中配置好了。
  • 如果你希望使用 HTTP 而不是 gRPC,你需要用--traces_exporter console,otlp_proto_http 替换--traces_exporter console,otlp 。注意,otlpotlp_proto_grpc 的一个别名。

输出示例。

Screen captuere of Python server app sample output

4- 调用/rolldice服务

打开一个新的终端窗口,并运行以下程序。

curl http://localhost:8082/rolldice

样本输出。

Screen capture of Python server output after client call

同样,我们看到了server.py 的跟踪,因为我们把 --traces_exporter 标志设置为 console,otlp,它通过 OTLP 输出到采集器控制台。

5- 在Lightstep中看到它

Screen capture of trace in Lightstep - Collector

启动器

如果你认为向Lightstep发送OTel数据很容易,那么通过OTel Python Launcher就更容易了!你可以把它看作是一个OTel包装。可以把它看作是一个OTel包装器,通过为你预先配置一堆东西来降低入门门槛,使发送数据到Lightstep变得特别容易。

通过Launcher发送OTel数据与我们在上面的Direct from Application例子中所做的几乎相同,但有一些小的区别。

  • 我们有更少的包来(耶!)。
  • 当我们运行opentelemetry-instrument ,我们的选项略有不同

让我们看看它的运行情况吧?

1- 按照 "直接来自应用程序"的例子的步骤1-3进行操作

小改动:用这些替换步骤2中的库。

# OTel-specific
pip install opentelemetry-launcher
pip install protobuf==3.20.1

# App-specific
pip install requests
pip install flask

我们需要强制使用一个特定版本的protobuf ,因为Launcher与新版本的兼容性问题。这在opentelemetry-python已经被修复

当我们安装opentelemetry-launcher 包的时候,它也会起到双重作用,不需要我们运行opentelemetry-bootstrap -a install

2- 运行该应用程序

export LS_ACCESS_TOKEN=""

opentelemetry-instrument \
    --service_name test-py-auto-launcher-server \
    python server.py

看起来我们的选择比较少,不是吗?让我们深入了解一下一些值得注意的事项。

  • 我们不需要指定一个--exporter_otlp_traces_endpoint ,因为这已经隐含地为我们做了,并设置为ingest.lightstep.com:443
  • 我们不需要为我们的Lightstep Access Tokenexport OTEL_EXPORTER_OTLP_TRACES_HEADERS="lightstep-access-token=" )设置一个看起来很乱的环境变量,而只需要这样做。export LS_ACCESS_TOKEN="",这看起来更干净。

如果你希望首先通过一个采集器实例发送你的OTel数据,而不是直接从你的应用程序发送,你可以这样做。

opentelemetry-instrument \
    --service_name test-py-auto-launcher-server \
    --exporter_otlp_traces_endpoint "0.0.0.0:4317" \
    --exporter_otlp_traces_insecure true \
    python server.py

请注意我们不必设置LS_ACCESS_TOKEN ,因为这已经在采集器的config.yml文件中配置好了。只要确保你有一个正在运行的OTel收集器实例就可以了

另外,一定要设置--exporter_otlp_traces_insecure true 。如果你使用收集器并隐式配置它,这是必需的,就像我们在这里做的那样。只有在采集器中没有配置证书的情况下才需要这样做。

输出样本。

Screen captuere of Python server app sample output

3- 调用/rolldice服务

打开一个新的终端窗口,并运行以下程序。

curl http://localhost:8082/rolldice

样本输出。

Screen captuere of Python server app sample output for Launcher

请注意,由于我们的opentelemetry-instrument 调用没有指定一个--traces_exporter ,它相当于说--traces_exporter otlp_proto_grpc 。我也意味着没有跟踪输出到控制台(stdout)。

4- 在Lightstep中看到它

Screen capture of trace in Lightstep - Launcher

我应该总是使用自动仪表代理吗?

即使你使用的Python库没有自动仪表代理,opentelemetry-instrument 仍然有帮助吗?我个人认为是的!考虑一下这个文件,client.py

from sys import argv

from requests import get

from opentelemetry import trace
from opentelemetry.propagate import inject
tracer = trace.get_tracer_provider().get_tracer(__name__)

assert len(argv) == 2

with tracer.start_as_current_span("client"):

   with tracer.start_as_current_span("client-server"):
       headers = {}
       inject(headers)
       requested = get(
           "http://localhost:8082/rolldice",
           params={"param": argv[1]},
           headers=headers,
       )

       assert requested.status_code == 200

让我们用自动仪表代理来运行上面的程序。请确保用你自己的Lightstep Access Token替换 。

export OTEL_EXPORTER_OTLP_TRACES_HEADERS="lightstep-access-token="

opentelemetry-instrument \
    --traces_exporter console,otlp \
    --service_name test-py-auto-client \
    --exporter_otlp_endpoint "ingest.lightstep.com:443" \
    python client.py test

请注意,除了在client.py 中创建跨度之外,里面没有 OTEL 配置。你不需要配置服务名称、输出器或端点。这些都是在你运行opentelemetry-instrument 时处理的。另外,如果你的代码恰好使用了一个自动指示的库,你就不必再做任何其他事情了。

***注意。***如果你想知道为什么我们要执行python client.py test 这个命令,那是因为client.py 需要一个参数,在这个例子中,这个参数叫做test

gRPC调试

你有没有想过你的gRPC调用是否进入了一个黑洞?我肯定会这么想。当我在为 Golang OTel 库的 gRPC 忙活时,我了解到一些 gRPC 调试标志,这些标志可以使我在排除 gRPC 连接问题时更加容易。这当然让我想知道是否有类似的 Python。结果是有的。在运行你的应用程序之前设置这些环境变量,你就可以了。

export GRPC_VERBOSITY=debug
export GRPC_TRACE=http,call_error,connectivity_state

这意味着,当我们启动我们的server.py ,我们会得到这样的结果。

Screen captuere of Python server app sample output with gRPC debug

然后当我们通过curl 调用我们的端点时,我们得到这样的结果。

Screen capture of Python server app sample output with gRPC degug showing successful gRPC call

上面突出显示的部分告诉我,我们的gRPC调用成功了!

最后的思考

在Python中的自动测量是非常可怕的,它真的降低了OpenTelemetry的入门门槛。正如我们所看到的直接来自应用和采集器的例子,代码几乎保持不变。唯一的区别是,你需要改变一些标志,以便自动监测代理知道把你的痕迹发送到哪里。很好,很简单!

如果你想知道,还有一种完全纯粹的OTel Python手动仪表方法,我将在未来的博文中介绍,敬请期待现在,让我们沉浸在你今天学到的关于 OTel Python 自动仪表的超酷知识中吧