statsclient: added symlinks
[govpp.git] / adapter / vppapiclient / stat_client.go
1 // Copyright (c) 2018 Cisco and/or its affiliates.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at:
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 // +build !windows,!darwin,!novpp,!beyond18.10
16
17 package vppapiclient
18
19 /*
20 #cgo CFLAGS: -DPNG_DEBUG=1
21 #cgo LDFLAGS: -lvppapiclient
22
23 #include "stat_client_wrapper.h"
24 */
25 import "C"
26
27 import (
28         "fmt"
29         "os"
30         "unsafe"
31
32         "git.fd.io/govpp.git/adapter"
33 )
34
35 // global VPP stats API client, library vppapiclient only supports
36 // single connection at a time
37 var globalStatClient *statClient
38
39 // statClient is the default implementation of StatsAPI.
40 type statClient struct {
41         socketName string
42 }
43
44 // NewStatClient returns new VPP stats API client.
45 func NewStatClient(socketName string) adapter.StatsAPI {
46         return &statClient{
47                 socketName: socketName,
48         }
49 }
50
51 func (c *statClient) Connect() error {
52         if globalStatClient != nil {
53                 return fmt.Errorf("already connected to stats API, disconnect first")
54         }
55
56         var sockName string
57         if c.socketName == "" {
58                 sockName = adapter.DefaultStatsSocket
59         } else {
60                 sockName = c.socketName
61         }
62
63         if _, err := os.Stat(sockName); err != nil {
64                 if os.IsNotExist(err) {
65                         return fmt.Errorf("stats socket file %q does not exists, ensure that VPP is running with `statseg { ... }` section in config", sockName)
66                 }
67                 return fmt.Errorf("stats socket file error: %v", err)
68         }
69
70         rc := C.govpp_stat_connect(C.CString(sockName))
71         if rc != 0 {
72                 return fmt.Errorf("connecting to VPP stats API failed (rc=%v)", rc)
73         }
74
75         globalStatClient = c
76         return nil
77 }
78
79 func (c *statClient) Disconnect() error {
80         globalStatClient = nil
81
82         C.govpp_stat_disconnect()
83         return nil
84 }
85
86 func (c *statClient) ListStats(patterns ...string) (indexes []adapter.StatIdentifier, err error) {
87         dir := C.govpp_stat_segment_ls(convertStringSlice(patterns))
88         if dir == nil {
89                 return nil, adapter.ErrStatsDataBusy
90         }
91         defer C.govpp_stat_segment_vec_free(unsafe.Pointer(dir))
92
93         l := C.govpp_stat_segment_vec_len(unsafe.Pointer(dir))
94         for i := 0; i < int(l); i++ {
95                 nameChar := C.govpp_stat_segment_dir_index_to_name(dir, C.uint32_t(i))
96                 indexes = append(indexes, adapter.StatIdentifier{
97                         Name:  []byte(C.GoString(nameChar)),
98                         Index: uint32(i),
99                 })
100                 C.free(unsafe.Pointer(nameChar))
101         }
102
103         return indexes, nil
104 }
105
106 func (c *statClient) DumpStats(patterns ...string) (stats []adapter.StatEntry, err error) {
107         dir := C.govpp_stat_segment_ls(convertStringSlice(patterns))
108         if dir == nil {
109                 return nil, adapter.ErrStatsDataBusy
110         }
111         defer C.govpp_stat_segment_vec_free(unsafe.Pointer(dir))
112
113         dump := C.govpp_stat_segment_dump(dir)
114         if dump == nil {
115                 return nil, adapter.ErrStatsDataBusy
116         }
117         defer C.govpp_stat_segment_data_free(dump)
118
119         l := C.govpp_stat_segment_vec_len(unsafe.Pointer(dump))
120         for i := 0; i < int(l); i++ {
121                 v := C.govpp_stat_segment_dump_index(dump, C.int(i))
122                 nameChar := v.name
123                 name := C.GoString(nameChar)
124                 typ := adapter.StatType(C.govpp_stat_segment_data_type(&v))
125
126                 stat := adapter.StatEntry{
127                         StatIdentifier: adapter.StatIdentifier{
128                                 Name:  []byte(name),
129                                 Index: uint32(i),
130                         },
131                         Type: typ,
132                 }
133
134                 switch typ {
135                 case adapter.ScalarIndex:
136                         stat.Data = adapter.ScalarStat(C.govpp_stat_segment_data_get_scalar_value(&v))
137
138                 case adapter.ErrorIndex:
139                         stat.Data = adapter.ErrorStat([]adapter.Counter{adapter.Counter(C.govpp_stat_segment_data_get_error_value(&v))})
140
141                 case adapter.SimpleCounterVector:
142                         length := int(C.govpp_stat_segment_vec_len(unsafe.Pointer(C.govpp_stat_segment_data_get_simple_counter(&v))))
143                         vector := make([][]adapter.Counter, length)
144                         for k := 0; k < length; k++ {
145                                 for j := 0; j < int(C.govpp_stat_segment_vec_len(unsafe.Pointer(C.govpp_stat_segment_data_get_simple_counter_index(&v, C.int(k))))); j++ {
146                                         vector[k] = append(vector[k], adapter.Counter(C.govpp_stat_segment_data_get_simple_counter_index_value(&v, C.int(k), C.int(j))))
147                                 }
148                         }
149                         stat.Data = adapter.SimpleCounterStat(vector)
150
151                 case adapter.CombinedCounterVector:
152                         length := int(C.govpp_stat_segment_vec_len(unsafe.Pointer(C.govpp_stat_segment_data_get_combined_counter(&v))))
153                         vector := make([][]adapter.CombinedCounter, length)
154                         for k := 0; k < length; k++ {
155                                 for j := 0; j < int(C.govpp_stat_segment_vec_len(unsafe.Pointer(C.govpp_stat_segment_data_get_combined_counter_index(&v, C.int(k))))); j++ {
156                                         vector[k] = append(vector[k], [2]uint64{
157                                                 uint64(C.govpp_stat_segment_data_get_combined_counter_index_packets(&v, C.int(k), C.int(j))),
158                                                 uint64(C.govpp_stat_segment_data_get_combined_counter_index_bytes(&v, C.int(k), C.int(j))),
159                                         })
160                                 }
161                         }
162                         stat.Data = adapter.CombinedCounterStat(vector)
163
164                 case adapter.NameVector:
165                         length := int(C.govpp_stat_segment_vec_len(unsafe.Pointer(C.govpp_stat_segment_data_get_name_vector(&v))))
166                         var vector []adapter.Name
167                         for k := 0; k < length; k++ {
168                                 s := C.govpp_stat_segment_data_get_name_vector_index(&v, C.int(k))
169                                 var name adapter.Name
170                                 if s != nil {
171                                         name = adapter.Name(C.GoString(s))
172                                 }
173                                 vector = append(vector, name)
174                         }
175                         stat.Data = adapter.NameStat(vector)
176
177                 default:
178                         fmt.Fprintf(os.Stderr, "invalid stat type: %v (%v)\n", typ, name)
179                         continue
180
181                 }
182
183                 stats = append(stats, stat)
184         }
185
186         return stats, nil
187 }
188
189 func (c *statClient) PrepareDir(_ ...string) (*adapter.StatDir, error) {
190         return nil, adapter.ErrNotImplemented
191 }
192
193 func (c *statClient) PrepareDirOnIndex(_ ...uint32) (*adapter.StatDir, error) {
194         return nil, adapter.ErrNotImplemented
195 }
196
197 func (c *statClient) UpdateDir(_ *adapter.StatDir) error {
198         return adapter.ErrNotImplemented
199 }
200
201 func convertStringSlice(strs []string) **C.uint8_t {
202         var arr **C.uint8_t
203         for _, str := range strs {
204                 arr = C.govpp_stat_segment_string_vector(arr, C.CString(str))
205         }
206         return arr
207 }