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