pub mod grafana;
pub mod prometheus;
pub mod templates;
use crate::error::Result;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DashboardConfig {
pub title: String,
pub description: String,
pub tags: Vec<String>,
pub refresh_interval: u32,
pub time_range: TimeRange,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TimeRange {
pub from: String,
pub to: String,
}
impl Default for DashboardConfig {
fn default() -> Self {
Self {
title: "OxiGDAL Dashboard".to_string(),
description: "Real-time performance monitoring for OxiGDAL".to_string(),
tags: vec!["oxigdal".to_string(), "geospatial".to_string()],
refresh_interval: 5,
time_range: TimeRange {
from: "now-1h".to_string(),
to: "now".to_string(),
},
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PanelConfig {
pub title: String,
pub panel_type: PanelType,
pub queries: Vec<Query>,
pub grid_pos: GridPos,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum PanelType {
Graph,
Singlestat,
Table,
Heatmap,
Gauge,
BarGauge,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Query {
pub expr: String,
pub legend_format: Option<String>,
pub interval: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GridPos {
pub x: u32,
pub y: u32,
pub w: u32,
pub h: u32,
}
pub struct DashboardBuilder {
config: DashboardConfig,
panels: Vec<PanelConfig>,
}
impl DashboardBuilder {
pub fn new(title: impl Into<String>) -> Self {
Self {
config: DashboardConfig {
title: title.into(),
..Default::default()
},
panels: Vec::new(),
}
}
pub fn with_description(mut self, description: impl Into<String>) -> Self {
self.config.description = description.into();
self
}
pub fn with_tag(mut self, tag: impl Into<String>) -> Self {
self.config.tags.push(tag.into());
self
}
pub fn with_refresh_interval(mut self, seconds: u32) -> Self {
self.config.refresh_interval = seconds;
self
}
pub fn add_panel(mut self, panel: PanelConfig) -> Self {
self.panels.push(panel);
self
}
pub fn build(self) -> Dashboard {
Dashboard {
config: self.config,
panels: self.panels,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Dashboard {
pub config: DashboardConfig,
pub panels: Vec<PanelConfig>,
}
impl Dashboard {
pub fn to_json(&self) -> Result<String> {
serde_json::to_string_pretty(self).map_err(crate::error::ObservabilityError::Serialization)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_dashboard_builder() {
let dashboard = DashboardBuilder::new("Test Dashboard")
.with_description("Test description")
.with_tag("test")
.with_refresh_interval(10)
.build();
assert_eq!(dashboard.config.title, "Test Dashboard");
assert_eq!(dashboard.config.refresh_interval, 10);
}
}