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

Cloud Logging API

The logs-api feature adds a sink that writes through the Cloud Logging API (logging.googleapis.com), for hosts with no logging agent to collect stdout. Entries are queued and written in batches by a background task on the Tokio runtime that build_async was called on.

    let (log_layer, log_handle) = GcpCloudLoggingLayerBuilder::new(google_project_id)
        .with_cloud_logging_api(GcpCloudLoggingApiConfig::new(LogId::new(
            "gcloud-observability-example",
        )?))
        .build_async()
        .await?;

    // The OpenTelemetry layer goes before the logging layer: the logging layer reads the span
    // context the OpenTelemetry layer attaches, and sees only what is registered ahead of it.
    let subscriber = Registry::default()
        .with(tracing_opentelemetry::layer().with_tracer(tracer))
        .with(log_layer);
    tracing::subscriber::set_global_default(subscriber)?;

GcpCloudLoggingApiConfig::new takes a LogId, the log the entries go to: 1 to 511 letters, digits and / _ - .. LogId::from_static checks a constant at compile time. A / is URL-encoded as %2F in the logName, as Cloud Logging stores it.

SettingDefault
with_resourcethe global monitored resource, labelled with the project ID
with_batch_size200 entries
with_flush_interval2 seconds
with_queue_capacity10 000 entries
with_shutdown_timeout5 seconds

A monitored resource is the resource an entry is attributed to, such as gce_instance or k8s_container. Set one with with_resource to have entries grouped with the rest of that resource’s logs.

A batch is written when batch_size entries are queued, or flush_interval after its first entry. When the queue is full, new entries are dropped instead of blocking the thread that logged them, and a message on stderr reports the drops.

Shutting down

build_async returns the layer and a GcpCloudLoggingHandle. Call handle.shutdown().await before the process ends: it closes the queue and waits, bounded by the shutdown timeout, for the final write. Dropping the handle without it leaves the queued entries unwritten. flush and shutdown are async and block no thread, so they work on a current-thread runtime.

Full example available here.