tracing_gcloud_layer/
lib.rs

1mod config;
2mod default_mapper;
3mod gauth;
4pub mod google_logger;
5pub mod google_writer;
6mod log_entry;
7mod runtime;
8mod utils;
9
10use derive_builder::Builder;
11use google_logger::{GoogleLogger, LogMapper, LoggerError};
12use tracing_subscriber::Registry;
13
14use self::google_writer::GoogleWriterHandle;
15
16pub use config::GoogleWriterConfig;
17pub use default_mapper::DefaultLogMapper;
18pub use runtime::GoogleWriterRuntime;
19pub use utils::{extract_trace_id, get_severity};
20
21pub type DefaultGCloudLayerConfig = GCloudLayerConfig<DefaultLogMapper>;
22pub type DefaultGCloudLayerConfigBuilder = GCloudLayerConfigBuilder<DefaultLogMapper>;
23
24/// Configuration for setting up Google Cloud logging with `tracing`.
25///
26/// `GCloudLayerConfig` holds everything needed to build a `tracing_stackdriver` layer
27/// that sends logs to Google Cloud Logging. It supports custom log mappers, batching,
28/// and uses service account credentials for authentication.
29///
30/// Use `.build_layer()` to produce a ready-to-use `tracing` layer.
31#[derive(Builder, Clone)]
32#[builder(pattern = "owned", setter(into, strip_option))]
33pub struct GCloudLayerConfig<M: LogMapper = DefaultLogMapper> {
34    /// The log name shown in Cloud Logging (e.g., `"stdout"` or `"my-service"`).
35    log_name: String,
36    /// Raw bytes of a Google service account JSON key.
37    logger_credential: Vec<u8>,
38    #[builder(default)]
39    config: GoogleWriterConfig,
40    #[builder(default)]
41    log_mapper: M,
42}
43
44impl<M: LogMapper> GCloudLayerConfig<M> {
45    /// Builds a `tracing_stackdriver` layer using this config.
46    ///
47    /// Creates a `GoogleLogger` from the provided log name and credentials,
48    /// then wraps it in a `GoogleWriter` for async batching. Returns a
49    /// `tracing_stackdriver` layer that can be added to a subscriber.
50    ///
51    /// # Example
52    /// ```no_run
53    /// use tracing_gcloud_layer::DefaultGCloudLayerConfigBuilder;
54    /// use tracing_subscriber::prelude::*;
55    ///
56    /// #[tokio::main]
57    /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
58    ///     let svc_account_bytes = std::fs::read("svc-account.json")?;
59    ///
60    ///     let (layer, runtime) = DefaultGCloudLayerConfigBuilder::default()
61    ///         .log_name("my-service")
62    ///         .logger_credential(svc_account_bytes)
63    ///         .build()?
64    ///         .build_layer()?;
65    ///
66    ///     tracing_subscriber::registry().with(layer).init();
67    ///     runtime.shutdown().await;
68    ///     Ok(())
69    /// }
70    /// ```
71    pub fn build_layer(
72        self,
73    ) -> Result<
74        (
75            tracing_stackdriver::Layer<Registry, impl Fn() -> GoogleWriterHandle>,
76            GoogleWriterRuntime<M>,
77        ),
78        LoggerError,
79    > {
80        let GCloudLayerConfig {
81            config,
82            log_mapper,
83            log_name,
84            logger_credential,
85        } = self;
86
87        let log_name = std::sync::Arc::from(log_name);
88        let logger = GoogleLogger::new(log_name, logger_credential, log_mapper)?;
89
90        let runtime = GoogleWriterRuntime::new(logger.clone(), config.clone());
91
92        let layer = tracing_stackdriver::layer().with_writer({
93            let writer = runtime.writer();
94            move || writer.clone()
95        });
96
97        Ok((layer, runtime))
98    }
99}