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}