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