tracing_gcloud_layer/
lib.rs

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