הגדרה של איסוף נתוני מעקב באמצעות OpenTelemetry

במאמר הזה נסביר איך להגדיר מעקב בצד הלקוח ומעקב מקצה לקצה באמצעות OpenTelemetry. כדי להפעיל מעקב מקצה לקצה, צריך להגדיר מעקב בצד הלקוח. מידע נוסף זמין במאמר בנושא סקירה כללית על איסוף נתוני מעקב.

לפני שמתחילים

  • כדי לוודא שלחשבון השירות שבו האפליקציה משתמשת יש את ההרשאות הנדרשות להגדרת איסוף נתוני מעקב, צריך לבקש מהאדמין להקצות לחשבון השירות שבו האפליקציה משתמשת בפרויקט את תפקידי ה-IAM הבאים:

  • מוודאים ש-Cloud Trace ו-Telemetry API מופעלים בפרויקט. מידע נוסף על הפעלת ממשקי API זמין במאמר הפעלת ממשקי API.

הגדרת מעקב בצד הלקוח

כדי לייצא עקבות באמצעות פרוטוקול OpenTelemetry ‏(OTLP), צריך להגדיר את האפליקציה. אפשר לשלוח נתונים אל OpenTelemetry Collector או ישירות אל Cloud Trace דרך Telemetry API. שתי השיטות משתמשות באותן תלות והגדרות. ההבדל היחיד ביניהם הוא נקודת הקצה של OTLP שבה משתמשים ב-exporter.

ייצוא מעקבים באמצעות OpenTelemetry Protocol

כדי לייצא מעקבים באמצעות פרוטוקול OpenTelemetry, צריך להגדיר את OpenTelemetry SDK ואת כלי הייצוא OTLP:

  1. מוסיפים את יחסי התלות הנדרשים לאפליקציה באמצעות הקוד הבא:

    Java

    <dependency>
      <groupId>com.google.cloud</groupId>
      <artifactId>google-cloud-spanner</artifactId>
    </dependency>
    <dependency>
      <groupId>io.opentelemetry</groupId>
      <artifactId>opentelemetry-sdk</artifactId>
    </dependency>
    <dependency>
      <groupId>io.opentelemetry</groupId>
      <artifactId>opentelemetry-sdk-trace</artifactId>
    </dependency>
    <dependency>
      <groupId>io.opentelemetry</groupId>
      <artifactId>opentelemetry-exporter-otlp</artifactId>
    </dependency>

    המשך

    go.opentelemetry.io/otel v1.28.0
    go.opentelemetry.io/otel/sdk v1.28.0
    go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0

    Node.js

    "@opentelemetry/exporter-trace-otlp-grpc": "^0.57.0",
    "@opentelemetry/sdk-trace-base": "^1.26.0",
    "@opentelemetry/sdk-trace-node": "^1.26.0",

    Python

    pip install opentelemetry-api opentelemetry-sdk
    pip install opentelemetry-exporter-otlp

  2. מגדירים את האובייקט OpenTelemetry ומפעילים את האפשרות 'מעקב'.

    Java

    Resource resource = Resource
        .getDefault().merge(Resource.builder().put("service.name", "My App").build());
    
    OtlpGrpcSpanExporter otlpGrpcSpanExporter =
        OtlpGrpcSpanExporter
            .builder()
            .setEndpoint(otlpEndpoint) // Replace with your OTLP endpoint
            .build();
    
    // Using a batch span processor
    // You can use `.setScheduleDelay()`, `.setExporterTimeout()`,
    // `.setMaxQueueSize`(), and `.setMaxExportBatchSize()` to further customize.
    BatchSpanProcessor otlpGrpcSpanProcessor =
        BatchSpanProcessor.builder(otlpGrpcSpanExporter).build();
    
    // Create a new tracer provider
    sdkTracerProvider = SdkTracerProvider.builder()
        // Use Otlp exporter or any other exporter of your choice.
        .addSpanProcessor(otlpGrpcSpanProcessor)
        .setResource(resource)
        .setSampler(Sampler.traceIdRatioBased(0.1))
        .build();
    
    // Export to a collector that is expecting OTLP using gRPC.
    OpenTelemetry openTelemetry = OpenTelemetrySdk.builder()
        .setTracerProvider(sdkTracerProvider).build();
    
    // Enable OpenTelemetry traces before Injecting OpenTelemetry
    SpannerOptions.enableOpenTelemetryTraces();
    
    // Inject OpenTelemetry object via Spanner options or register as GlobalOpenTelemetry.
    SpannerOptions options = SpannerOptions.newBuilder()
        .setOpenTelemetry(openTelemetry)
        .build();
    Spanner spanner = options.getService();

    המשך

    
    // Ensure that your Go runtime version is supported by the OpenTelemetry-Go
    // compatibility policy before enabling OpenTelemetry instrumentation.
    
    // Enable OpenTelemetry traces by setting environment variable GOOGLE_API_GO_EXPERIMENTAL_TELEMETRY_PLATFORM_TRACING
    // to the case-insensitive value "opentelemetry" before loading the client library.
    
    ctx := context.Background()
    
    // Create a new resource to uniquely identify the application
    res, err := resource.Merge(resource.Default(),
    	resource.NewWithAttributes(semconv.SchemaURL,
    		semconv.ServiceName("My App"),
    		semconv.ServiceVersion("0.1.0"),
    	))
    if err != nil {
    	log.Fatal(err)
    }
    
    // Create a new OTLP exporter.
    defaultOtlpEndpoint := "http://localhost:4317" // Replace with the endpoint on which OTLP collector is running
    traceExporter, err := otlptracegrpc.New(ctx, otlptracegrpc.WithEndpoint(defaultOtlpEndpoint))
    if err != nil {
    	log.Fatal(err)
    }
    
    // Create a new tracer provider
    tracerProvider := sdktrace.NewTracerProvider(
    	sdktrace.WithResource(res),
    	sdktrace.WithBatcher(traceExporter),
    	sdktrace.WithSampler(sdktrace.TraceIDRatioBased(0.1)),
    )
    
    // Register tracer provider as global
    otel.SetTracerProvider(tracerProvider)

    Node.js

    const {NodeTracerProvider} = require('@opentelemetry/sdk-trace-node');
    const {
      OTLPTraceExporter,
    } = require('@opentelemetry/exporter-trace-otlp-grpc');
    const {
      BatchSpanProcessor,
      TraceIdRatioBasedSampler,
    } = require('@opentelemetry/sdk-trace-base');
    const {Resource} = require('@opentelemetry/resources');
    const {Spanner} = require('@google-cloud/spanner');
    
    // Define a Resource with service metadata
    const resource = new Resource({
      'service.name': 'my-service',
      'service.version': '1.0.0',
    });
    
    // Create an OTLP gRPC trace exporter
    const traceExporter = new OTLPTraceExporter({
      url: 'http://localhost:4317', // Default OTLP gRPC endpoint
    });
    
    // Create a provider with a custom sampler
    const provider = new NodeTracerProvider({
      sampler: new TraceIdRatioBasedSampler(1.0), // Sample 100% of traces
      resource,
      spanProcessors: [new BatchSpanProcessor(traceExporter)],
    });
    
    // Uncomment following line to register tracerProvider globally or pass it in Spanner object
    // provider.register();
    
    // Create the Cloud Spanner Client.
    const spanner = new Spanner({
      projectId: projectId,
      observabilityOptions: {
        tracerProvider: provider,
        enableExtendedTracing: true,
        enableEndToEndTracing: true,
      },
    });
    

    Python

    # Setup OpenTelemetry, trace and OTLP exporter.
    tracer_provider = TracerProvider(sampler=ALWAYS_ON)
    otlp_exporter = OTLPSpanExporter(endpoint="http://localhost:4317")
    tracer_provider.add_span_processor(BatchSpanProcessor(otlp_exporter))
    
    # Setup the Cloud Spanner Client.
    spanner_client = spanner.Client(
        project_id,
        observability_options=dict(tracer_provider=tracer_provider, enable_extended_tracing=True, enable_end_to_end_tracing=True),
    )

הגדרת מעקב מקצה לקצה

בקטע הזה מוסבר איך להגדיר מעקב מקצה לקצה בספריות לקוח של Spanner:

  1. מוסיפים את יחסי התלות הנדרשים לאפליקציה באמצעות הקוד הבא:

    Java

    התלות הקיימת במעקב בצד הלקוח מספיקה להגדרת מעקב מקצה לקצה. לא צריך להוסיף תלות כלשהי.

    המשך

    בנוסף ליחסי התלות שנדרשים למעקב בצד הלקוח, נדרש גם יחס התלות הבא:

    go.opentelemetry.io/otel/propagation v1.28.0

    Node.js

    התלות הקיימת במעקב בצד הלקוח מספיקה להגדרת מעקב מקצה לקצה. לא צריך להוסיף תלות כלשהי.

    Python

    התלות הקיימת במעקב בצד הלקוח מספיקה להגדרת מעקב מקצה לקצה. לא צריך להוסיף תלות כלשהי.

  2. הצטרפות למעקב מקצה לקצה.

    Java

    SpannerOptions options = SpannerOptions.newBuilder()
      .setOpenTelemetry(openTelemetry)
      .setEnableEndToEndTracing(/* enableEndtoEndTracing= */ true)
      .build();

    המשך

    כדי להפעיל את התכונה, משתמשים באפשרות EnableEndToEndTracing בהגדרות הלקוח.

    client, _ := spanner.NewClientWithConfig(ctx, "projects/test-project/instances/test-instance/databases/test-db", spanner.ClientConfig{
    SessionPoolConfig: spanner.DefaultSessionPoolConfig,
    EnableEndToEndTracing:      true,
    }, clientOptions...)

    Node.js

    const spanner = new Spanner({
    projectId: projectId,
    observabilityOptions: {
    tracerProvider: openTelemetryTracerProvider,
    enableEndToEndTracing: true,
    }
    })

    Python

    observability_options={
    "tracer_provider": tracer_provider,
    "enable_end_to_end_tracing": True,
    }
    spanner = spanner.Client(project_id, observability_options=observability_options)

  3. מגדירים את ההפצה של הקשר המעקב ב-OpenTelemetry.

    Java

    OpenTelemetry openTelemetry = OpenTelemetrySdk.builder()
      .setTracerProvider(sdkTracerProvider)
      .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance()))
      .buildAndRegisterGlobal();

    Go

    // Register the TraceContext propagator globally.
    otel.SetTextMapPropagator(propagation.TraceContext{})

    Node.js

    const {propagation} = require('@opentelemetry/api');
    const {W3CTraceContextPropagator} = require('@opentelemetry/core');
    propagation.setGlobalPropagator(new W3CTraceContextPropagator());

    Python

    from opentelemetry.propagate import set_global_textmap
    from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator
    set_global_textmap(TraceContextTextMapPropagator())

מאפיינים של מעקב מקצה לקצה

עקבות מקצה לקצה יכולות לכלול את המידע הבא:

שם המאפיין תיאור
service.name ערך המאפיין הוא תמיד spanner_api_frontend.
cloud.region האזור Google Cloud בענן של ממשק הקצה (frontend) של Spanner API שמשרת את בקשת האפליקציה.
gcp.spanner.server.query.fingerprint ערך המאפיין הוא טביעת האצבע של השאילתה. כדי לנפות באגים בשאילתה הזו, אפשר לעיין בעמודה TEXT_FINGERPRINT בטבלאות של נתוני השאילתות.
gcp.spanner.server.paxos.participantcount מספר המשתתפים בעסקה. מידע נוסף זמין במאמר Life of Spanner Reads & Writes.
gcp.spanner.isolation_level ערך המאפיין הוא רמת הבידוד של הטרנזקציה. הערכים האפשריים הם SERIALIZABLE ו-REPEATABLE_READ. מידע נוסף זמין במאמר סקירה כללית על רמות בידוד.

תיעוד עקבות לדוגמה

בעקבות מקצה לקצה אפשר לראות את הפרטים הבאים:

  • זמן האחזור בין האפליקציה לבין Spanner. אתם יכולים לחשב את זמן האחזור ברשת כדי לראות אם יש בעיות ברשת.
  • האזור ב-Cloud של חזית ה-API של Spanner שממנו מוגשות הבקשות של האפליקציה. אפשר להשתמש בזה כדי לבדוק קריאות חוצות אזורים בין האפליקציה לבין Spanner.

בדוגמה הבאה, בקשת האפליקציה שלכם מוגשת על ידי הקצה הקדמי של ה-API של Spanner באזור us-west1, וחביון הרשת הוא 8.542ms‏ (55.47ms – 46.928ms).

צפייה במעקב מקצה לקצה.

המאמרים הבאים