systemprompt_cli/commands/analytics/sessions/
mod.rs1mod live;
8mod stats;
9mod trends;
10
11use anyhow::Result;
12use clap::Subcommand;
13use schemars::JsonSchema;
14use serde::{Deserialize, Serialize};
15use systemprompt_runtime::DatabaseContext;
16
17use crate::CliConfig;
18use crate::shared::render_result;
19
20#[derive(Debug, Subcommand)]
21pub enum SessionsCommands {
22 #[command(about = "Session statistics", alias = "list")]
23 Stats(stats::StatsArgs),
24
25 #[command(about = "Session trends over time")]
26 Trends(trends::TrendsArgs),
27
28 #[command(about = "Real-time active sessions")]
29 Live(live::LiveArgs),
30}
31
32#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
33pub struct SessionStatsOutput {
34 pub period: String,
35 #[serde(rename = "sessions_created_in_period")]
36 pub total_sessions: i64,
37 #[serde(rename = "sessions_currently_active")]
38 pub active_sessions: i64,
39 pub unique_users: i64,
40 pub avg_duration_seconds: i64,
41 pub avg_requests_per_session: f64,
42 pub conversion_rate: f64,
43}
44
45#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
46pub struct SessionTrendPoint {
47 pub timestamp: String,
48 pub session_count: i64,
49 pub active_users: i64,
50 pub avg_duration_seconds: i64,
51}
52
53#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
54pub struct SessionTrendsOutput {
55 pub period: String,
56 pub group_by: String,
57 pub points: Vec<SessionTrendPoint>,
58}
59
60#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
61pub struct ActiveSessionRow {
62 #[serde(rename = "session_id")]
63 pub session: String,
64 pub user_type: String,
65 pub started_at: String,
66 pub duration_seconds: i64,
67 pub request_count: i64,
68 pub last_activity: String,
69}
70
71#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
72pub struct LiveSessionsOutput {
73 pub active_count: i64,
74 pub sessions: Vec<ActiveSessionRow>,
75 pub timestamp: String,
76}
77
78pub async fn execute(command: SessionsCommands, config: &CliConfig) -> Result<()> {
79 match command {
80 SessionsCommands::Stats(args) => {
81 let result = stats::execute(args, config).await?;
82 render_result(&result);
83 Ok(())
84 },
85 SessionsCommands::Trends(args) => {
86 let result = trends::execute(args, config).await?;
87 render_result(&result);
88 Ok(())
89 },
90 SessionsCommands::Live(args) => {
91 let result = live::execute(args, config).await?;
92 render_result(&result);
93 Ok(())
94 },
95 }
96}
97
98pub async fn execute_with_pool(
99 command: SessionsCommands,
100 db_ctx: &DatabaseContext,
101 config: &CliConfig,
102) -> Result<()> {
103 match command {
104 SessionsCommands::Stats(args) => {
105 let result = stats::execute_with_pool(args, db_ctx, config).await?;
106 render_result(&result);
107 Ok(())
108 },
109 SessionsCommands::Trends(args) => {
110 let result = trends::execute_with_pool(args, db_ctx, config).await?;
111 render_result(&result);
112 Ok(())
113 },
114 SessionsCommands::Live(args) => {
115 let result = live::execute_with_pool(args, db_ctx, config).await?;
116 render_result(&result);
117 Ok(())
118 },
119 }
120}