@@ -20,31 +20,54 @@ use std::sync::Arc;
20
20
21
21
use actix_web:: http:: header:: ContentType ;
22
22
use arrow_schema:: Schema ;
23
+ use chrono:: Utc ;
23
24
use http:: StatusCode ;
24
25
use serde:: Serialize ;
25
26
26
27
use crate :: {
27
- handlers:: http:: { logstream:: error:: StreamError , query:: update_schema_when_distributed} ,
28
+ handlers:: http:: {
29
+ cluster:: utils:: { merge_quried_stats, IngestionStats , QueriedStats , StorageStats } ,
30
+ logstream:: error:: StreamError ,
31
+ query:: update_schema_when_distributed,
32
+ } ,
28
33
parseable:: { StreamNotFound , PARSEABLE } ,
29
- storage:: StreamInfo ,
34
+ stats,
35
+ storage:: { retention:: Retention , StreamInfo } ,
30
36
LOCK_EXPECT ,
31
37
} ;
32
38
33
39
#[ derive( Serialize ) ]
34
40
pub struct PrismLogstreamInfo {
35
41
info : StreamInfo ,
36
42
schema : Arc < Schema > ,
43
+ stats : QueriedStats ,
44
+ retention : Retention ,
37
45
}
38
46
39
47
pub async fn get_prism_logstream_info (
40
48
stream_name : & str ,
41
49
) -> Result < PrismLogstreamInfo , PrismLogstreamError > {
42
50
// get StreamInfo
43
51
let info = get_stream_info_helper ( stream_name) . await ?;
52
+
44
53
// get stream schema
45
54
let schema = get_stream_schema_helper ( stream_name) . await ?;
46
55
47
- Ok ( PrismLogstreamInfo { info, schema } )
56
+ // get stream stats
57
+ let stats = get_stats ( stream_name) . await ?;
58
+
59
+ // get retention
60
+ let retention = PARSEABLE
61
+ . get_stream ( stream_name) ?
62
+ . get_retention ( )
63
+ . unwrap_or_default ( ) ;
64
+
65
+ Ok ( PrismLogstreamInfo {
66
+ info,
67
+ schema,
68
+ stats,
69
+ retention,
70
+ } )
48
71
}
49
72
50
73
async fn get_stream_schema_helper ( stream_name : & str ) -> Result < Arc < Schema > , StreamError > {
@@ -66,6 +89,73 @@ async fn get_stream_schema_helper(stream_name: &str) -> Result<Arc<Schema>, Stre
66
89
}
67
90
}
68
91
92
+ async fn get_stats ( stream_name : & str ) -> Result < QueriedStats , PrismLogstreamError > {
93
+ let stats = stats:: get_current_stats ( stream_name, "json" )
94
+ . ok_or_else ( || StreamNotFound ( stream_name. to_owned ( ) ) ) ?;
95
+
96
+ let ingestor_stats: Option < Vec < QueriedStats > > = None ;
97
+
98
+ let hash_map = PARSEABLE . streams . read ( ) . expect ( "Readable" ) ;
99
+ let stream_meta = & hash_map
100
+ . get ( stream_name)
101
+ . ok_or_else ( || StreamNotFound ( stream_name. to_owned ( ) ) ) ?
102
+ . metadata
103
+ . read ( )
104
+ . expect ( LOCK_EXPECT ) ;
105
+
106
+ let time = Utc :: now ( ) ;
107
+
108
+ let stats = match & stream_meta. first_event_at {
109
+ Some ( _) => {
110
+ let ingestion_stats = IngestionStats :: new (
111
+ stats. current_stats . events ,
112
+ format ! ( "{} {}" , stats. current_stats. ingestion, "Bytes" ) ,
113
+ stats. lifetime_stats . events ,
114
+ format ! ( "{} {}" , stats. lifetime_stats. ingestion, "Bytes" ) ,
115
+ stats. deleted_stats . events ,
116
+ format ! ( "{} {}" , stats. deleted_stats. ingestion, "Bytes" ) ,
117
+ "json" ,
118
+ ) ;
119
+ let storage_stats = StorageStats :: new (
120
+ format ! ( "{} {}" , stats. current_stats. storage, "Bytes" ) ,
121
+ format ! ( "{} {}" , stats. lifetime_stats. storage, "Bytes" ) ,
122
+ format ! ( "{} {}" , stats. deleted_stats. storage, "Bytes" ) ,
123
+ "parquet" ,
124
+ ) ;
125
+
126
+ QueriedStats :: new ( stream_name, time, ingestion_stats, storage_stats)
127
+ }
128
+
129
+ None => {
130
+ let ingestion_stats = IngestionStats :: new (
131
+ stats. current_stats . events ,
132
+ format ! ( "{} {}" , stats. current_stats. ingestion, "Bytes" ) ,
133
+ stats. lifetime_stats . events ,
134
+ format ! ( "{} {}" , stats. lifetime_stats. ingestion, "Bytes" ) ,
135
+ stats. deleted_stats . events ,
136
+ format ! ( "{} {}" , stats. deleted_stats. ingestion, "Bytes" ) ,
137
+ "json" ,
138
+ ) ;
139
+ let storage_stats = StorageStats :: new (
140
+ format ! ( "{} {}" , stats. current_stats. storage, "Bytes" ) ,
141
+ format ! ( "{} {}" , stats. lifetime_stats. storage, "Bytes" ) ,
142
+ format ! ( "{} {}" , stats. deleted_stats. storage, "Bytes" ) ,
143
+ "parquet" ,
144
+ ) ;
145
+
146
+ QueriedStats :: new ( stream_name, time, ingestion_stats, storage_stats)
147
+ }
148
+ } ;
149
+ let stats = if let Some ( mut ingestor_stats) = ingestor_stats {
150
+ ingestor_stats. push ( stats) ;
151
+ merge_quried_stats ( ingestor_stats)
152
+ } else {
153
+ stats
154
+ } ;
155
+
156
+ Ok ( stats)
157
+ }
158
+
69
159
async fn get_stream_info_helper ( stream_name : & str ) -> Result < StreamInfo , StreamError > {
70
160
// For query mode, if the stream not found in memory map,
71
161
//check if it exists in the storage
@@ -120,13 +210,16 @@ pub enum PrismLogstreamError {
120
210
Anyhow ( #[ from] anyhow:: Error ) ,
121
211
#[ error( "StreamError: {0}" ) ]
122
212
StreamError ( #[ from] StreamError ) ,
213
+ #[ error( "StreamNotFound: {0}" ) ]
214
+ StreamNotFound ( #[ from] StreamNotFound ) ,
123
215
}
124
216
125
217
impl actix_web:: ResponseError for PrismLogstreamError {
126
218
fn status_code ( & self ) -> http:: StatusCode {
127
219
match self {
128
220
PrismLogstreamError :: Anyhow ( _) => StatusCode :: INTERNAL_SERVER_ERROR ,
129
221
PrismLogstreamError :: StreamError ( e) => e. status_code ( ) ,
222
+ PrismLogstreamError :: StreamNotFound ( _) => StatusCode :: INTERNAL_SERVER_ERROR ,
130
223
}
131
224
}
132
225
0 commit comments