Simplify Your OTel Trace With Google Cloud

OpenTelemetry (OTel) is the go-to standard for monitoring applications, offering a vendor-neutral way to capture telemetry data like traces, metrics, and logs. This enables consistent instrumentation and avoids vendor lock-in. Developers widely use OTel to instrument applications, with exporting telemetry data to Google Cloud Observability services.

OTel’s native data format follows OTLP (standing for OpenTelemetry Protocol) standard. To export OTel data to Google Cloud usually requires exporters like Google Cloud Trace Exporter for Go that exist for most of the popular programming languages.

What these exporters do is:

  1. Transform the telemetry data from OTLP format into a proprietary format defined by the Cloud Observability service (e.g. Cloud Trace).
  2. Sends the transformed data using the service API.

While this approach works, you should consider several factors when using Google Cloud-specific exporters.

  • Additional Complexity: In some configurations the use of the Google Cloud-specific exporter library requires extra dependencies or customization to OTel collector pipeline.
  • Vendor Awareness: If the export code is a part of the application, using a specific vendor’s exporter makes the instrumentation code depending on this vendor. If you ever need to send telemetry to a different backend, the change will require adding another vendor-specific exporter.
  • Risk of Data Loss: Despite the best effort the transformation of the telemetry data from the OTLP data format to the proprietary format can result in some data loss. For example it can occur if the proprietary format has different limits or doesn’t support certain OTLP fields.

In Q2 2025 Google Cloud introduced support for OTLP (referenced as Telemetry API). At this moment (Q3’ 2025) it supports only Cloud Trace. Now developers can use OTel native exporter to post data to the trace endpoint:

https://telemetry.googleapis.com/v1/traces

To use the Telemetry API to write traces you will need Cloud Telemetry Traces Writer (roles/telemetry.tracesWriter) role or, if you authenticate using OAuth, the following OAuth scopes:

  • https://www.googleapis.com/auth/trace.append
  • https://www.googleapis.com/auth/cloud-platform

Migrating from the Trace exporter to the native OTLP endpoint

Let’s see how the use of Telemetry API looks in practice using an example of the Go application that already uses OTel to generate metrics and traces and uses Google Cloud-specific exporters.

The first step is to add reading the application default credentials from the runtime environment. Because the example runs as a Cloud Run service, its default credentials is the service account that is associated with the service. The changes are added to the setup.go file that configures telemetry. Two packages are added to the import section:

import (
// add the following import packages
  "google.golang.org/grpc"
  "google.golang.org/grpc/credentials/oauth"
)

And the setupTelemetry() method is modified to read the default credentials with the appropriate scope:

func setupTelemetry(ctx context.Context) (shutdown func(context.Context) error, err error) {

  // add the following code after the call to otel.SetTextMapPropagator()
  scopes := []string{
    "https://www.googleapis.com/auth/trace.append",
    "https://www.googleapis.com/auth/cloud-platform",
  }
  creds, err2 := oauth.NewApplicationDefault(ctx, scopes...)
  if err2 != nil {
    err = errors.Join(err2, shutdown(ctx))
    return
  }

// ...
}

The second step replaces the existing exporter with the native OTLP exporter and configures it to use the credentials from the first step. Like before, the import section is modified to remove Google Trace exporter’s package and to add otlptracegrpc:

import (
// replace package github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/trace with the following two
  "go.opentelemetry.io/otel/attribute"
  "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
)

And the method setupTelemetry() is modified to replace the trace exporter initialiation:

func setupTelemetry(ctx context.Context) (shutdown func(context.Context) error, err error) {

// replace resource creation call to resource.New() with the following
  res, err2 := resource.New(ctx,
      resource.WithDetectors(gcp.NewDetector()),
      resource.WithTelemetrySDK(),
      resource.WithAttributes(
          semconv.ServiceNameKey.String(os.Getenv("K_SERVICE")),
          attribute.String("gcp.project_id", projectID),
      ),
  )

// replace the call to cloudtrace.New() with the following
  texporter, err2 := otlptracegrpc.New(ctx,
      otlptracegrpc.WithEndpoint("telemetry.googleapis.com:443"),
      otlptracegrpc.WithDialOption(grpc.WithPerRPCCredentials(creds)),
  )

// ...
}

The above changes do the following:

  • Each span in the trace will be generated with additional attribute gcp.project_id that is used by Telemetry API to determine the span’s destination
  • The native OTLP exporter is configured to use the Telemetry API endpoint with the Cloud Run service’s service account credentials

This example uses OTLP/gRPC exporter, which is the recommended transport for Google Cloud APIs. The format of the endpoint follows the hostname:port notation requested for gRPC. An OTLP/HTTP alternative (otlptracehttp) also exists. It would require using https://... URL for the endpoint and different credential handling.

This is all. After these changes are applied, do not forget to update dependencies and download missing packages by running the go CLI command:

go mod tidy

Now your code does all the same but uses native OTLP to export trace data to Cloud Trace. You can see examples for Java, NodeJS and Python in the same repository.

Note that the example configures the resource attribute and the OTLP exporter’s endpoint in the code. It is done to avoid unexpected value injections. The same configuration can be done using environment variables. You can see the migration guide in documentation for the example.

Before running the example, ensure you have completed the following:

  1. Enable the Telemetry API on the project where you deploy the example. Use the following command to do it from the shell:

    gcloud service enable telemetry.googleapis.com --project=${YOUR_PROJECT_ID}
    
  2. The example deploys Cloud Run service that uses the default compute engine service account. The service account associated with the service should be granted roles/telemetry.tracesWriter role to allow it using Telemetry API.

Migrate OTel Collector configuration

Before wrapping up, let’s look at what to do if the application uses OTel Collector instead of having the exporter coded inside the source code. In this scenario the migration includes only changes in the OTel Collector configuration. Follow these steps to update the collector’s configuration file and restart the collector.

  1. Remove the googlecloud exporter from the configuration and from the traces pipeline
  2. Modify the collector’s configuration with the changes shown below:
extensions:
  # add auth extension
  googleclientauth:

processors:
  # add resource attribute
  resource/gcp_project_id:
    attributes:
    - key: gcp.project_id
      value: "YOUR_PROJECT_ID"
      action: insert

exporters:
  # add OTLP exporter
  otlp:
    auth:
      authenticator: googleclientauth
    endpoint: telemetry.googleapis.com:443

service:
  # update the following lists by appending the values after …,
  extensions: […, googleclientauth]
  pipelines:
    traces:
      exporters: […, otlp]
      processors: […, resource/gcp_project_id]

These changes do the following:

  • Add the googleclientauth extension that reads the application default credentials from the runtime environment
  • Insert the gcp.project_id resource attribute with the value of the project ID to which spans will be exported
  • Sets the OTLP exporter’s endpoint and authentication configuration to enable the exporter to send spans to Telemetry API

The changes in the service section reflect the added extension, processor and exporter to the existing lists. Note that the list of the trace exporters under the service section should not include the Google Trace Exporter unless you want to duplicate the spans.

The use of the googleclientauth extension reads credentials at runtime and eliminates the need to statically store credentials such as OAuth client ID or secret inside the configuration file.

The OTLP exporter and the googleclientauth extension are a part of most popular builds of the OTel collector. (e.g. Google-Built OTel Collector) If the build of the OTel Collector in use does not include them, follow documentation to build the version of the collector with these packages.

Wrapping up

Using native OTLP exporter for transferring spans to Cloud Trace has no drawbacks and many benefits including:

  • Reduced complexity
  • Vendor agnostic pipeline
  • Elimination of potential data loss
  • Alignment with OTel recommended practices

If your code already uses OTel to generate traces, it is very easy to convert it to using native OTLP endpoint of Google Cloud.

Telemetry API supports OTLP endpoint only for spans now. The support for metrics and logs will be added in the future.

For additional code samples and information look at