Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Error Reporting

Cloud Error Reporting groups the log entries it recognises as errors, counts them and shows them in one list. The logging layer writes that format on every sink when it is built with a service context:

    let (log_layer, log_handle) = GcpCloudLoggingLayerBuilder::new(google_project_id)
        .with_cloud_logging_api(GcpCloudLoggingApiConfig::new(LogId::new(
            "gcloud-observability-example",
        )?))
        .with_error_reporting(
            ServiceContext::new("gcloud-observability-error-reporting-example")
                .with_version(env!("CARGO_PKG_VERSION")),
        )
        .build_async()
        .await?;

    // The filter keeps the Cloud Logging client's own debug events out of the log it writes.
    let subscriber = Registry::default()
        .with(EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")))
        .with(log_layer);

ServiceContext::new(service) names the service errors are grouped under, such as the Cloud Run service or the binary name, and with_version sets the deployed version Error Reporting shows beside the error.

Every event at ERROR severity or above becomes an error event, including an event with a severity field of critical, alert or emergency. Other events are untouched. The entry gets:

  • @type, the ReportedErrorEvent type, which makes Error Reporting evaluate the entry;
  • serviceContext, from the ServiceContext;
  • context.reportLocation, from the file and line of the event, with the module path as the function name;
  • context.httpRequest, mapped from the http_request.* fields when the event has them;
  • a message made of the event message, the error, and a backtrace.

Without with_error_reporting an error event is written like any other.

The error in the message

Pass the error to the event as a &dyn Error, so that its source() chain is kept:

tracing::error!(error = &failure as &dyn std::error::Error, order_id, "checkout failed");

The first line of message is the event message followed by the Display of the error and of each source, outermost first: checkout failed: payment declined: card expired. error = %err and error = ?err record only the text they format, so the chain stops at the outer error.

The chain stays on that first line, and no Caused by: lines follow it: Error Reporting keys a group on the cause such a line names, so unrelated errors that share a root cause would become one group.

Grouping

Error Reporting groups errors with the same first line and error text, and it does so wherever they were logged: two call sites that log the same header and error are one group. A different text is a different group. Keep text that varies between occurrences, such as an order ID, in a field instead of the message.

context.reportLocation is always set, so grouping works without a backtrace. Error Reporting groups by the top frames of a stack trace when it has one.

OTLP sink

On the OTLP sink the body carries the same keys, so they reach jsonPayload, and the severity number is 17 or above. The sink also sets the exception.type and exception.message attributes, which Google maps to labels. A &dyn Error has no type name on stable Rust, so exception.type is set from an exception.type event field when the event has one.

Entries sent over OTLP are grouped by Error Reporting like the others.

Full example available here.

See Google’s Formatting error messages for the format.