Fix sdlcli get -command result stdout write
[ric-plt/sdlgo.git] / internal / cli / statistics.go
1 /*
2    Copyright (c) 2021 AT&T Intellectual Property.
3    Copyright (c) 2018-2021 Nokia.
4
5    Licensed under the Apache License, Version 2.0 (the "License");
6    you may not use this file except in compliance with the License.
7    You may obtain a copy of the License at
8
9        http://www.apache.org/licenses/LICENSE-2.0
10
11    Unless required by applicable law or agreed to in writing, software
12    distributed under the License is distributed on an "AS IS" BASIS,
13    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14    See the License for the specific language governing permissions and
15    limitations under the License.
16 */
17
18 /*
19  * This source code is part of the near-RT RIC (RAN Intelligent Controller)
20  * platform project (RICP).
21  */
22
23 package cli
24
25 import (
26         "fmt"
27         "gerrit.o-ran-sc.org/r/ric-plt/sdlgo/internal/sdlgoredis"
28         "github.com/spf13/cobra"
29         "os"
30         "reflect"
31         "text/tabwriter"
32 )
33
34 func init() {
35         rootCmd.AddCommand(newStatisticsCmd(newDatabase))
36 }
37
38 var (
39         statsLong = `Display SDL resource usage statistics`
40
41         statsExample = `  # Show statistics per node
42   sdlcli statistics`
43 )
44
45 func newStatisticsCmd(dbCreateCb DbCreateCb) *cobra.Command {
46         cmd := &cobra.Command{
47                 Use:     "statistics",
48                 Short:   "Display statistics.",
49                 Long:    statsLong,
50                 Example: statsExample,
51                 Args:    cobra.ExactArgs(0),
52                 RunE: func(cmd *cobra.Command, args []string) error {
53                         statistics, err := runStats(dbCreateCb)
54                         if err != nil {
55                                 fmt.Fprintf(os.Stderr, "%s", buf.String())
56                                 return err
57                         }
58                         printStatistics(cmd, statistics)
59                         return nil
60                 },
61         }
62         cmd.SetOut(os.Stdout)
63         return cmd
64 }
65
66 func runStats(dbCreateCb DbCreateCb) ([]*sdlgoredis.DbStatistics, error) {
67         var statistics []*sdlgoredis.DbStatistics
68         for _, dbInst := range dbCreateCb().Instances {
69                 dbStatistics, err := dbInst.Statistics()
70                 if err != nil {
71                         return nil, err
72                 }
73                 statistics = append(statistics, dbStatistics)
74         }
75         return statistics, nil
76 }
77
78 func writeClientsInfo(w *tabwriter.Writer, clients sdlgoredis.ClientsInfoFields) {
79         fmt.Fprintf(w, "\t\t\tConnectedClients:%d\n", clients.ConnectedClients)
80         fmt.Fprintf(w, "\t\t\tClientRecentMaxInputBuffer:%d\n", clients.ClientRecentMaxInputBuffer)
81         fmt.Fprintf(w, "\t\t\tClientRecentMaxOutputBuffer:%d\n", clients.ClientRecentMaxOutputBuffer)
82 }
83
84 func writeMemoryInfo(w *tabwriter.Writer, memory sdlgoredis.MeroryInfoFields) {
85         fmt.Fprintf(w, "\t\t\tUsedMemory:%d\n", memory.UsedMemory)
86         fmt.Fprintf(w, "\t\t\tUsedMemoryHuman:%s\n", memory.UsedMemoryHuman)
87         fmt.Fprintf(w, "\t\t\tUsedMemoryRss:%d\n", memory.UsedMemoryRss)
88         fmt.Fprintf(w, "\t\t\tUsedMemoryRssHuman:%s\n", memory.UsedMemoryRssHuman)
89         fmt.Fprintf(w, "\t\t\tUsedMemoryPeak:%d\n", memory.UsedMemoryPeak)
90         fmt.Fprintf(w, "\t\t\tUsedMemoryPeakHuman:%s\n", memory.UsedMemoryPeakHuman)
91         fmt.Fprintf(w, "\t\t\tUsedMemoryPeakPerc:%s\n", memory.UsedMemoryPeakPerc)
92         fmt.Fprintf(w, "\t\t\tMemFragmentationRatio:%.2f\n", memory.MemFragmentationRatio)
93         fmt.Fprintf(w, "\t\t\tMemFragmentationBytes:%d\n", memory.MemFragmentationBytes)
94 }
95
96 func writeStatsInfo(w *tabwriter.Writer, stats sdlgoredis.StatsInfoFields) {
97         fmt.Fprintf(w, "\t\t\tTotalConnectionsReceived:%d\n", stats.TotalConnectionsReceived)
98         fmt.Fprintf(w, "\t\t\tTotalCommandsProcessed:%d\n", stats.TotalCommandsProcessed)
99         fmt.Fprintf(w, "\t\t\tSyncFull:%d\n", stats.SyncFull)
100         fmt.Fprintf(w, "\t\t\tSyncPartialOk:%d\n", stats.SyncPartialOk)
101         fmt.Fprintf(w, "\t\t\tSyncPartialErr:%d\n", stats.SyncPartialErr)
102         fmt.Fprintf(w, "\t\t\tPubsubChannels:%d\n", stats.PubsubChannels)
103 }
104
105 func writeCpuInfo(w *tabwriter.Writer, cpu sdlgoredis.CpuInfoFields) {
106         fmt.Fprintf(w, "\t\t\tUsedCpuSys:%v\n", cpu.UsedCpuSys)
107         fmt.Fprintf(w, "\t\t\tUsedCpuUser:%v\n", cpu.UsedCpuUser)
108 }
109
110 func fillCommandstatsInfo(w *tabwriter.Writer, i interface{}, cmdstat string) {
111         stype := reflect.ValueOf(i).Elem()
112         callsField := stype.FieldByName("Calls").Interface()
113         usecField := stype.FieldByName("Usec").Interface()
114         usecPerCallField := stype.FieldByName("UsecPerCall").Interface()
115
116         if callsField.(uint32) > 0 {
117                 fmt.Fprintf(w, "\t\t\t%s:calls=%d usec:%d usecPerCall:%.2f\n",
118                         cmdstat, callsField, usecField, usecPerCallField)
119         }
120 }
121
122 func writeCommandstatsInfo(w *tabwriter.Writer, commandstats sdlgoredis.CommandstatsInfoFields) {
123         fillCommandstatsInfo(w, &commandstats.CmdstatReplconf, "CmdstatReplconf")
124         fillCommandstatsInfo(w, &commandstats.CmdstatKeys, "CmdstatKeys")
125         fillCommandstatsInfo(w, &commandstats.CmdstatRole, "CmdstatRole")
126         fillCommandstatsInfo(w, &commandstats.CmdstatPsync, "CmdstatPsync")
127         fillCommandstatsInfo(w, &commandstats.CmdstatMset, "CmdstatMset")
128         fillCommandstatsInfo(w, &commandstats.CmdstatPublish, "CmdstatPublish")
129         fillCommandstatsInfo(w, &commandstats.CmdstatInfo, "CmdstatInfo")
130         fillCommandstatsInfo(w, &commandstats.CmdstatPing, "CmdstatPing")
131         fillCommandstatsInfo(w, &commandstats.CmdstatClient, "CmdstatClient")
132         fillCommandstatsInfo(w, &commandstats.CmdstatCommand, "CmdstatCommand")
133         fillCommandstatsInfo(w, &commandstats.CmdstatSubscribe, "CmdstatSubscribe")
134         fillCommandstatsInfo(w, &commandstats.CmdstatMonitor, "CmdstatMonitor")
135         fillCommandstatsInfo(w, &commandstats.CmdstatConfig, "CmdstatConfig")
136         fillCommandstatsInfo(w, &commandstats.CmdstatSlaveof, "CmdstatSlaveof")
137 }
138
139 func writeKeyspaceInfo(w *tabwriter.Writer, keyspace sdlgoredis.KeyspaceInfoFields) {
140         fmt.Fprintf(w, "\t\t\tDb0:keys=%d\n", keyspace.Db.Keys)
141 }
142
143 func printStatistics(cmd *cobra.Command, statistics []*sdlgoredis.DbStatistics) {
144         w := tabwriter.NewWriter(cmd.OutOrStdout(), 6, 4, 2, ' ', 0)
145         fmt.Fprintln(w, "CLUSTER\tROLE\tADDRESS\tSTATISTICS")
146
147         for i, s := range statistics {
148                 for _, stats := range s.Stats {
149                         fmt.Fprintf(w, "%d", i)
150                         if stats.Info.Fields.PrimaryRole {
151                                 fmt.Fprintf(w, "\tPrimary")
152                         } else {
153                                 fmt.Fprintf(w, "\tReplica")
154                         }
155                         fmt.Fprintf(w, "\t%s:%s", stats.IPAddr, stats.Port)
156                         fmt.Fprintf(w, "\tUptimeInDays:%d\n", stats.Info.Fields.Server.UptimeInDays)
157                         writeClientsInfo(w, stats.Info.Fields.Clients)
158                         writeMemoryInfo(w, stats.Info.Fields.Memory)
159                         writeStatsInfo(w, stats.Info.Fields.Stats)
160                         writeCpuInfo(w, stats.Info.Fields.Cpu)
161                         writeCommandstatsInfo(w, stats.Info.Fields.Commandstats)
162                         writeKeyspaceInfo(w, stats.Info.Fields.Keyspace)
163                 }
164         }
165         w.Flush()
166 }