1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
//! Usage reporting
//!
//! The Redis Enterprise REST API documents `GET /v1/usage_report` only.
//! Earlier revisions of this module exposed `/latest`, `/generate`, `/config`,
//! per-report `/{uid}` and `/{uid}/csv` endpoints at paths the docs never
//! define; those have been removed.
//!
//! Note: the live cluster response is a streaming NDJSON document and the
//! `Vec<UsageReport>` shape modeled by `list()` is a best-effort buffered
//! decode. A streaming reshape is tracked as a follow-up to the #65 audit.
use crate::client::RestClient;
use crate::error::Result;
use serde::{Deserialize, Serialize};
/// Usage report
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UsageReport {
/// Unique identifier for this usage report
pub report_id: String,
/// Timestamp when the report was generated
pub timestamp: String,
/// Start time of the reporting period
pub period_start: String,
/// End time of the reporting period
pub period_end: String,
/// Name of the cluster
pub cluster_name: String,
/// Usage information for individual databases
#[serde(skip_serializing_if = "Option::is_none")]
pub databases: Option<Vec<DatabaseUsage>>,
/// Usage information for cluster nodes
#[serde(skip_serializing_if = "Option::is_none")]
pub nodes: Option<Vec<NodeUsage>>,
/// Summary of overall usage across the cluster
#[serde(skip_serializing_if = "Option::is_none")]
pub summary: Option<UsageSummary>,
}
/// Database usage information
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DatabaseUsage {
/// Database unique identifier
pub bdb_uid: u32,
/// Name of the database
pub name: String,
/// Average memory usage during the reporting period (bytes)
pub memory_used_avg: u64,
/// Peak memory usage during the reporting period (bytes)
pub memory_used_peak: u64,
/// Average operations per second
pub ops_per_sec_avg: f64,
/// Average bandwidth usage (bytes per second)
pub bandwidth_avg: u64,
/// Number of shards in the database
#[serde(skip_serializing_if = "Option::is_none")]
pub shard_count: Option<u32>,
}
/// Node usage information
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NodeUsage {
/// Node unique identifier
pub node_uid: u32,
/// Average CPU usage as a percentage (0.0-1.0)
pub cpu_usage_avg: f32,
/// Average memory usage during the reporting period (bytes)
pub memory_usage_avg: u64,
/// Persistent storage usage (bytes)
pub persistent_storage_usage: u64,
/// Ephemeral storage usage (bytes)
pub ephemeral_storage_usage: u64,
}
/// Usage summary
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UsageSummary {
/// Total memory usage across the cluster (GB)
pub total_memory_gb: f64,
/// Total number of operations across the cluster
pub total_ops: u64,
/// Total bandwidth usage across the cluster (GB)
pub total_bandwidth_gb: f64,
/// Total number of databases in the cluster
pub database_count: u32,
/// Total number of nodes in the cluster
pub node_count: u32,
/// Total number of shards in the cluster
pub shard_count: u32,
}
/// Usage report handler
pub struct UsageReportHandler {
client: RestClient,
}
impl UsageReportHandler {
/// Create a new handler bound to the given REST client.
pub fn new(client: RestClient) -> Self {
UsageReportHandler { client }
}
/// List usage reports - GET /v1/usage_report.
///
/// The live cluster returns a streaming NDJSON document; this method
/// buffers and decodes the whole payload, which is fine for short
/// reporting periods but should not be relied on for cluster-wide
/// scans. A streaming reshape is a #65 follow-up.
pub async fn list(&self) -> Result<Vec<UsageReport>> {
self.client.get("/v1/usage_report").await
}
}