bosun.org@v0.0.0-20210513094433-e25bc3e69a1f/cmd/scollector/collectors/elasticsearch.go (about) 1 package collectors 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "io" 7 "io/ioutil" 8 "net/http" 9 "net/url" 10 "reflect" 11 "regexp" 12 "strings" 13 "time" 14 15 "bosun.org/cmd/scollector/conf" 16 "bosun.org/metadata" 17 "bosun.org/opentsdb" 18 "bosun.org/slog" 19 ) 20 21 func init() { 22 registerInit(func(c *conf.Conf) { 23 for _, filter := range c.ElasticIndexFilters { 24 err := AddElasticIndexFilter(filter, true) 25 if err != nil { 26 slog.Errorf("Error processing ElasticIndexFilter: %s", err) 27 } 28 } 29 for _, filter := range c.ElasticIndexFiltersInc { 30 err := AddElasticIndexFilter(filter, false) 31 if err != nil { 32 slog.Errorf("Error processing ElasticIndexFilterInc: %s", err) 33 } 34 } 35 if c.Elastic == nil { 36 // preserve the legacy defaults (localhost:9200) 37 c.Elastic = append(c.Elastic, conf.Elastic{}) 38 } 39 for _, instance := range c.Elastic { 40 var indexInterval = time.Minute * 15 41 var clusterInterval = DefaultFreq 42 var err error 43 // preserve defaults of localhost:9200 44 if instance.Host == "" { 45 instance.Host = "localhost" 46 } 47 if instance.Port == 0 { 48 instance.Port = 9200 49 } 50 if instance.Scheme == "" { 51 instance.Scheme = "http" 52 } 53 if instance.Name == "" { 54 instance.Name = fmt.Sprintf("%v_%v", instance.Host, instance.Port) 55 } 56 if instance.Disable { 57 slog.Infof("Elastic instance %v is disabled. Skipping.", instance.Name) 58 continue 59 } 60 var creds string 61 if instance.User != "" || instance.Password != "" { 62 creds = fmt.Sprintf("%v:%v@", instance.User, instance.Password) 63 } else { 64 creds = "" 65 } 66 url := fmt.Sprintf("%v://%v%v:%v", instance.Scheme, creds, instance.Host, instance.Port) 67 if instance.IndexInterval != "" { 68 indexInterval, err = time.ParseDuration(instance.IndexInterval) 69 if err != nil { 70 panic(fmt.Errorf("Failed to parse IndexInterval: %v, err: %v", instance.IndexInterval, err)) 71 } 72 slog.Infof("Using IndexInterval: %v for %v", indexInterval, instance.Name) 73 } else { 74 slog.Infof("Using default IndexInterval: %v for %v", indexInterval, instance.Name) 75 } 76 if instance.ClusterInterval != "" { 77 clusterInterval, err = time.ParseDuration(instance.ClusterInterval) 78 if err != nil { 79 panic(fmt.Errorf("Failed to parse ClusterInterval: %v, err: %v", instance.ClusterInterval, err)) 80 } 81 slog.Infof("Using ClusterInterval: %v for %v", clusterInterval, instance.Name) 82 } else { 83 slog.Infof("Using default ClusterInterval: %v for %v", clusterInterval, instance.Name) 84 } 85 // for legacy reasons, keep localhost:9200 named elasticsearch / elasticsearch-indices 86 var name string 87 if instance.Name == "localhost_9200" { 88 name = "elasticsearch" 89 } else { 90 name = fmt.Sprintf("elasticsearch-%v", instance.Name) 91 } 92 collectors = append(collectors, &IntervalCollector{ 93 F: func() (opentsdb.MultiDataPoint, error) { 94 return c_elasticsearch(false, instance) 95 }, 96 name: name, 97 Interval: clusterInterval, 98 Enable: enableURL(url), 99 }) 100 // keep legacy collector name if localhost_9200 101 if instance.Name == "localhost_9200" { 102 name = "elasticsearch-indices" 103 } else { 104 name = fmt.Sprintf("elasticsearch-indices-%v", instance.Name) 105 } 106 collectors = append(collectors, &IntervalCollector{ 107 F: func() (opentsdb.MultiDataPoint, error) { 108 return c_elasticsearch(true, instance) 109 }, 110 name: name, 111 Interval: indexInterval, 112 Enable: enableURL(url), 113 }) 114 } 115 }) 116 } 117 118 var ( 119 elasticPreV1 = regexp.MustCompile(`^0\.`) 120 elasticStatusMap = map[string]int{ 121 "green": 0, 122 "yellow": 1, 123 "red": 2, 124 } 125 elasticIndexFilters = make([]*regexp.Regexp, 0) 126 elasticIndexFiltersInc = make([]*regexp.Regexp, 0) 127 ) 128 129 func AddElasticIndexFilter(s string, exclude bool) error { 130 re, err := regexp.Compile(s) 131 if err != nil { 132 return err 133 } 134 if exclude { 135 slog.Infof("Added ES Index Filter: %v", s) 136 elasticIndexFilters = append(elasticIndexFilters, re) 137 } else { 138 slog.Infof("Added ES Index Inclusion Filter: %v", s) 139 elasticIndexFiltersInc = append(elasticIndexFiltersInc, re) 140 } 141 return nil 142 } 143 144 type structProcessor struct { 145 elasticVersion string 146 md *opentsdb.MultiDataPoint 147 } 148 149 // structProcessor.add() takes in a metric name prefix, an arbitrary struct, and a tagset. 150 // The processor recurses through the struct and builds metrics. The field tags direct how 151 // the field should be processed, as well as the metadata for the resulting metric. 152 // 153 // The field tags used are described as follows: 154 // 155 // version: typically set to '1' or '2'. 156 // This is compared against the elastic cluster version. If the version from the tag 157 // does not match the version in production, the metric will not be sent for this field. 158 // 159 // exclude: 160 // If this tag is set to 'true', a metric will not be sent for this field. 161 // 162 // rate: one of 'gauge', 'counter', 'rate' 163 // This tag dictates the metadata.RateType we send. 164 // 165 // unit: 'bytes', 'pages', etc 166 // This tag dictates the metadata.Unit we send. 167 // 168 // metric: 169 // This is the metric name which will be sent. If not present, the 'json' 170 // tag is sent as the metric name. 171 // 172 // Special handling: 173 // 174 // Metrics having the json tag suffix of 'in_milliseconds' are automagically 175 // divided by 1000 and sent as seconds. The suffix is stripped from the name. 176 // 177 // Metrics having the json tag suffix of 'in_bytes' are automatically sent as 178 // gauge bytes. The suffix is stripped from the metric name. 179 func (s *structProcessor) add(prefix string, st interface{}, ts opentsdb.TagSet) { 180 t := reflect.TypeOf(st) 181 valueOf := reflect.ValueOf(st) 182 for i := 0; i < t.NumField(); i++ { 183 field := t.Field(i) 184 value := valueOf.Field(i).Interface() 185 if field.Tag.Get("exclude") == "true" { 186 continue 187 } 188 var ( 189 jsonTag = field.Tag.Get("json") 190 metricTag = field.Tag.Get("metric") 191 versionTag = field.Tag.Get("version") 192 rateTag = field.Tag.Get("rate") 193 unitTag = field.Tag.Get("unit") 194 ) 195 metricName := jsonTag 196 if metricTag != "" { 197 metricName = metricTag 198 } 199 if metricName == "" { 200 slog.Errorf("Unable to determine metric name for field %s. Skipping.", field.Name) 201 continue 202 } 203 if versionTag == "" || strings.HasPrefix(s.elasticVersion, versionTag) { 204 switch value := value.(type) { 205 case int, float64: // Number types in our structs are only ints and float64s. 206 // Turn all millisecond metrics into seconds 207 if strings.HasSuffix(metricName, "_in_millis") { 208 switch value.(type) { 209 case int: 210 value = float64(value.(int)) / 1000 211 case float64: 212 value = value.(float64) / 1000 213 } 214 unitTag = "seconds" 215 metricName = strings.TrimSuffix(metricName, "_in_millis") 216 } 217 // Set rate and unit for all "_in_bytes" metrics, and strip the "_in_bytes" 218 if strings.HasSuffix(metricName, "_in_bytes") { 219 if rateTag == "" { 220 rateTag = "gauge" 221 } 222 unitTag = "bytes" 223 metricName = strings.TrimSuffix(metricName, "_in_bytes") 224 } 225 Add(s.md, prefix+"."+metricName, value, ts, metadata.RateType(rateTag), metadata.Unit(unitTag), field.Tag.Get("desc")) 226 case string: 227 // The json data has a lot of strings, and we don't care about em. 228 default: 229 // If we hit another struct, recurse 230 if reflect.ValueOf(value).Kind() == reflect.Struct { 231 s.add(prefix+"."+metricName, value, ts) 232 } else { 233 slog.Errorf("Field %s for metric %s is non-numeric type. Cannot record as a metric.\n", field.Name, prefix+"."+metricName) 234 } 235 } 236 } 237 } 238 } 239 240 func c_elasticsearch(collectIndices bool, instance conf.Elastic) (opentsdb.MultiDataPoint, error) { 241 slog.Infof("Updating ES stats for %v", instance) 242 var status ElasticStatus 243 if err := esReq(instance, "/", "", &status); err != nil { 244 return nil, err 245 } 246 var clusterStats ElasticClusterStats 247 if err := esReq(instance, esStatsURL(status.Version.Number), "", &clusterStats); err != nil { 248 return nil, err 249 } 250 var clusterState ElasticClusterState 251 if err := esReq(instance, "/_cluster/state/master_node", "", &clusterState); err != nil { 252 return nil, err 253 } 254 var clusterHealth ElasticHealth 255 if err := esReq(instance, "/_cluster/health", "level=indices", &clusterHealth); err != nil { 256 return nil, err 257 } 258 var indexStats ElasticIndexStats 259 if err := esReq(instance, "/_stats", "", &indexStats); err != nil { 260 return nil, err 261 } 262 var md opentsdb.MultiDataPoint 263 s := structProcessor{elasticVersion: status.Version.Number, md: &md} 264 ts := opentsdb.TagSet{"cluster": clusterStats.ClusterName} 265 isMaster := false 266 // As we're pulling _local stats here, this will only process 1 node. 267 for nodeID, nodeStats := range clusterStats.Nodes { 268 isMaster = nodeID == clusterState.MasterNode 269 if isMaster { 270 s.add("elastic.health.cluster", clusterHealth, ts) 271 if statusCode, ok := elasticStatusMap[clusterHealth.Status]; ok { 272 Add(&md, "elastic.health.cluster.status", statusCode, ts, metadata.Gauge, metadata.StatusCode, "The current status of the cluster. Zero for green, one for yellow, two for red.") 273 } 274 indexStatusCount := map[string]int{ 275 "green": 0, 276 "yellow": 0, 277 "red": 0, 278 } 279 for _, index := range clusterHealth.Indices { 280 indexStatusCount[index.Status] += 1 281 } 282 for status, count := range indexStatusCount { 283 Add(&md, "elastic.health.cluster.index_status_count", count, opentsdb.TagSet{"status": status}.Merge(ts), metadata.Gauge, metadata.Unit("indices"), "Index counts by status.") 284 } 285 } 286 s.add("elastic", nodeStats, ts) 287 // These are index stats in aggregate for this node. 288 s.add("elastic.indices.local", nodeStats.Indices, ts) 289 s.add("elastic.jvm.gc", nodeStats.JVM.GC.Collectors.Old, opentsdb.TagSet{"gc": "old"}.Merge(ts)) 290 s.add("elastic.jvm.gc", nodeStats.JVM.GC.Collectors.Young, opentsdb.TagSet{"gc": "young"}.Merge(ts)) 291 } 292 if collectIndices && isMaster { 293 for k, index := range indexStats.Indices { 294 if esSkipIndex(k) { 295 slog.Infof("Skipping index: %v", k) 296 continue 297 } 298 slog.Infof("Pulling index stats: %v", k) 299 ts := opentsdb.TagSet{"index_name": k, "cluster": clusterStats.ClusterName} 300 if indexHealth, ok := clusterHealth.Indices[k]; ok { 301 s.add("elastic.health.indices", indexHealth, ts) 302 if status, ok := elasticStatusMap[indexHealth.Status]; ok { 303 Add(&md, "elastic.health.indices.status", status, ts, metadata.Gauge, metadata.StatusCode, "The current status of the index. Zero for green, one for yellow, two for red.") 304 } 305 } 306 s.add("elastic.indices.cluster", index.Primaries, ts) 307 } 308 } 309 return md, nil 310 } 311 312 func esSkipIndex(index string) bool { 313 for _, re := range elasticIndexFilters { 314 if re.MatchString(index) { 315 return true 316 } 317 } 318 for _, re := range elasticIndexFiltersInc { 319 if re.MatchString(index) { 320 return false 321 } 322 } 323 return len(elasticIndexFiltersInc) > 0 324 } 325 326 func esReq(instance conf.Elastic, path, query string, v interface{}) error { 327 up := url.UserPassword(instance.User, instance.Password) 328 u := &url.URL{ 329 Scheme: instance.Scheme, 330 User: up, 331 Host: fmt.Sprintf("%v:%v", instance.Host, instance.Port), 332 Path: path, 333 RawQuery: query, 334 } 335 resp, err := http.Get(u.String()) 336 if err != nil { 337 slog.Errorf("Error querying Elasticsearch: %v", err) 338 return nil 339 } 340 defer resp.Body.Close() 341 if resp.StatusCode != http.StatusOK { 342 // Drain up to 512 bytes and close the body to let the Transport reuse the connection 343 io.CopyN(ioutil.Discard, resp.Body, 512) 344 return nil 345 } 346 j := json.NewDecoder(resp.Body) 347 return j.Decode(v) 348 } 349 350 func esStatsURL(version string) string { 351 if elasticPreV1.MatchString(version) { 352 return "/_cluster/nodes/_local/stats" 353 } 354 return "/_nodes/_local/stats" 355 } 356 357 type ElasticHealth struct { 358 ActivePrimaryShards int `json:"active_primary_shards" desc:"The number of active primary shards. Each document is stored in a single primary shard and then when it is indexed it is copied the replicas of that shard."` 359 ActiveShards int `json:"active_shards" desc:"The number of active shards."` 360 ActiveShardsPercentAsNumber float64 `json:"active_shards_percent_as_number" version:"2"` // 2.0 only 361 ClusterName string `json:"cluster_name"` 362 DelayedUnassignedShards int `json:"delayed_unassigned_shards" version:"2"` // 2.0 only 363 Indices map[string]ElasticIndexHealth `json:"indices" exclude:"true"` 364 InitializingShards int `json:"initializing_shards" desc:"The number of initalizing shards."` 365 NumberOfDataNodes int `json:"number_of_data_nodes"` 366 NumberOfInFlightFetch int `json:"number_of_in_flight_fetch" version:"2"` // 2.0 only 367 NumberOfNodes int `json:"number_of_nodes"` 368 NumberOfPendingTasks int `json:"number_of_pending_tasks"` 369 RelocatingShards int `json:"relocating_shards" desc:"The number of shards relocating."` 370 Status string `json:"status" desc:"The current status of the cluster. 0: green, 1: yellow, 2: red."` 371 TaskMaxWaitingInQueueMillis int `json:"task_max_waiting_in_queue_millis" version:"2"` // 2.0 only 372 TimedOut bool `json:"timed_out" exclude:"true"` 373 UnassignedShards int `json:"unassigned_shards" version:"2"` // 2.0 only 374 } 375 376 type ElasticIndexHealth struct { 377 ActivePrimaryShards int `json:"active_primary_shards" desc:"The number of active primary shards. Each document is stored in a single primary shard and then when it is indexed it is copied the replicas of that shard."` 378 ActiveShards int `json:"active_shards" desc:"The number of active shards."` 379 InitializingShards int `json:"initializing_shards" desc:"The number of initalizing shards."` 380 NumberOfReplicas int `json:"number_of_replicas" desc:"The number of replicas."` 381 NumberOfShards int `json:"number_of_shards" desc:"The number of shards."` 382 RelocatingShards int `json:"relocating_shards" desc:"The number of shards relocating."` 383 Status string `json:"status" desc:"The current status of the index. 0: green, 1: yellow, 2: red."` 384 UnassignedShards int `json:"unassigned_shards"` 385 } 386 387 type ElasticIndexStats struct { 388 All ElasticIndex `json:"_all"` 389 Shards struct { 390 Failed float64 `json:"failed"` 391 Successful float64 `json:"successful"` 392 Total float64 `json:"total"` 393 } `json:"_shards"` 394 Indices map[string]ElasticIndex `json:"indices"` 395 } 396 397 type ElasticIndex struct { 398 Primaries ElasticIndexDetails `json:"primaries"` 399 Total ElasticIndexDetails `json:"total"` 400 } 401 402 type ElasticIndexDetails struct { 403 Completion struct { 404 SizeInBytes int `json:"size_in_bytes" desc:"Size of the completion index (used for auto-complete functionallity)."` 405 } `json:"completion"` 406 Docs struct { 407 Count int `json:"count" rate:"gauge" rate:"gauge" unit:"documents" desc:"The number of documents in the index."` 408 Deleted int `json:"deleted" rate:"gauge" unit:"documents" desc:"The number of deleted documents in the index."` 409 } `json:"docs"` 410 Fielddata struct { 411 Evictions int `json:"evictions" rate:"counter" unit:"evictions" desc:"The number of cache evictions for field data."` 412 MemorySizeInBytes int `json:"memory_size_in_bytes" desc:"The amount of memory used for field data."` 413 } `json:"fielddata"` 414 FilterCache struct { // 1.0 only 415 Evictions int `json:"evictions" version:"1" rate:"counter" unit:"evictions" desc:"The number of cache evictions for filter data."` // 1.0 only 416 MemorySizeInBytes int `json:"memory_size_in_bytes" version:"1" desc:"The amount of memory used for filter data."` // 1.0 only 417 } `json:"filter_cache"` 418 Flush struct { 419 Total int `json:"total" rate:"counter" unit:"flushes" desc:"The number of flush operations. The flush process of an index basically frees memory from the index by flushing data to the index storage and clearing the internal transaction log."` 420 TotalTimeInMillis int `json:"total_time_in_millis" rate:"counter" unit:"seconds" desc:"The total amount of time spent on flush operations. The flush process of an index basically frees memory from the index by flushing data to the index storage and clearing the internal transaction log."` 421 } `json:"flush"` 422 Get struct { 423 Current int `json:"current" rate:"gauge" unit:"gets" desc:"The current number of get operations. Gets get a typed JSON document from the index based on its id."` 424 ExistsTimeInMillis int `json:"exists_time_in_millis" rate:"counter" unit:"seconds" desc:"The total amount of time spent on get exists operations. Gets exists sees if a document exists."` 425 ExistsTotal int `json:"exists_total" rate:"counter" unit:"get exists" desc:"The total number of get exists operations. Gets exists sees if a document exists."` 426 MissingTimeInMillis int `json:"missing_time_in_millis" rate:"counter" unit:"seconds" desc:"The total amount of time spent trying to get documents that turned out to be missing."` 427 MissingTotal int `json:"missing_total" rate:"counter" unit:"operations" desc:"The total number of operations that tried to get a document that turned out to be missing."` 428 TimeInMillis int `json:"time_in_millis" rate:"counter" unit:"seconds" desc:"The total amount of time spent on get operations. Gets get a typed JSON document from the index based on its id."` 429 Total int `json:"total" rate:"counter" unit:"operations" desc:"The total number of get operations. Gets get a typed JSON document from the index based on its id."` 430 } `json:"get"` 431 IDCache struct { // 1.0 only 432 MemorySizeInBytes int `json:"memory_size_in_bytes" version:"1" desc:"The size of the id cache."` // 1.0 only 433 } `json:"id_cache"` 434 Indexing struct { 435 DeleteCurrent int `json:"delete_current" rate:"gauge" unit:"documents" desc:"The current number of documents being deleted via indexing commands (such as a delete query)."` 436 DeleteTimeInMillis int `json:"delete_time_in_millis" rate:"counter" unit:"seconds" desc:"The time spent deleting documents."` 437 DeleteTotal int `json:"delete_total" rate:"counter" unit:"documents" desc:"The total number of documents deleted."` 438 IndexCurrent int `json:"index_current" rate:"gauge" unit:"documents" desc:"The current number of documents being indexed."` 439 IndexTimeInMillis int `json:"index_time_in_millis" rate:"counter" unit:"seconds" desc:"The total amount of time spent indexing documents."` 440 IndexTotal int `json:"index_total" rate:"counter" unit:"documents" desc:"The total number of documents indexed."` 441 IsThrottled bool `json:"is_throttled" exclude:"true"` 442 NoopUpdateTotal int `json:"noop_update_total"` 443 ThrottleTimeInMillis int `json:"throttle_time_in_millis"` 444 } `json:"indexing"` 445 Merges struct { 446 Current int `json:"current" rate:"gauge" unit:"merges" desc:"The current number of merge operations. In elastic Lucene segments are merged behind the scenes. It is possible these can impact search performance."` 447 CurrentDocs int `json:"current_docs" rate:"gauge" unit:"documents" desc:"The current number of documents that have an underlying merge operation going on. In elastic Lucene segments are merged behind the scenes. It is possible these can impact search performance."` 448 CurrentSizeInBytes int `json:"current_size_in_bytes" desc:"The current number of bytes being merged. In elastic Lucene segments are merged behind the scenes. It is possible these can impact search performance."` 449 Total int `json:"total" rate:"counter" unit:"merges" desc:"The total number of merges. In elastic Lucene segments are merged behind the scenes. It is possible these can impact search performance."` 450 TotalAutoThrottleInBytes int `json:"total_auto_throttle_in_bytes" version:"2"` // 2.0 only 451 TotalDocs int `json:"total_docs" rate:"counter" unit:"documents" desc:"The total number of documents that have had an underlying merge operation. In elastic Lucene segments are merged behind the scenes. It is possible these can impact search performance."` 452 TotalSizeInBytes int `json:"total_size_in_bytes" desc:"The total number of bytes merged. In elastic Lucene segments are merged behind the scenes. It is possible these can impact search performance."` 453 TotalStoppedTimeInMillis int `json:"total_stopped_time_in_millis" version:"2"` // 2.0 only 454 TotalThrottledTimeInMillis int `json:"total_throttled_time_in_millis" version:"2"` // 2.0 only 455 TotalTimeInMillis int `json:"total_time_in_millis" rate:"counter" unit:"seconds" desc:"The total amount of time spent on merge operations. In elastic Lucene segments are merged behind the scenes. It is possible these can impact search performance."` 456 } `json:"merges"` 457 Percolate struct { 458 Current int `json:"current" rate:"gauge" unit:"operations" desc:"The current number of percolate operations."` 459 MemorySize string `json:"memory_size"` 460 MemorySizeInBytes int `json:"memory_size_in_bytes" desc:"The amount of memory used for the percolate index. Percolate is a reverse query to document operation."` 461 Queries int `json:"queries" rate:"counter" unit:"queries" desc:"The total number of percolate queries. Percolate is a reverse query to document operation."` 462 TimeInMillis int `json:"time_in_millis" rate:"counter" unit:"seconds" desc:"The total amount of time spent on percolating. Percolate is a reverse query to document operation."` 463 Total int `json:"total" rate:"gauge" unit:"operations" desc:"The total number of percolate operations. Percolate is a reverse query to document operation."` 464 } `json:"percolate"` 465 QueryCache struct { 466 CacheCount int `json:"cache_count" version:"2"` // 2.0 only 467 CacheSize int `json:"cache_size" version:"2"` // 2.0 only 468 Evictions int `json:"evictions"` 469 HitCount int `json:"hit_count"` 470 MemorySizeInBytes int `json:"memory_size_in_bytes"` 471 MissCount int `json:"miss_count"` 472 TotalCount int `json:"total_count" version:"2"` // 2.0 only 473 } `json:"query_cache"` 474 Recovery struct { 475 CurrentAsSource int `json:"current_as_source"` 476 CurrentAsTarget int `json:"current_as_target"` 477 ThrottleTimeInMillis int `json:"throttle_time_in_millis"` 478 } `json:"recovery"` 479 Refresh struct { 480 Total int `json:"total" rate:"counter" unit:"refresh" desc:"The total number of refreshes. Refreshing makes all operations performed since the last search available."` 481 TotalTimeInMillis int `json:"total_time_in_millis" rate:"counter" unit:"seconds" desc:"The total amount of time spent on refreshes. Refreshing makes all operations performed since the last search available."` 482 } `json:"refresh"` 483 RequestCache struct { // 2.0 only 484 Evictions int `json:"evictions" version:"2"` // 2.0 only 485 HitCount int `json:"hit_count" version:"2"` // 2.0 only 486 MemorySizeInBytes int `json:"memory_size_in_bytes" version:"2"` // 2.0 only 487 MissCount int `json:"miss_count" version:"2"` // 2.0 only 488 } `json:"request_cache"` 489 Search struct { 490 FetchCurrent int `json:"fetch_current" rate:"gauge" unit:"documents" desc:"The current number of documents being fetched. Fetching is a phase of querying in a distributed search."` 491 FetchTimeInMillis int `json:"fetch_time_in_millis" rate:"counter" unit:"seconds" desc:"The total time spent fetching documents. Fetching is a phase of querying in a distributed search."` 492 FetchTotal int `json:"fetch_total" rate:"counter" unit:"documents" desc:"The total number of documents fetched. Fetching is a phase of querying in a distributed search."` 493 OpenContexts int `json:"open_contexts" rate:"gauge" unit:"contexts" desc:"The current number of open contexts. A search is left open when srolling (i.e. pagination)."` 494 QueryCurrent int `json:"query_current" rate:"gauge" unit:"queries" desc:"The current number of queries."` 495 QueryTimeInMillis int `json:"query_time_in_millis" rate:"counter" unit:"seconds" desc:"The total amount of time spent querying."` 496 QueryTotal int `json:"query_total" rate:"counter" unit:"queries" desc:"The total number of queries."` 497 ScrollCurrent int `json:"scroll_current" version:"2"` // 2.0 only 498 ScrollTimeInMillis int `json:"scroll_time_in_millis" version:"2"` // 2.0 only 499 ScrollTotal int `json:"scroll_total" version:"2"` // 2.0 only 500 } `json:"search"` 501 Segments struct { 502 Count int `json:"count" rate:"counter" unit:"segments" desc:"The number of segments that make up the index."` 503 DocValuesMemoryInBytes int `json:"doc_values_memory_in_bytes" version:"2"` // 2.0 only 504 FixedBitSetMemoryInBytes int `json:"fixed_bit_set_memory_in_bytes"` 505 IndexWriterMaxMemoryInBytes int `json:"index_writer_max_memory_in_bytes"` 506 IndexWriterMemoryInBytes int `json:"index_writer_memory_in_bytes"` 507 MemoryInBytes int `json:"memory_in_bytes" desc:"The total amount of memory used for Lucene segments."` 508 NormsMemoryInBytes int `json:"norms_memory_in_bytes" version:"2"` // 2.0 only 509 StoredFieldsMemoryInBytes int `json:"stored_fields_memory_in_bytes" version:"2"` // 2.0 only 510 TermVectorsMemoryInBytes int `json:"term_vectors_memory_in_bytes" version:"2"` // 2.0 only 511 TermsMemoryInBytes int `json:"terms_memory_in_bytes" version:"2"` // 2.0 only 512 VersionMapMemoryInBytes int `json:"version_map_memory_in_bytes"` 513 } `json:"segments"` 514 Store struct { 515 SizeInBytes int `json:"size_in_bytes" unit:"bytes" desc:"The current size of the store."` 516 ThrottleTimeInMillis int `json:"throttle_time_in_millis" rate:"gauge" unit:"seconds" desc:"The amount of time that merges where throttled."` 517 } `json:"store"` 518 Suggest struct { 519 Current int `json:"current" rate:"gauge" unit:"suggests" desc:"The current number of suggest operations."` 520 TimeInMillis int `json:"time_in_millis" rate:"gauge" unit:"seconds" desc:"The total amount of time spent on suggest operations."` 521 Total int `json:"total" rate:"gauge" unit:"suggests" desc:"The total number of suggest operations."` 522 } `json:"suggest"` 523 Translog struct { 524 Operations int `json:"operations" rate:"gauge" unit:"operations" desc:"The total number of translog operations. The transaction logs (or write ahead logs) ensure atomicity of operations."` 525 SizeInBytes int `json:"size_in_bytes" desc:"The current size of transaction log. The transaction log (or write ahead log) ensure atomicity of operations."` 526 } `json:"translog"` 527 Warmer struct { 528 Current int `json:"current" rate:"gauge" unit:"operations" desc:"The current number of warmer operations. Warming registers search requests in the background to speed up actual search requests."` 529 Total int `json:"total" rate:"gauge" unit:"operations" desc:"The total number of warmer operations. Warming registers search requests in the background to speed up actual search requests."` 530 TotalTimeInMillis int `json:"total_time_in_millis" rate:"gauge" unit:"seconds" desc:"The total time spent on warmer operations. Warming registers search requests in the background to speed up actual search requests."` 531 } `json:"warmer"` 532 } 533 534 type ElasticStatus struct { 535 Status int `json:"status"` 536 Name string `json:"name"` 537 Version struct { 538 Number string `json:"number"` 539 } `json:"version"` 540 } 541 542 type ElasticClusterStats struct { 543 ClusterName string `json:"cluster_name"` 544 Nodes map[string]struct { 545 Attributes struct { 546 Master string `json:"master"` 547 } `json:"attributes"` 548 Breakers struct { 549 Fielddata ElasticBreakersStat `json:"fielddata"` 550 Parent ElasticBreakersStat `json:"parent"` 551 Request ElasticBreakersStat `json:"request"` 552 } `json:"breakers" exclude:"true"` 553 FS struct { 554 Data []struct { 555 AvailableInBytes int `json:"available_in_bytes"` 556 Dev string `json:"dev" version:"1"` // 1.0 only 557 DiskIoOp int `json:"disk_io_op" version:"1"` // 1.0 only 558 DiskIoSizeInBytes int `json:"disk_io_size_in_bytes" version:"1"` // 1.0 only 559 DiskQueue string `json:"disk_queue" version:"1"` // 1.0 only 560 DiskReadSizeInBytes int `json:"disk_read_size_in_bytes" version:"1"` // 1.0 only 561 DiskReads int `json:"disk_reads" version:"1"` // 1.0 only 562 DiskServiceTime string `json:"disk_service_time" version:"1"` // 1.0 only 563 DiskWriteSizeInBytes int `json:"disk_write_size_in_bytes" version:"1"` // 1.0 only 564 DiskWrites int `json:"disk_writes" version:"1"` // 1.0 only 565 FreeInBytes int `json:"free_in_bytes"` 566 Mount string `json:"mount"` 567 Path string `json:"path"` 568 TotalInBytes int `json:"total_in_bytes"` 569 Type string `json:"type" version:"2"` // 2.0 only 570 } `json:"data"` 571 Timestamp int `json:"timestamp"` 572 Total struct { 573 AvailableInBytes int `json:"available_in_bytes"` 574 DiskIoOp int `json:"disk_io_op" version:"1"` // 1.0 only 575 DiskIoSizeInBytes int `json:"disk_io_size_in_bytes" version:"1"` // 1.0 only 576 DiskQueue string `json:"disk_queue" version:"1"` // 1.0 only 577 DiskReadSizeInBytes int `json:"disk_read_size_in_bytes" version:"1"` // 1.0 only 578 DiskReads int `json:"disk_reads" version:"1"` // 1.0 only 579 DiskServiceTime string `json:"disk_service_time" version:"1"` // 1.0 only 580 DiskWriteSizeInBytes int `json:"disk_write_size_in_bytes" version:"1"` // 1.0 only 581 DiskWrites int `json:"disk_writes" version:"1"` // 1.0 only 582 FreeInBytes int `json:"free_in_bytes"` 583 TotalInBytes int `json:"total_in_bytes"` 584 } `json:"total"` 585 } `json:"fs" exclude:"true"` 586 Host string `json:"host"` 587 HTTP struct { 588 CurrentOpen int `json:"current_open"` 589 TotalOpened int `json:"total_opened"` 590 } `json:"http"` 591 Indices ElasticIndexDetails `json:"indices" exclude:"true"` // Stored under elastic.indices.local namespace. 592 //IP []string `json:"ip" exclude:"true"` // Incompatible format between 5.x and previous, and not used in collector 593 JVM struct { 594 BufferPools struct { 595 Direct struct { 596 Count int `json:"count"` 597 TotalCapacityInBytes int `json:"total_capacity_in_bytes"` 598 UsedInBytes int `json:"used_in_bytes"` 599 } `json:"direct"` 600 Mapped struct { 601 Count int `json:"count"` 602 TotalCapacityInBytes int `json:"total_capacity_in_bytes"` 603 UsedInBytes int `json:"used_in_bytes"` 604 } `json:"mapped"` 605 } `json:"buffer_pools"` 606 Classes struct { // 2.0 only 607 CurrentLoadedCount int `json:"current_loaded_count" version:"2"` // 2.0 only 608 TotalLoadedCount int `json:"total_loaded_count" version:"2"` // 2.0 only 609 TotalUnloadedCount int `json:"total_unloaded_count" version:"2"` // 2.0 only 610 } `json:"classes"` 611 GC struct { 612 Collectors struct { 613 Old struct { 614 CollectionCount int `json:"collection_count"` 615 CollectionTimeInMillis int `json:"collection_time_in_millis"` 616 } `json:"old"` 617 Young struct { 618 CollectionCount int `json:"collection_count"` 619 CollectionTimeInMillis int `json:"collection_time_in_millis"` 620 } `json:"young"` 621 } `json:"collectors"` 622 } `json:"gc" exclude:"true"` // This is recorded manually so we can tag the GC collector type. 623 Mem struct { 624 HeapCommittedInBytes int `json:"heap_committed_in_bytes" metric:"heap_committed"` 625 HeapMaxInBytes int `json:"heap_max_in_bytes"` 626 HeapUsedInBytes int `json:"heap_used_in_bytes" metric:"heap_used"` 627 HeapUsedPercent int `json:"heap_used_percent"` 628 NonHeapCommittedInBytes int `json:"non_heap_committed_in_bytes"` 629 NonHeapUsedInBytes int `json:"non_heap_used_in_bytes"` 630 Pools struct { 631 Old struct { 632 MaxInBytes int `json:"max_in_bytes"` 633 PeakMaxInBytes int `json:"peak_max_in_bytes"` 634 PeakUsedInBytes int `json:"peak_used_in_bytes"` 635 UsedInBytes int `json:"used_in_bytes"` 636 } `json:"old"` 637 Survivor struct { 638 MaxInBytes int `json:"max_in_bytes"` 639 PeakMaxInBytes int `json:"peak_max_in_bytes"` 640 PeakUsedInBytes int `json:"peak_used_in_bytes"` 641 UsedInBytes int `json:"used_in_bytes"` 642 } `json:"survivor"` 643 Young struct { 644 MaxInBytes int `json:"max_in_bytes"` 645 PeakMaxInBytes int `json:"peak_max_in_bytes"` 646 PeakUsedInBytes int `json:"peak_used_in_bytes"` 647 UsedInBytes int `json:"used_in_bytes"` 648 } `json:"young"` 649 } `json:"pools" exclude:"true"` 650 } `json:"mem"` 651 Threads struct { 652 Count int `json:"count"` 653 PeakCount int `json:"peak_count"` 654 } `json:"threads"` 655 Timestamp int `json:"timestamp"` 656 UptimeInMillis int `json:"uptime_in_millis"` 657 } `json:"jvm"` 658 Name string `json:"name"` 659 Network struct { // 1.0 only 660 TCP struct { // 1.0 only 661 ActiveOpens int `json:"active_opens" version:"1"` // 1.0 only 662 AttemptFails int `json:"attempt_fails" version:"1"` // 1.0 only 663 CurrEstab int `json:"curr_estab" version:"1"` // 1.0 only 664 EstabResets int `json:"estab_resets" version:"1"` // 1.0 only 665 InErrs int `json:"in_errs" version:"1"` // 1.0 only 666 InSegs int `json:"in_segs" version:"1"` // 1.0 only 667 OutRsts int `json:"out_rsts" version:"1"` // 1.0 only 668 OutSegs int `json:"out_segs" version:"1"` // 1.0 only 669 PassiveOpens int `json:"passive_opens" version:"1"` // 1.0 only 670 RetransSegs int `json:"retrans_segs" version:"1"` // 1.0 only 671 } `json:"tcp"` 672 } `json:"network"` 673 OS struct { 674 CPU struct { // 1.0 only 675 Idle int `json:"idle" version:"1"` // 1.0 only 676 Stolen int `json:"stolen" version:"1"` // 1.0 only 677 Sys int `json:"sys" version:"1"` // 1.0 only 678 Usage int `json:"usage" version:"1"` // 1.0 only 679 User int `json:"user" version:"1"` // 1.0 only 680 } `json:"cpu"` 681 // LoadAverage []float64 `json:"load_average"` // 1.0 only 682 // LoadAverage float64 `json:"load_average"` // 2.0 only 683 Mem struct { 684 ActualFreeInBytes int `json:"actual_free_in_bytes" version:"1"` // 1.0 only 685 ActualUsedInBytes int `json:"actual_used_in_bytes" version:"1"` // 1.0 only 686 FreeInBytes int `json:"free_in_bytes"` 687 FreePercent int `json:"free_percent"` 688 TotalInBytes int `json:"total_in_bytes" version:"2"` // 2.0 only 689 UsedInBytes int `json:"used_in_bytes"` 690 UsedPercent int `json:"used_percent"` 691 } `json:"mem"` 692 Swap struct { 693 FreeInBytes int `json:"free_in_bytes"` 694 TotalInBytes int `json:"total_in_bytes" version:"2"` // 2.0 only 695 UsedInBytes int `json:"used_in_bytes"` 696 } `json:"swap"` 697 Timestamp int `json:"timestamp"` 698 UptimeInMillis int `json:"uptime_in_millis"` 699 } `json:"os" exclude:"true"` // These are OS-wide stats, and are already gathered by other collectors. 700 Process struct { 701 CPU struct { 702 Percent int `json:"percent" exclude:"true"` 703 SysInMillis int `json:"sys_in_millis" version:"1"` // 1.0 only 704 TotalInMillis int `json:"total_in_millis"` 705 UserInMillis int `json:"user_in_millis" version:"1"` // 1.0 only 706 } `json:"cpu"` 707 MaxFileDescriptors int `json:"max_file_descriptors" version:"2"` // 2.0 only 708 Mem struct { 709 ResidentInBytes int `json:"resident_in_bytes" metric:"resident" version:"1"` // 1.0 only 710 ShareInBytes int `json:"share_in_bytes" metric:"shared" version:"1"` // 1.0 only 711 TotalVirtualInBytes int `json:"total_virtual_in_bytes" metric:"total_virtual"` 712 } `json:"mem"` 713 OpenFileDescriptors int `json:"open_file_descriptors"` 714 Timestamp int `json:"timestamp" exclude:"true"` 715 } `json:"process"` 716 Script struct { // 2.0 only 717 CacheEvictions int `json:"cache_evictions" version:"2"` // 2.0 only 718 Compilations int `json:"compilations" version:"2"` // 2.0 only 719 } `json:"script"` 720 ThreadPool struct { 721 Bulk ElasticThreadPoolStat `json:"bulk"` 722 FetchShardStarted ElasticThreadPoolStat `json:"fetch_shard_started" version:"2"` // 2.0 only 723 FetchShardStore ElasticThreadPoolStat `json:"fetch_shard_store" version:"2"` // 2.0 only 724 Flush ElasticThreadPoolStat `json:"flush"` 725 Generic ElasticThreadPoolStat `json:"generic"` 726 Get ElasticThreadPoolStat `json:"get"` 727 Index ElasticThreadPoolStat `json:"index"` 728 Listener ElasticThreadPoolStat `json:"listener"` 729 Management ElasticThreadPoolStat `json:"management"` 730 Merge ElasticThreadPoolStat `json:"merge" version:"1"` // 1.0 only 731 Optimize ElasticThreadPoolStat `json:"optimize"` 732 Percolate ElasticThreadPoolStat `json:"percolate"` 733 Refresh ElasticThreadPoolStat `json:"refresh"` 734 Search ElasticThreadPoolStat `json:"search"` 735 Snapshot ElasticThreadPoolStat `json:"snapshot"` 736 Suggest ElasticThreadPoolStat `json:"suggest"` 737 Warmer ElasticThreadPoolStat `json:"warmer"` 738 } `json:"thread_pool" exclude:"true"` 739 Timestamp int `json:"timestamp"` 740 Transport struct { 741 RxCount int `json:"rx_count"` 742 RxSizeInBytes int `json:"rx_size_in_bytes"` 743 ServerOpen int `json:"server_open"` 744 TxCount int `json:"tx_count"` 745 TxSizeInBytes int `json:"tx_size_in_bytes"` 746 } `json:"transport"` 747 TransportAddress string `json:"transport_address"` 748 } `json:"nodes"` 749 } 750 751 type ElasticThreadPoolStat struct { 752 Active int `json:"active"` 753 Completed int `json:"completed"` 754 Largest int `json:"largest"` 755 Queue int `json:"queue"` 756 Rejected int `json:"rejected"` 757 Threads int `json:"threads"` 758 } 759 760 type ElasticBreakersStat struct { 761 EstimatedSize string `json:"estimated_size"` 762 EstimatedSizeInBytes int `json:"estimated_size_in_bytes"` 763 LimitSize string `json:"limit_size"` 764 LimitSizeInBytes int `json:"limit_size_in_bytes"` 765 Overhead float64 `json:"overhead"` 766 Tripped int `json:"tripped"` 767 } 768 769 type ElasticClusterState struct { 770 MasterNode string `json:"master_node"` 771 }