5
5
"encoding/json"
6
6
"fmt"
7
7
"io/ioutil"
8
- "log"
9
8
"os/exec"
10
9
"path/filepath"
11
10
"strings"
@@ -28,17 +27,19 @@ const (
28
27
)
29
28
30
29
type Ceph struct {
31
- CephBinary string
32
- OsdPrefix string
33
- MonPrefix string
34
- MdsPrefix string
35
- RgwPrefix string
36
- SocketDir string
37
- SocketSuffix string
38
- CephUser string
39
- CephConfig string
40
- GatherAdminSocketStats bool
41
- GatherClusterStats bool
30
+ CephBinary string `toml:"ceph_binary"`
31
+ OsdPrefix string `toml:"osd_prefix"`
32
+ MonPrefix string `toml:"mon_prefix"`
33
+ MdsPrefix string `toml:"mds_prefix"`
34
+ RgwPrefix string `toml:"rgw_prefix"`
35
+ SocketDir string `toml:"socket_dir"`
36
+ SocketSuffix string `toml:"socket_suffix"`
37
+ CephUser string `toml:"ceph_user"`
38
+ CephConfig string `toml:"ceph_config"`
39
+ GatherAdminSocketStats bool `toml:"gather_admin_socket_stats"`
40
+ GatherClusterStats bool `toml:"gather_cluster_stats"`
41
+
42
+ Log telegraf.Logger `toml:"-"`
42
43
}
43
44
44
45
func (c * Ceph ) Description () string {
@@ -67,7 +68,14 @@ var sampleConfig = `
67
68
## suffix used to identify socket files
68
69
socket_suffix = "asok"
69
70
70
- ## Ceph user to authenticate as
71
+ ## Ceph user to authenticate as, ceph will search for the corresponding keyring
72
+ ## e.g. client.admin.keyring in /etc/ceph, or the explicit path defined in the
73
+ ## client section of ceph.conf for example:
74
+ ##
75
+ ## [client.telegraf]
76
+ ## keyring = /etc/ceph/client.telegraf.keyring
77
+ ##
78
+ ## Consult the ceph documentation for more detail on keyring generation.
71
79
ceph_user = "client.admin"
72
80
73
81
## Ceph configuration to use to locate the cluster
@@ -76,7 +84,8 @@ var sampleConfig = `
76
84
## Whether to gather statistics via the admin socket
77
85
gather_admin_socket_stats = true
78
86
79
- ## Whether to gather statistics via ceph commands
87
+ ## Whether to gather statistics via ceph commands, requires ceph_user and ceph_config
88
+ ## to be specified
80
89
gather_cluster_stats = false
81
90
`
82
91
@@ -112,14 +121,14 @@ func (c *Ceph) gatherAdminSocketStats(acc telegraf.Accumulator) error {
112
121
acc .AddError (fmt .Errorf ("error reading from socket '%s': %v" , s .socket , err ))
113
122
continue
114
123
}
115
- data , err := parseDump (dump )
124
+ data , err := c . parseDump (dump )
116
125
if err != nil {
117
126
acc .AddError (fmt .Errorf ("error parsing dump from socket '%s': %v" , s .socket , err ))
118
127
continue
119
128
}
120
129
for tag , metrics := range data {
121
130
acc .AddFields (measurement ,
122
- map [ string ] interface {}( metrics ) ,
131
+ metrics ,
123
132
map [string ]string {"type" : s .sockType , "id" : s .sockID , "collection" : tag })
124
133
}
125
134
}
@@ -138,7 +147,7 @@ func (c *Ceph) gatherClusterStats(acc telegraf.Accumulator) error {
138
147
139
148
// For each job, execute against the cluster, parse and accumulate the data points
140
149
for _ , job := range jobs {
141
- output , err := c .exec (job .command )
150
+ output , err := c .execute (job .command )
142
151
if err != nil {
143
152
return fmt .Errorf ("error executing command: %v" , err )
144
153
}
@@ -171,15 +180,17 @@ func init() {
171
180
172
181
var perfDump = func (binary string , socket * socket ) (string , error ) {
173
182
cmdArgs := []string {"--admin-daemon" , socket .socket }
174
- if socket .sockType == typeOsd {
183
+
184
+ switch socket .sockType {
185
+ case typeOsd :
175
186
cmdArgs = append (cmdArgs , "perf" , "dump" )
176
- } else if socket . sockType == typeMon {
187
+ case typeMon :
177
188
cmdArgs = append (cmdArgs , "perfcounters_dump" )
178
- } else if socket . sockType == typeMds {
189
+ case typeMds :
179
190
cmdArgs = append (cmdArgs , "perf" , "dump" )
180
- } else if socket . sockType == typeRgw {
191
+ case typeRgw :
181
192
cmdArgs = append (cmdArgs , "perf" , "dump" )
182
- } else {
193
+ default :
183
194
return "" , fmt .Errorf ("ignoring unknown socket type: %s" , socket .sockType )
184
195
}
185
196
@@ -268,23 +279,23 @@ type taggedMetricMap map[string]metricMap
268
279
269
280
// Parses a raw JSON string into a taggedMetricMap
270
281
// Delegates the actual parsing to newTaggedMetricMap(..)
271
- func parseDump (dump string ) (taggedMetricMap , error ) {
282
+ func ( c * Ceph ) parseDump (dump string ) (taggedMetricMap , error ) {
272
283
data := make (map [string ]interface {})
273
284
err := json .Unmarshal ([]byte (dump ), & data )
274
285
if err != nil {
275
286
return nil , fmt .Errorf ("failed to parse json: '%s': %v" , dump , err )
276
287
}
277
288
278
- return newTaggedMetricMap (data ), nil
289
+ return c . newTaggedMetricMap (data ), nil
279
290
}
280
291
281
292
// Builds a TaggedMetricMap out of a generic string map.
282
293
// The top-level key is used as a tag and all sub-keys are flattened into metrics
283
- func newTaggedMetricMap (data map [string ]interface {}) taggedMetricMap {
294
+ func ( c * Ceph ) newTaggedMetricMap (data map [string ]interface {}) taggedMetricMap {
284
295
tmm := make (taggedMetricMap )
285
296
for tag , datapoints := range data {
286
297
mm := make (metricMap )
287
- for _ , m := range flatten (datapoints ) {
298
+ for _ , m := range c . flatten (datapoints ) {
288
299
mm [m .name ()] = m .value
289
300
}
290
301
tmm [tag ] = mm
@@ -296,7 +307,7 @@ func newTaggedMetricMap(data map[string]interface{}) taggedMetricMap {
296
307
// Nested keys are flattened into ordered slices associated with a metric value.
297
308
// The key slices are treated as stacks, and are expected to be reversed and concatenated
298
309
// when passed as metrics to the accumulator. (see (*metric).name())
299
- func flatten (data interface {}) []* metric {
310
+ func ( c * Ceph ) flatten (data interface {}) []* metric {
300
311
var metrics []* metric
301
312
302
313
switch val := data .(type ) {
@@ -305,20 +316,20 @@ func flatten(data interface{}) []*metric {
305
316
case map [string ]interface {}:
306
317
metrics = make ([]* metric , 0 , len (val ))
307
318
for k , v := range val {
308
- for _ , m := range flatten (v ) {
319
+ for _ , m := range c . flatten (v ) {
309
320
m .pathStack = append (m .pathStack , k )
310
321
metrics = append (metrics , m )
311
322
}
312
323
}
313
324
default :
314
- log . Printf ( "I! [inputs.ceph] ignoring unexpected type '%T' for value %v" , val , val )
325
+ c . Log . Infof ( " ignoring unexpected type '%T' for value %v" , val , val )
315
326
}
316
327
317
328
return metrics
318
329
}
319
330
320
- // exec executes the 'ceph' command with the supplied arguments, returning JSON formatted output
321
- func (c * Ceph ) exec (command string ) (string , error ) {
331
+ // execute executes the 'ceph' command with the supplied arguments, returning JSON formatted output
332
+ func (c * Ceph ) execute (command string ) (string , error ) {
322
333
cmdArgs := []string {"--conf" , c .CephConfig , "--name" , c .CephUser , "--format" , "json" }
323
334
cmdArgs = append (cmdArgs , strings .Split (command , " " )... )
324
335
0 commit comments