Skip to main content

scouter_settings/
storage.rs

1use crate::ScouterServerConfig;
2use scouter_types::StorageType;
3use serde::Serialize;
4use std::path::PathBuf;
5
6#[derive(Debug, Clone, Serialize)]
7pub struct ObjectStorageSettings {
8    pub storage_uri: String,
9    pub storage_type: StorageType,
10    pub region: String, // this is aws specific
11    /// How often the Delta Lake compaction (Z-ORDER optimize) runs for trace tables. Default: 24h.
12    pub trace_compaction_interval_hours: u64,
13    /// How often the span buffer flushes to Delta Lake. Default: 5s.
14    pub trace_flush_interval_secs: u64,
15}
16
17impl Default for ObjectStorageSettings {
18    fn default() -> Self {
19        let storage_uri = std::env::var("SCOUTER_STORAGE_URI")
20            .unwrap_or_else(|_| "./scouter_storage".to_string());
21
22        let storage_type = ScouterServerConfig::get_storage_type(&storage_uri);
23
24        // need to set this for aws objectstore
25        let region = std::env::var("AWS_REGION").unwrap_or_else(|_| "us-east-1".to_string());
26
27        let trace_compaction_interval_hours =
28            std::env::var("SCOUTER_TRACE_COMPACTION_INTERVAL_HOURS")
29                .ok()
30                .and_then(|v| v.parse().ok())
31                .unwrap_or(24u64);
32
33        let trace_flush_interval_secs = std::env::var("SCOUTER_TRACE_FLUSH_INTERVAL_SECS")
34            .ok()
35            .and_then(|v| v.parse().ok())
36            .unwrap_or(5u64);
37
38        Self {
39            storage_uri,
40            storage_type,
41            region,
42            trace_compaction_interval_hours,
43            trace_flush_interval_secs,
44        }
45    }
46}
47
48impl ObjectStorageSettings {
49    /// Buffer size for trace span batching before flushing to Delta Lake.
50    ///
51    /// Configurable via `SCOUTER_TRACE_BUFFER_SIZE`. Larger values produce fewer,
52    /// bigger Parquet files — reducing Delta log replay cost and file-open overhead
53    /// on cloud storage at the expense of slightly longer flush intervals.
54    /// Default: 10,000 spans.
55    pub fn trace_buffer_size(&self) -> usize {
56        std::env::var("SCOUTER_TRACE_BUFFER_SIZE")
57            .ok()
58            .and_then(|v| v.parse().ok())
59            .unwrap_or(10_000)
60    }
61
62    pub fn storage_root(&self) -> String {
63        match self.storage_type {
64            StorageType::Google | StorageType::Aws | StorageType::Azure => {
65                if let Some(stripped) = self.storage_uri.strip_prefix("gs://") {
66                    stripped.split('/').next().unwrap_or(stripped).to_string()
67                } else if let Some(stripped) = self.storage_uri.strip_prefix("s3://") {
68                    stripped.split('/').next().unwrap_or(stripped).to_string()
69                } else if let Some(stripped) = self.storage_uri.strip_prefix("az://") {
70                    stripped.split('/').next().unwrap_or(stripped).to_string()
71                } else {
72                    self.storage_uri.clone()
73                }
74            }
75            StorageType::Local => {
76                // For local storage, just return the path directly
77                self.storage_uri.clone()
78            }
79        }
80    }
81
82    pub fn canonicalized_path(&self) -> String {
83        // if registry is local canonicalize the path
84        if self.storage_type == StorageType::Local {
85            let path = PathBuf::from(&self.storage_uri);
86            if path.exists() {
87                path.canonicalize()
88                    .unwrap_or_else(|_| path.clone())
89                    .to_str()
90                    .unwrap()
91                    .to_string()
92            } else {
93                self.storage_uri.clone()
94            }
95        } else {
96            self.storage_uri.clone()
97        }
98    }
99}