Распространение трассировки в Google Cloud Run с OpenTelemetry

У меня есть приложение Flask, которое общается с сервисом Python gRPC, оба развернуты в Google Cloud Run. Я могу видеть следы в Google Trace после инструментирования приложений, но все они, похоже, имеют разные идентификаторы 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 я могу видеть, что идентификаторы трассировки в обеих службах совпадают, однако в Google Cloud Run они явно не приводят к отдельным трассировкам в Google Trace, поэтому мне интересно, удаляет ли Сеть заголовки между службами или что-то еще происходит, что означает, что идентификатор трассировки не распространяется?

В качестве дополнительной заметки я также заметил, что балансировщик нагрузки перед идентификаторами Trace / Span в Cloud Run не распространяется с помощью CloudTraceSpanFormatPropagator (), что также делает мои журналы беспорядочными, поскольку журналы не вложены вместе для запросов.




Ответы (1)


После нескольких часов отладки выясняется, что документация по клиентскому инструментарию Python gRPC была плохой. Для небезопасных (localhost) каналов документация работает, а клиент оснащён инструментами. Для безопасных каналов (необходимых для Google Cloud Run) вам необходимо передать channel_type='secure'. Я не уверен, почему он был разработан таким образом и вызвал проблему с модулем: https://github.com/open-telemetry/opentelemetry-python-contrib/issues/365

Кроме того, вам необходимо использовать заголовок X-Cloud-Trace-Context, чтобы ваши трассировки использовали тот же идентификатор трассировки, что и балансировщик нагрузки и AppServer в Google Cloud, и все они связаны в 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

Это заняло некоторое время, но я думаю, что это моя вина, что я выбрал альфа-версию (только что перешедшую в бета-версию) (OpenTelemetry) для новой, не очень хорошо документированной (в этой области) службы Google Cloud. Но с этими исправлениями теперь все работает, и намного проще отлаживать проблемы и видеть полный сквозной запрос!

person dgildeh    schedule 05.03.2021