youtubebeat/vendor/github.com/elastic/beats/metricbeat/module/elasticsearch/node_stats/data_xpack.go

229 lines
8.3 KiB
Go

// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package node_stats
import (
"encoding/json"
"time"
"github.com/pkg/errors"
"github.com/elastic/beats/libbeat/common"
s "github.com/elastic/beats/libbeat/common/schema"
c "github.com/elastic/beats/libbeat/common/schema/mapstriface"
"github.com/elastic/beats/libbeat/logp"
"github.com/elastic/beats/metricbeat/helper/elastic"
"github.com/elastic/beats/metricbeat/mb"
"github.com/elastic/beats/metricbeat/module/elasticsearch"
)
var (
sourceNodeXpack = s.Schema{
"host": c.Str("host"),
"transport_address": c.Str("transport_address"),
"ip": c.Str("ip"),
"name": c.Str("name"),
}
schemaXpack = s.Schema{
"indices": c.Dict("indices", s.Schema{
"docs": c.Dict("docs", s.Schema{
"count": c.Int("count"),
}),
"store": c.Dict("store", s.Schema{
"size_in_bytes": c.Int("size_in_bytes"),
}),
"indexing": c.Dict("indexing", s.Schema{
"index_total": c.Int("index_total"),
"index_time_in_millis": c.Int("index_time_in_millis"),
"throttle_time_in_millis": c.Int("throttle_time_in_millis"),
}),
"search": c.Dict("search", s.Schema{
"query_total": c.Int("query_total"),
"query_time_in_millis": c.Int("query_time_in_millis"),
}),
"query_cache": c.Dict("query_cache", s.Schema{
"memory_size_in_bytes": c.Int("memory_size_in_bytes"),
"hit_count": c.Int("hit_count"),
"miss_count": c.Int("miss_count"),
"evictions": c.Int("evictions"),
}),
"fielddata": c.Dict("fielddata", s.Schema{
"memory_size_in_bytes": c.Int("memory_size_in_bytes"),
"evictions": c.Int("evictions"),
}),
"segments": c.Dict("segments", s.Schema{
"count": c.Int("count"),
"memory_in_bytes": c.Int("memory_in_bytes"),
"terms_memory_in_bytes": c.Int("terms_memory_in_bytes"),
"stored_fields_memory_in_bytes": c.Int("stored_fields_memory_in_bytes"),
"term_vectors_memory_in_bytes": c.Int("term_vectors_memory_in_bytes"),
"norms_memory_in_bytes": c.Int("norms_memory_in_bytes"),
"points_memory_in_bytes": c.Int("points_memory_in_bytes"),
"doc_values_memory_in_bytes": c.Int("doc_values_memory_in_bytes"),
"index_writer_memory_in_bytes": c.Int("index_writer_memory_in_bytes"),
"version_map_memory_in_bytes": c.Int("version_map_memory_in_bytes"),
"fixed_bit_set_memory_in_bytes": c.Int("fixed_bit_set_memory_in_bytes"),
}),
"request_cache": c.Dict("request_cache", s.Schema{
"memory_size_in_bytes": c.Int("memory_size_in_bytes"),
"evictions": c.Int("evictions"),
"hit_count": c.Int("hit_count"),
"miss_count": c.Int("miss_count"),
}),
}),
"os": c.Dict("os", s.Schema{
"cpu": c.Dict("cpu", s.Schema{
"load_average": c.Dict("load_average", s.Schema{
"1m": c.Float("1m", s.Optional),
"5m": c.Float("5m", s.Optional),
"15m": c.Float("15m", s.Optional),
}),
}),
"cgroup": c.Dict("cgroup", s.Schema{
"cpuacct": c.Dict("cpuacct", s.Schema{
"control_group": c.Str("control_group"),
"usage_nanos": c.Int("usage_nanos"),
}),
"cpu": c.Dict("cpu", s.Schema{
"control_group": c.Str("control_group"),
"cfs_period_micros": c.Int("cfs_period_micros"),
"cfs_quota_micros": c.Int("cfs_quota_micros"),
"stat": c.Dict("stat", s.Schema{
"number_of_elapsed_periods": c.Int("number_of_elapsed_periods"),
"number_of_times_throttled": c.Int("number_of_times_throttled"),
"time_throttled_nanos": c.Int("time_throttled_nanos"),
}),
}),
"memory": c.Dict("memory", s.Schema{
"control_group": c.Str("control_group"),
// The two following values are currently string. See https://github.com/elastic/elasticsearch/pull/26166
"limit_in_bytes": c.Str("limit_in_bytes"),
"usage_in_bytes": c.Str("usage_in_bytes"),
}),
}, c.DictOptional),
}),
"process": c.Dict("process", s.Schema{
"open_file_descriptors": c.Int("open_file_descriptors"),
"max_file_descriptors": c.Int("max_file_descriptors"),
"cpu": c.Dict("cpu", s.Schema{
"percent": c.Int("percent"),
}),
}),
"jvm": c.Dict("jvm", s.Schema{
"mem": c.Dict("mem", s.Schema{
"heap_used_in_bytes": c.Int("heap_used_in_bytes"),
"heap_used_percent": c.Int("heap_used_percent"),
"heap_max_in_bytes": c.Int("heap_max_in_bytes"),
}),
"gc": c.Dict("gc", s.Schema{
"collectors": c.Dict("collectors", s.Schema{
"young": c.Dict("young", s.Schema{
"collection_count": c.Int("collection_count"),
"collection_time_in_millis": c.Int("collection_time_in_millis"),
}),
"old": c.Dict("young", s.Schema{
"collection_count": c.Int("collection_count"),
"collection_time_in_millis": c.Int("collection_time_in_millis"),
}),
}),
}),
}),
"thread_pool": c.Dict("thread_pool", s.Schema{
"analyze": c.Dict("analyze", threadPoolStatsSchema),
"write": c.Dict("write", threadPoolStatsSchema),
"generic": c.Dict("generic", threadPoolStatsSchema),
"get": c.Dict("get", threadPoolStatsSchema),
"management": c.Dict("management", threadPoolStatsSchema),
"search": c.Dict("search", threadPoolStatsSchema),
"watcher": c.Dict("watcher", threadPoolStatsSchema),
}),
"fs": c.Dict("fs", s.Schema{
"total": c.Dict("total", s.Schema{
"total_in_bytes": c.Int("total_in_bytes"),
"free_in_bytes": c.Int("free_in_bytes"),
"available_in_bytes": c.Int("available_in_bytes"),
}),
}),
}
threadPoolStatsSchema = s.Schema{
"threads": c.Int("threads"),
"queue": c.Int("queue"),
"rejected": c.Int("rejected"),
}
)
func eventsMappingXPack(r mb.ReporterV2, m *MetricSet, content []byte) error {
nodesStruct := struct {
ClusterName string `json:"cluster_name"`
Nodes map[string]map[string]interface{} `json:"nodes"`
}{}
err := json.Unmarshal(content, &nodesStruct)
if err != nil {
return errors.Wrap(err, "failure parsing Elasticsearch Node Stats API response")
}
// Normally the nodeStruct should only contain one node. But if _local is removed
// from the path and Metricbeat is not installed on the same machine as the node
// it will provid the data for multiple nodes. This will mean the detection of the
// master node will not be accurate anymore as often in these cases a proxy is in front
// of ES and it's not know if the request will be routed to the same node as before.
for nodeID, node := range nodesStruct.Nodes {
clusterID, err := elasticsearch.GetClusterID(m.HTTP, m.HTTP.GetURI(), nodeID)
if err != nil {
logp.Err("could not fetch cluster id: %s", err)
continue
}
isMaster, err := elasticsearch.IsMaster(m.HTTP, m.HTTP.GetURI())
if err != nil {
logp.Err("error determining if connected Elasticsearch node is master: %s", err)
continue
}
event := mb.Event{}
// Build source_node object
sourceNode, _ := sourceNodeXpack.Apply(node)
sourceNode["uuid"] = nodeID
nodeData, err := schemaXpack.Apply(node)
if err != nil {
logp.Err("failure to apply node schema: %s", err)
continue
}
nodeData["node_master"] = isMaster
nodeData["node_id"] = nodeID
event.RootFields = common.MapStr{
"timestamp": time.Now(),
"cluster_uuid": clusterID,
"interval_ms": m.Module().Config().Period.Nanoseconds() / 1000 / 1000,
"type": "node_stats",
"source_node": sourceNode,
"node_stats": nodeData,
}
event.Index = elastic.MakeXPackMonitoringIndexName(elastic.Elasticsearch)
r.Event(event)
}
return nil
}