@@ -59,36 +59,48 @@ type StreamRetentionData []struct {
5959 Duration string `json:"duration"`
6060}
6161
62- // StreamAlertData is the data structure for stream alerts
63- type StreamAlertData struct {
64- Alerts []struct {
65- Message string `json:"message"`
66- Name string `json:"name"`
67- Rule struct {
68- Config struct {
69- Column string `json:"column"`
70- Operator string `json:"operator"`
71- Repeats int `json:"repeats"`
72- Value int `json:"value"`
73- } `json:"config"`
74- Type string `json:"type"`
75- } `json:"rule"`
76- Targets []struct {
77- Endpoint string `json:"endpoint"`
78- Password string `json:"password,omitempty"`
79- Repeat struct {
80- Interval string `json:"interval"`
81- Times int `json:"times"`
82- } `json:"repeat"`
83- SkipTLSCheck bool `json:"skip_tls_check,omitempty"`
84- Type string `json:"type"`
85- Username string `json:"username,omitempty"`
86- Headers struct {
87- Authorization string `json:"Authorization"`
88- } `json:"headers,omitempty"`
89- } `json:"targets"`
90- } `json:"alerts"`
91- Version string `json:"version"`
62+ // AlertConfig structure
63+ type AlertConfig struct {
64+ Version string `json:"version"`
65+ Alerts []Alert `json:"alerts"`
66+ }
67+
68+ // Alert structure
69+ type Alert struct {
70+ Targets []Target `json:"targets"`
71+ Name string `json:"name"`
72+ Message string `json:"message"`
73+ Rule Rule `json:"rule"`
74+ }
75+
76+ // Target structure
77+ type Target struct {
78+ Type string `json:"type"`
79+ Endpoint string `json:"endpoint"`
80+ Headers map [string ]string `json:"headers"`
81+ SkipTLSCheck bool `json:"skip_tls_check"`
82+ Repeat Repeat `json:"repeat"`
83+ }
84+
85+ // Repeat structure
86+ type Repeat struct {
87+ Interval string `json:"interval"`
88+ Times int `json:"times"`
89+ }
90+
91+ // Rule structure
92+ type Rule struct {
93+ Type string `json:"type"`
94+ Config RuleConfig `json:"config"`
95+ }
96+
97+ // RuleConfig structure
98+ type RuleConfig struct {
99+ Column string `json:"column"`
100+ Operator string `json:"operator"`
101+ IgnoreCase bool `json:"ignoreCase"`
102+ Value interface {} `json:"value"`
103+ Repeats int `json:"repeats"`
92104}
93105
94106// AddStreamCmd is the parent command for stream
@@ -132,10 +144,11 @@ var StatStreamCmd = &cobra.Command{
132144 Example : " pb stream info backend_logs" ,
133145 Short : "Get statistics for a stream" ,
134146 Args : cobra .ExactArgs (1 ),
135- RunE : func (_ * cobra.Command , args []string ) error {
147+ RunE : func (cmd * cobra.Command , args []string ) error {
136148 name := args [0 ]
137149 client := DefaultClient ()
138150
151+ // Fetch stats data
139152 stats , err := fetchStats (& client , name )
140153 if err != nil {
141154 return err
@@ -144,68 +157,96 @@ var StatStreamCmd = &cobra.Command{
144157 ingestionCount := stats .Ingestion .Count
145158 ingestionSize , _ := strconv .Atoi (strings .TrimRight (stats .Ingestion .Size , " Bytes" ))
146159 storageSize , _ := strconv .Atoi (strings .TrimRight (stats .Storage .Size , " Bytes" ))
160+ compressionRatio := 100 - (float64 (storageSize ) / float64 (ingestionSize ) * 100 )
147161
162+ // Fetch retention data
148163 retention , err := fetchRetention (& client , name )
149164 if err != nil {
150165 return err
151166 }
152167
153- isRetentionSet := len (retention ) > 0
154-
155- fmt .Println (StyleBold .Render ("\n Info:" ))
156- fmt .Printf (" Event Count: %d\n " , ingestionCount )
157- fmt .Printf (" Ingestion Size: %s\n " , humanize .Bytes (uint64 (ingestionSize )))
158- fmt .Printf (" Storage Size: %s\n " , humanize .Bytes (uint64 (storageSize )))
159- fmt .Printf (
160- " Compression Ratio: %.2f%s\n " ,
161- 100 - (float64 (storageSize )/ float64 (ingestionSize ))* 100 , "%" )
162- fmt .Println ()
163-
164- if isRetentionSet {
165- fmt .Println (StyleBold .Render ("Retention:" ))
166- for _ , item := range retention {
167- fmt .Printf (" Action: %s\n " , StyleBold .Render (item .Action ))
168- fmt .Printf (" Duration: %s\n " , StyleBold .Render (item .Duration ))
169- fmt .Println ()
170- }
171- } else {
172- fmt .Println (StyleBold .Render ("No retention period set on stream\n " ))
173- }
174-
168+ // Fetch alerts data
175169 alertsData , err := fetchAlerts (& client , name )
176170 if err != nil {
177171 return err
178172 }
179- alerts := alertsData .Alerts
180-
181- isAlertsSet := len (alerts ) > 0
182-
183- if isAlertsSet {
184- fmt .Println (StyleBold .Render ("Alerts:" ))
185- for _ , alert := range alerts {
186- fmt .Printf (" Alert: %s\n " , StyleBold .Render (alert .Name ))
187- ruleFmt := fmt .Sprintf (
188- "%s %s %s repeated %d times" ,
189- alert .Rule .Config .Column ,
190- alert .Rule .Config .Operator ,
191- fmt .Sprint (alert .Rule .Config .Value ),
192- alert .Rule .Config .Repeats ,
193- )
194- fmt .Printf (" Rule: %s\n " , ruleFmt )
195- fmt .Printf (" Targets: " )
196- for _ , target := range alert .Targets {
197- fmt .Printf ("%s, " , target .Type )
198- }
199- fmt .Print ("\n \n " )
173+
174+ // Check output format
175+ output , _ := cmd .Flags ().GetString ("output" )
176+ if output == "json" {
177+ // Prepare JSON response
178+ data := map [string ]interface {}{
179+ "info" : map [string ]interface {}{
180+ "event_count" : ingestionCount ,
181+ "ingestion_size" : humanize .Bytes (uint64 (ingestionSize )),
182+ "storage_size" : humanize .Bytes (uint64 (storageSize )),
183+ "compression_ratio" : fmt .Sprintf ("%.2f%%" , compressionRatio ),
184+ },
185+ "retention" : retention ,
186+ "alerts" : alertsData .Alerts ,
187+ }
188+
189+ jsonData , err := json .MarshalIndent (data , "" , " " )
190+ if err != nil {
191+ return err
200192 }
193+ fmt .Println (string (jsonData ))
201194 } else {
202- fmt .Println (StyleBold .Render ("No alerts set on stream\n " ))
195+ // Default text output
196+ isRetentionSet := len (retention ) > 0
197+ isAlertsSet := len (alertsData .Alerts ) > 0
198+
199+ fmt .Println (StyleBold .Render ("\n Info:" ))
200+ fmt .Printf (" Event Count: %d\n " , ingestionCount )
201+ fmt .Printf (" Ingestion Size: %s\n " , humanize .Bytes (uint64 (ingestionSize )))
202+ fmt .Printf (" Storage Size: %s\n " , humanize .Bytes (uint64 (storageSize )))
203+ fmt .Printf (
204+ " Compression Ratio: %.2f%s\n " ,
205+ compressionRatio , "%" )
206+ fmt .Println ()
207+
208+ if isRetentionSet {
209+ fmt .Println (StyleBold .Render ("Retention:" ))
210+ for _ , item := range retention {
211+ fmt .Printf (" Action: %s\n " , StyleBold .Render (item .Action ))
212+ fmt .Printf (" Duration: %s\n " , StyleBold .Render (item .Duration ))
213+ fmt .Println ()
214+ }
215+ } else {
216+ fmt .Println (StyleBold .Render ("No retention period set on stream\n " ))
217+ }
218+
219+ if isAlertsSet {
220+ fmt .Println (StyleBold .Render ("Alerts:" ))
221+ for _ , alert := range alertsData .Alerts {
222+ fmt .Printf (" Alert: %s\n " , StyleBold .Render (alert .Name ))
223+ ruleFmt := fmt .Sprintf (
224+ "%s %s %s repeated %d times" ,
225+ alert .Rule .Config .Column ,
226+ alert .Rule .Config .Operator ,
227+ fmt .Sprint (alert .Rule .Config .Value ),
228+ alert .Rule .Config .Repeats ,
229+ )
230+ fmt .Printf (" Rule: %s\n " , ruleFmt )
231+ fmt .Printf (" Targets: " )
232+ for _ , target := range alert .Targets {
233+ fmt .Printf ("%s, " , target .Type )
234+ }
235+ fmt .Print ("\n \n " )
236+ }
237+ } else {
238+ fmt .Println (StyleBold .Render ("No alerts set on stream\n " ))
239+ }
203240 }
204241
205242 return nil
206243 },
207244}
208245
246+ func init () {
247+ StatStreamCmd .Flags ().String ("output" , "text" , "Output format: text or json" )
248+ }
249+
209250var RemoveStreamCmd = & cobra.Command {
210251 Use : "remove stream-name" ,
211252 Aliases : []string {"rm" },
@@ -345,7 +386,7 @@ func fetchRetention(client *HTTPClient, name string) (data StreamRetentionData,
345386 return
346387}
347388
348- func fetchAlerts (client * HTTPClient , name string ) (data StreamAlertData , err error ) {
389+ func fetchAlerts (client * HTTPClient , name string ) (data AlertConfig , err error ) {
349390 req , err := client .NewRequest ("GET" , fmt .Sprintf ("logstream/%s/alert" , name ), nil )
350391 if err != nil {
351392 return
0 commit comments