Opentelemetry:无法以简单/干净的方式将跨度与跟踪链接起来

问题描述 投票:0回答:2

当尝试在跨度中添加跨度链接时,直接的方法
我在文档中阅读过,不起作用。我总是得到

AttributeError: 'Context' object has no attribute 'trace_id'

我的最新尝试

重现问题的简化代码

from opentelemetry import trace
from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator
from shared_functionality.common.observability import make_global_tracer

make_global_tracer()
tracer = trace.get_tracer(__name__)


def message_broker_consumer_runner():
    with tracer.start_as_current_span(name=f"consumer_runner.{None}") as consume_span:
        carrier = {}
        TraceContextTextMapPropagator().inject(carrier)
        return carrier


def api_gateway():
    with tracer.start_as_current_span(name=f"api_gateway.{None}") as consume_span:
        carrier = {}
        TraceContextTextMapPropagator().inject(carrier)
        return carrier


def update_info(__trace_propagator):
    print(f"{__trace_propagator=}")


def end(consumer_runner_carrier):
    print(f"{consumer_runner_carrier=}")
    consumer_runner_span = trace.NonRecordingSpan(
        TraceContextTextMapPropagator().extract(consumer_runner_carrier)
    )
    consumer_runner_context = consumer_runner_span.get_span_context()
    with tracer.start_as_current_span(
        name="trigger_update.info",
        context=api_gateway(),  # to show the API Gateway trigger as causal parent.
        links=[
            trace.Link(consumer_runner_context)
        ],  # to show consumer running function as co-parent/linked.
    ) as msg_span:
        update_info(
            __trace_propagator=msg_span.get_span_context()
        )  # Trace further passed to track business logic function.


if __name__ == "__main__":
    end(message_broker_consumer_runner())

错误

consumer_runner_carrier={'traceparent': '00-624066a40219dec50ed88de4feb4ee7a-1be9a825202fa729-01'}
__trace_propagator=SpanContext(trace_id=0x7ae344302d28c0000ea8d4b5457aff39, span_id=0x851a6758cb28f8b7, trace_flags=0x01, trace_state=[], is_remote=False)
{
    "name": "consumer_runner.None",
    "context": {
        "trace_id": "0x624066a40219dec50ed88de4feb4ee7a",
        "span_id": "0x1be9a825202fa729",
        "trace_state": "[]"
    },
    "kind": "SpanKind.INTERNAL",
    "parent_id": null,
    "start_time": "2023-10-10T18:39:20.205144Z",
    "end_time": "2023-10-10T18:39:20.205172Z",
    "status": {
        "status_code": "UNSET"
    },
    "attributes": {},
    "events": [],
    "links": [],
    "resource": {
        "attributes": {
            "telemetry.sdk.language": "python",
            "telemetry.sdk.name": "opentelemetry",
            "telemetry.sdk.version": "1.20.0",
            "service.name": "data_fetcher",
            "service.version": "1.0",
            "deployment.environment": "development"
        },
        "schema_url": ""
    }
}
{
    "name": "api_gateway.None",
    "context": {
        "trace_id": "0x565151dfcc4cffbbd44e953d2c8ba27a",
        "span_id": "0x3e3e8a6265a6e481",
        "trace_state": "[]"
    },
    "kind": "SpanKind.INTERNAL",
    "parent_id": null,
    "start_time": "2023-10-10T18:39:20.205270Z",
    "end_time": "2023-10-10T18:39:20.205287Z",
    "status": {
        "status_code": "UNSET"
    },
    "attributes": {},
    "events": [],
    "links": [],
    "resource": {
        "attributes": {
            "telemetry.sdk.language": "python",
            "telemetry.sdk.name": "opentelemetry",
            "telemetry.sdk.version": "1.20.0",
            "service.name": "data_fetcher",
            "service.version": "1.0",
            "deployment.environment": "development"
        },
        "schema_url": ""
    }
}
Exception while exporting Span batch.
Traceback (most recent call last):
  File "/usr/local/lib/python3.11/site-packages/opentelemetry/sdk/trace/export/__init__.py", line 368, in _export_batch
    self.span_exporter.export(self.spans_list[:idx])  # type: ignore
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/opentelemetry/sdk/trace/export/__init__.py", line 522, in export
    self.out.write(self.formatter(span))
                   ^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/opentelemetry/sdk/trace/export/__init__.py", line 513, in <lambda>
    ] = lambda span: span.to_json()
                     ^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/opentelemetry/sdk/trace/__init__.py", line 492, in to_json
    f_span["links"] = self._format_links(self._links)
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/opentelemetry/sdk/trace/__init__.py", line 535, in _format_links
    ] = Span._format_context(  # pylint: disable=protected-access
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/opentelemetry/sdk/trace/__init__.py", line 500, in _format_context
    x_ctx["trace_id"] = f"0x{trace_api.format_trace_id(context.trace_id)}"
                                                       ^^^^^^^^^^^^^^^^
AttributeError: 'Context' object has no attribute 'trace_id'

OpenTelemetry 版本

Python 3.11.4

opentelemetry-api                         1.20.0
opentelemetry-distro                      0.41b0
opentelemetry-exporter-otlp               1.20.0
opentelemetry-exporter-otlp-proto-common  1.20.0
opentelemetry-exporter-otlp-proto-grpc    1.20.0
opentelemetry-exporter-otlp-proto-http    1.20.0
opentelemetry-instrumentation             0.41b0
opentelemetry-instrumentation-aws-lambda  0.41b0
opentelemetry-instrumentation-dbapi       0.41b0
opentelemetry-instrumentation-grpc        0.41b0
opentelemetry-instrumentation-httpx       0.41b0
opentelemetry-instrumentation-logging     0.41b0
opentelemetry-instrumentation-pymongo     0.41b0
opentelemetry-instrumentation-requests    0.41b0
opentelemetry-instrumentation-sqlite3     0.41b0
opentelemetry-instrumentation-tortoiseorm 0.41b0
opentelemetry-instrumentation-urllib      0.41b0
opentelemetry-instrumentation-urllib3     0.41b0
opentelemetry-instrumentation-wsgi        0.41b0
opentelemetry-propagator-aws-xray         1.0.1
opentelemetry-proto                       1.20.0
opentelemetry-sdk                         1.20.0
opentelemetry-semantic-conventions        0.41b0
opentelemetry-util-http                   0.41b0

当我使用Pycharm的调试器暂停执行时,我可以看到

consumer_runner_context
的属性对象,它在其属性树深处有一个trace_id,因此我可以访问它:

consumer_runner_context.get(list(consumer_runner_context.keys())[0]).get_span_context()

这有效:

    with tracer.start_as_current_span(
        name="trigger_update.info",
        context=api_gateway(),  # to show the API Gateway trigger as causal parent.
        links=[trace.Link(consumer_runner_context.get(list(consumer_runner_context.keys())[0]).get_span_context())]
    )

但这似乎不是正确的方法。

正确的做法是什么?

python open-telemetry
2个回答
0
投票

至于答案 - 是的,据我所知,这是目前的做法。

ctx = propagate.extract(carrier)
sctx = next(iter(ctx.values())).get_span_context()
link = trace.Link(sctx)

在尝试了一段时间的 Links 之后,在我看来,它们(仍然)是 Otel 家族中有点被忽视的孩子。 如有错误,请指正。

我现在想到的两个例子:

  • 链接的可视化(例如在 Jaeger、SigNoz...)是非常基础的。人们只看到简单的“引用”(指向某处),这比什么都没有好,但使调试变得困难。

  • 通常仅在当前跨度中才发现要链接的跨度,而事先并不知道。仅仅为了捕获链接而创建新的子跨度通常是不需要的。在这里,我很想看到

    span.add_link()
    方法。


0
投票

不知道这是否有帮助,但我注意到 Python OpenTelemetry SDK 生成的跟踪信号的 JSON 模式与(例如)手动上传时 Tempo 接受的 JSON 模式之间存在多个差异。例如:

  1. SDK 会生成用于扫描的 JSON 文件,其中“属性”字段是一个对象(“{}”),但如果我手动将其更改为数组(“[]”),我只能将其导入到 Tempo 中。

  2. 正如最初的问题提到的,这个 JSON 片段是由 SDK 生成的,但 Tempo 导入有问题:

    “上下文”:{ “trace_id”:“0x624066a40219dec50ed88de4feb4ee7a”, “span_id”:“0x1be9a825202fa729”, “trace_state”:“[]” },

要导入它,我必须将其替换为单独的字段(即消除“上下文”并将 JSON 结构中的 id 字段提升一级),字段名称遵循 Camel 约定:

    "traceId": "0x624066a40219dec50ed88de4feb4ee7a",
    "spanId": "0x1be9a825202fa729",
  1. 与官方示例相反(例如,在https://github.com/open-telemetry/opentelemetry-proto/blob/39339ef177218cc965b8cf863d761775ec668858/examples/trace.json中),“scopeSpans”构造不被识别从 Grafana UI 手动导入期间的节奏(即 Grafana 会说没有导入数据),需要将其替换为“instrumentationLibrarySpans”(尽管它们显然意味着不同的东西,但至少导入是这样工作的)。

对我来说,结果是:在我相当简单的用例中可能会避免使用 Python OpenTelemetry SDK。我将编写自己的代码(“迷你库”)来生成 JSON 有效负载,我通过实验预先验证该负载将被 Tempo 接受。这对我来说很有效,因为我的代码行很小,但对于拥有许多开发人员的更大系统来说显然是行不通的。有点令人失望的是,OpenTelemetry/Grafana 人员无法在他们支持的 JSON 模式方面保持同步。

© www.soinside.com 2019 - 2024. All rights reserved.