使用 OpenTelemetry 在 Google 云 运行 上跟踪传播

Trace Propagation on Google Cloud Run with OpenTelemetry

我有一个 Flask 应用程序与 Python gRPC 服务通信,两者都部署在 Google 云 运行 上。在检测应用程序后,我可以在 Google Trace 上看到跟踪,但它们似乎都具有不同的跟踪 ID,这意味着跟踪没有在两个服务之间链接在一起。这是我的设置代码,用于在每侧设置 grpc/Flask 仪器设置的两个服务上进行跟踪:

import logging
from opentelemetry import trace
from opentelemetry.exporter.cloud_trace import CloudTraceSpanExporter
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import SimpleExportSpanProcessor
from opentelemetry.propagators import set_global_textmap
from opentelemetry.tools.cloud_trace_propagator import CloudTraceFormatPropagator
from google.auth.exceptions import DefaultCredentialsError

logger = logging.getLogger(__name__)

def setup_tracing():
    """
    Setup Tracing on Google Cloud. The Service Account Roles must have `Cloud Trace Agent`
    Role added for traces to be ingested.
    """

    trace.set_tracer_provider(TracerProvider())
    try:
        # If running on Google Cloud, will use instance metadata service account credentials to initialize
        trace.get_tracer_provider().add_span_processor(
            SimpleExportSpanProcessor(CloudTraceSpanExporter())
        )
        # Using the X-Cloud-Trace-Context header
        set_global_textmap(CloudTraceFormatPropagator())

        logger.info("Tracing Setup. Exporting Traces to Google Cloud.")
    except DefaultCredentialsError:
        # Not running on Google Cloud so will use console exporter
        from opentelemetry.sdk.trace.export import ConsoleSpanExporter
        trace.get_tracer_provider().add_span_processor(
            SimpleExportSpanProcessor(ConsoleSpanExporter())
        )
        logger.info("Tracing Setup. Exporting Traces to Console.")

在本地,我可以通过 ConsoleSpanExporter 看到两个服务上的跟踪 ID 匹配,但是在 Google Cloud 运行 上,它们显然不会在 Google Trace 上产生单独的跟踪,所以我想知道网络是否删除了服务之间的 headers 或其他事情正在发生,这意味着跟踪 ID 没有被传播?

作为额外说明,我还注意到 Cloud 运行 的 Trace/Span ID 前面的负载均衡器未使用 CloudTraceSpanFormatPropagator() 传播,这也让我的日志变得混乱因为日志没有针对请求嵌套在一起。

经过数小时的调试后发现 Python gRPC 客户端工具上的文档有问题。对于不安全的(本地主机)通道,文档有效并且客户端被检测。对于安全通道(Google 云 运行 的要求),您需要传入 channel_type='secure'。我不确定为什么要这样设计并在模块上提出问题:https://github.com/open-telemetry/opentelemetry-python-contrib/issues/365

此外,您需要使用 X-Cloud-Trace-Context header 来确保您的跟踪使用与 Google Cloud 运行 上的负载均衡器和 AppServer 相同的跟踪 ID和 Google Trace 中的所有 link,但它们的传播器的默认实现使用不能在 gRPC 元数据键中使用的大写字母,因此会引发验证错误。我把下面的 class 全部改为小写,现在一切正常:

https://github.com/GoogleCloudPlatform/opentelemetry-operations-python/blob/master/opentelemetry-tools-google-cloud/src/opentelemetry/tools/cloud_trace_propagator.py

最后,我遇到了一个长期存在的问题,即 link 将我的日志跟踪到 Google 云日志上,文档说使用十六进制跟踪 ID 和十六进制跨度 ID,但他们没有工作,因为我使用了错误的 OpenTelemetry 函数来格式化它们。但是这段代码有效,我现在可以在 Google Trace 的跟踪列表视图中看到我的日志和我的跟踪!

from opentelemetry import trace
from opentelemetry.trace.span import get_hexadecimal_trace_id, get_hexadecimal_span_id

        current_span = trace.get_current_span()
        if current_span:
            trace_id = current_span.get_span_context().trace_id
            span_id = current_span.get_span_context().span_id
            if trace_id and span_id:
                logging_fields['logging.googleapis.com/trace'] = f"projects/{self.gce_project}/traces/{get_hexadecimal_trace_id(trace_id)}"
                logging_fields['logging.googleapis.com/spanId'] = f"{get_hexadecimal_span_id(span_id)}"
                logging_fields['logging.googleapis.com/trace_sampled'] = True

花了一段时间,但我想这是我在一个新的、没有很好记录的(在这个领域)上选择 Alpha(刚刚变成 Beta)框架(OpenTelemetry)的错 Google 云服务。但是有了这些修复,现在一切正常,并且更容易调试问题并查看总的端到端请求!