Monitor performance with client-side traces

To monitor and debug Firestore requests end-to-end, you can enable traces in the Java client library. Client-side tracing can provide a signal about the performance as experienced by your application, as well as insights that can help with debugging issues.

Client-side traces, which are collected by executing RPCs from the client, provide the following information:

  • Spans with timestamps of when the client sent the RPC request and when the client received the RPC response, including latency introduced by the network and client system
  • Attributes (key-value pairs) that surface information about the client and its configuration
  • Logs associated with key events in the spans
  • Stack traces if a crash occurs in the client

OpenTelemetry

Traces for the Java client library are instrumented using OpenTelemetry APIs. OpenTelemetry is an industry standard, open-source observability framework. OpenTelemetry offers a wide range of tools such as instrumentation APIs and SDKs, collectors, backend-specific exporters and flexible configuration options such as sampling controls, span limits, and more.

Export traces with exporters and collectors

As part of your configurations, you can export your traces to an observability backend. Most observability service providers offer exporters for you to use, such as Cloud Trace.

In addition to an exporter, OpenTelemetry recommends setting up a Collector. A Collector lets your service offload data quickly and lets the collector take care of additional handling like retries, batching, and encryption. A Collector runs alongside your application. The collector receives OTLP messages, processes the messages, and exports them to your observability backend.

Limitations

Client-side traces have the following limitations:

  • Traces spans are available for the Java client library.
  • The client library does not produce trace spans for real-time listeners.

Billing

In addition to Firestore usage, client-side tracing can incur charges.

There are no charges for collecting traces or usage of the OpenTelemetry framework.

Ingestion of trace spans into your observability backend may be billable. For example, if you use Cloud Trace as your backend, you are billed according to Cloud Trace pricing. If you use another observability service provider, find out their billing model and associated costs.

To better understand billing, start with a small trace sampling ratio (trace a small percentage of your RPCs) based on your traffic.

Before you begin

Before you begin:

  • Make sure you set up the service account under which your app writes traces to your observability backend with the necessary Identity and Access Management roles:

    Trace operation IAM role
    Read traces roles/cloudtrace.user
    Write traces roles/cloudtrace.agent
    Read/write traces roles/cloudtrace.admin
  • Verify Trace API is enabled on this project.

Configure client-side traces

This section provides example configurations for client-side traces. You can export to a Collector or directly to an observability backend. You also have the following options for configuring client-side traces:

Export traces to a Collector with OpenTelemetry APIs

The following code configures the Firestore Java client library to export spans with a 10% sampling ratio to an OpenTelemetry Collector.

Java (Admin)

Resource resource = Resource
  .getDefault().merge(Resource.builder().put(SERVICE_NAME, "My App").build());

OtlpGrpcSpanExporter otlpGrpcSpanExporter =
  OtlpGrpcSpanExporter
  .builder()
  .setEndpoint("http://localhost:4317") // Replace with your OTLP endpoint
  .build();

// Using a batch span processor
// You can also use other `BatchSpanProcessorBuilder` methods
// to further customize.
BatchSpanProcessor otlpGrpcSpanProcessor =
  BatchSpanProcessor.builder(otlpGrpcSpanExporter).build();

// Export to a collector that is expecting OTLP using gRPC.
OpenTelemetry otel = OpenTelemetrySdk.builder()
        .setTracerProvider(SdkTracerProvider.builder()
            .setResource(resource)
            .addSpanProcessor(otlpGrpcSpaaudit-loggingnProcessor)
            .setSampler(Sampler.traceIdRatioBased(0.1))
            .build());

Firestore firestore = FirestoreOptions
  .newBuilder()
  .setOpenTelemetryOptions(
    FirestoreOpenTelemetryOptions.newBuilder()
      .setTracingEnabled(true)
      .setOpenTelemetry(otel)
      .build())
  .build().getService();

    

Export directly to an observability backend with OpenTelemetry APIs

The following code configures the Java client library to directly export trace spans to Cloud Trace with a 10% trace sampling ratio. You can use other observability service providers' exporters to directly export to their backend. If your observability backend supports OTLP ingestion, you can use OpenTelemetry OtlpGrpcSpanExporter to export to your backend rather than using a custom exporter.

Java (Admin)

// TraceExporter needed for this use case
import com.google.cloud.opentelemetry.trace.TraceExporter;

Resource resource = Resource
  .getDefault().merge(Resource.builder().put(SERVICE_NAME, "My App").build());
SpanExporter gcpTraceExporter = TraceExporter.createWithDefaultConfiguration();

// Using a batch span processor
// You can also use other `BatchSpanProcessorBuilder` methods
// to further customize.
SpanProcessor gcpBatchSpanProcessor =
  BatchSpanProcessor.builder(gcpTraceExporter).build();

// Export directly to Cloud Trace with 10% trace sampling ratio
OpenTelemetry otel = OpenTelemetrySdk.builder()
        .setTracerProvider(SdkTracerProvider.builder()
            .setResource(resource)
            .addSpanProcessor(gcpBatchSpanProcessor)
            .setSampler(Sampler.traceIdRatioBased(0.1))
            .build());

Firestore firestore = FirestoreOptions
  .newBuilder()
  .setOpenTelemetryOptions(
    FirestoreOpenTelemetryOptions.newBuilder()
      .setTracingEnabled(true)
      .setOpenTelemetry(otel)
      .build())
  .build().getService();

    

Export to a Collector with Auto Agents

Run your OpenTelemetry Collector with OTLP gRPC receivers enabled. Set the agent's exporter to otlp and specify the endpoint where the agent should export the data. The following example uses a 10% sampling ratio and sends traces to the Collector that listens on localhost port 4317.

Terminal

FIRESTORE_ENABLE_TRACING=ON                            \
java                                                   \
-javaagent:path/to/opentelemetry-javaagent.jar         \
-Dotel.traces.exporter=otlp                            \
-Dotel.exporter.otlp.endpoint="http://localhost:4317"  \
-Dotel.traces.sampler=traceidratio                     \
-Dotel.traces.sampler.arg=0.1                          \
-Dotel.service.name="My App"                           \
-jar myapp.jar

    

Export directly to an observability backend with Auto Agents

In addition to setting the environment variable FIRESTORE_ENABLE_TRACING=ON, you need to add the OpenTelemetry Java agent extension for your specific backend. The following example uses the Trace exporter extension and a 10% trace sampling ratio.

Terminal

FIRESTORE_ENABLE_TRACING=ON                                                \
java                                                                       \
-javaagent:path/to/opentelemetry-javaagent.jar                             \
-Dotel.javaagent.extensions=/path/to/exporter-auto-0.26.0-alpha-shaded.jar \
-Dotel.traces.exporter=google_cloud_trace                                  \
-Dotel.traces.sampler=traceidratio                                         \
-Dotel.traces.sampler.arg=0.1                                              \

    

Example trace

The following examples show how trace information is displayed in Cloud Trace. For more information about possible attributes and values, see Trace span attributes and events.

Example trace span

A trace span viewed from Cloud Trace

Example event log

A trace span event log viewed from Cloud Trace

Example attribute values

Attribute values of a trace span viewed from Cloud Trace

Example Stack Trace and Exception Event

A stack trace viewed from Cloud Trace

An exception event viewed from Cloud Trace

What's next