systemprompt_runtime/trace/repository/
log_summary.rs1use chrono::{DateTime, Utc};
7
8use super::{Result, TraceError, TraceRepository};
9use crate::trace::models::{LevelCount, LogTimeRange, ModuleCount};
10
11struct LevelRow {
12 level: String,
13 count: Option<i64>,
14}
15
16struct ModuleRow {
17 module: String,
18 count: Option<i64>,
19}
20
21struct TimeRangeRow {
22 earliest: Option<DateTime<Utc>>,
23 latest: Option<DateTime<Utc>>,
24}
25
26impl TraceRepository {
27 pub async fn count_logs_by_level(
28 &self,
29 since: Option<DateTime<Utc>>,
30 ) -> Result<Vec<LevelCount>> {
31 let rows = sqlx::query_as!(
32 LevelRow,
33 r#"
34 SELECT level as "level!", COUNT(*) as "count"
35 FROM logs
36 WHERE ($1::TIMESTAMPTZ IS NULL OR timestamp >= $1)
37 GROUP BY level
38 "#,
39 since
40 )
41 .fetch_all(&*self.pool)
42 .await?;
43
44 rows.into_iter()
45 .map(|r| -> Result<LevelCount> {
46 Ok(LevelCount {
47 level: r.level.parse()?,
48 count: r.count.unwrap_or(0),
49 })
50 })
51 .collect()
52 }
53
54 pub async fn top_modules(
55 &self,
56 since: Option<DateTime<Utc>>,
57 limit: i64,
58 ) -> Result<Vec<ModuleCount>> {
59 let rows = sqlx::query_as!(
60 ModuleRow,
61 r#"
62 SELECT module as "module!", COUNT(*) as "count"
63 FROM logs
64 WHERE ($1::TIMESTAMPTZ IS NULL OR timestamp >= $1)
65 GROUP BY module
66 ORDER BY count DESC
67 LIMIT $2
68 "#,
69 since,
70 limit
71 )
72 .fetch_all(&*self.pool)
73 .await?;
74
75 Ok(rows
76 .into_iter()
77 .map(|r| ModuleCount {
78 module: r.module,
79 count: r.count.unwrap_or(0),
80 })
81 .collect())
82 }
83
84 pub async fn log_time_range(&self, since: Option<DateTime<Utc>>) -> Result<LogTimeRange> {
85 let row = sqlx::query_as!(
86 TimeRangeRow,
87 r#"
88 SELECT MIN(timestamp) as "earliest", MAX(timestamp) as "latest"
89 FROM logs
90 WHERE ($1::TIMESTAMPTZ IS NULL OR timestamp >= $1)
91 "#,
92 since
93 )
94 .fetch_one(&*self.pool)
95 .await?;
96
97 Ok(LogTimeRange {
98 earliest: row.earliest,
99 latest: row.latest,
100 })
101 }
102
103 pub async fn total_log_count(&self) -> Result<i64> {
104 sqlx::query_scalar!(r#"SELECT COUNT(*) as "count!" FROM logs"#)
105 .fetch_one(&*self.pool)
106 .await
107 .map_err(TraceError::from)
108 }
109}