使用 OpenTelemetry 在 Google Cloud Run 上跟踪传播
Posted
技术标签:
【中文标题】使用 OpenTelemetry 在 Google Cloud Run 上跟踪传播【英文标题】:Trace Propagation on Google Cloud Run with OpenTelemetry 【发布时间】:2021-05-27 04:22:06 【问题描述】:我有一个 Flask 应用程序与 Python gRPC 服务通信,两者都部署在 Google Cloud Run 上。检测应用程序后,我可以在 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 看到两个服务上的 Trace ID 匹配,但是在 Google Cloud Run 上,它们显然不会在 Google Trace 上产生单独的跟踪,所以我想知道 Networking 是否删除了服务之间的标头还是发生了其他事情,这意味着跟踪 ID 没有被传播?
作为额外说明,我还注意到 Cloud Run 的 Trace/Span ID 前面的负载均衡器没有使用 CloudTraceSpanFormatPropagator() 进行传播,这也使我的日志变得混乱,因为日志没有嵌套在一起用于请求.
【问题讨论】:
您的问题和答案非常有帮助,因为我尝试将跟踪添加到类似的设置中 - 感谢您如此彻底!我也遇到了跟踪传播的问题(***.com/questions/69440929/…),尽管您发现的错误已得到修复。这是一个很长的镜头,但如果你有机会看看我的问题,我会非常感激,因为感觉这方面的文档仍然有些缺乏! 【参考方案1】:经过数小时的调试,结果发现它是关于 Python gRPC 客户端工具的糟糕文档。对于不安全的(本地主机)通道,文档有效并且客户端被检测。对于安全通道(根据 Google Cloud Run 的要求),您需要传入 channel_type='secure'
。我不确定为什么会这样设计并在模块上提出问题:https://github.com/open-telemetry/opentelemetry-python-contrib/issues/365
此外,您需要使用 X-Cloud-Trace-Context
标头来确保您的跟踪使用与 Google Cloud 上运行的负载平衡器和 AppServer 相同的跟踪 ID,并在 Google Trace 中链接,但其传播器的默认实现使用不能在 gRPC 元数据键中使用的大写字母,因此会引发验证错误。我参加了下面的课程并将其全部设为小写,现在一切正常:
https://github.com/GoogleCloudPlatform/opentelemetry-operations-python/blob/master/opentelemetry-tools-google-cloud/src/opentelemetry/tools/cloud_trace_propagator.py
最后,我在将我的日志链接到 Google Cloud 日志上的跟踪时遇到了一个长期存在的问题,文档说使用 Hex Trace ID 和 Hex Span 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) 的错。但是有了这些修复,现在一切正常,并且更容易调试问题并查看完整的端到端请求!
【讨论】:
以上是关于使用 OpenTelemetry 在 Google Cloud Run 上跟踪传播的主要内容,如果未能解决你的问题,请参考以下文章
Google Cloud Trace Opentelemetry Java 示例代码未显示在 Google Cloud Trace 仪表板上
如何将 OpenTelemetry Java 代理生成的跟踪导出到 Google Cloud Trace?
如何在 gRPC 服务器存根中从 ctx 创建 OpenTelemetry span