diff --git a/VERSION b/VERSION index 17e51c3..d917d3e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.1 +0.1.2 diff --git a/collector/api_base.go b/collector/api_base.go new file mode 100644 index 0000000..4d9e1ca --- /dev/null +++ b/collector/api_base.go @@ -0,0 +1,48 @@ +package collector + +import ( + "encoding/json" + "github.com/prometheus/common/log" + "net/http" +) + +// HTTPHandler type +type HTTPHandler struct { + Endpoint string +} + +// Get method for HTTPHandler +func (h *HTTPHandler) Get() (http.Response, error) { + response, err := http.Get(h.Endpoint) + if err != nil { + return http.Response{}, err + } + + return *response, nil +} + +// HTTPHandlerInterface interface +type HTTPHandlerInterface interface { + Get() (http.Response, error) +} + +func getMetrics(h HTTPHandlerInterface, target interface{}) error { + response, err := h.Get() + if err != nil { + log.Errorf("Cannot retrieve metrics: %s", err) + return nil + } + + defer func() { + err = response.Body.Close() + if err != nil { + log.Errorf("Cannot close response body: %v", err) + } + }() + + if err := json.NewDecoder(response.Body).Decode(target); err != nil { + log.Errorf("Cannot parse Logstash response json: %s", err) + } + + return nil +} diff --git a/collector/nodeinfo_api.go b/collector/nodeinfo_api.go new file mode 100644 index 0000000..0929e59 --- /dev/null +++ b/collector/nodeinfo_api.go @@ -0,0 +1,51 @@ +package collector + +// NodeInfoResponse type +type NodeInfoResponse struct { + Host string `json:"host"` + Version string `json:"version"` + HTTPAddress string `json:"http_address"` + ID string `json:"id"` + Name string `json:"name"` + Pipeline struct { + Workers int `json:"workers"` + BatchSize int `json:"batch_size"` + BatchDelay int `json:"batch_delay"` + ConfigReloadAutomatic bool `json:"config_reload_automatic"` + ConfigReloadInterval int `json:"config_reload_interval"` + } `json:"pipeline"` + Os struct { + Name string `json:"name"` + Arch string `json:"arch"` + Version string `json:"version"` + AvailableProcessors int `json:"available_processors"` + } `json:"os"` + Jvm struct { + Pid int `json:"pid"` + Version string `json:"version"` + VMName string `json:"vm_name"` + VMVersion string `json:"vm_version"` + VMVendor string `json:"vm_vendor"` + StartTimeInMillis int64 `json:"start_time_in_millis"` + Mem struct { + HeapInitInBytes int `json:"heap_init_in_bytes"` + HeapMaxInBytes int `json:"heap_max_in_bytes"` + NonHeapInitInBytes int `json:"non_heap_init_in_bytes"` + NonHeapMaxInBytes int `json:"non_heap_max_in_bytes"` + } `json:"mem"` + GcCollectors []string `json:"gc_collectors"` + } `json:"jvm"` +} + +// NodeInfo function +func NodeInfo(endpoint string) (NodeInfoResponse, error) { + var response NodeInfoResponse + + handler := &HTTPHandler{ + Endpoint: endpoint + "/_node", + } + + err := getMetrics(handler, &response) + + return response, err +} diff --git a/collector/nodeinfo_collector.go b/collector/nodeinfo_collector.go new file mode 100644 index 0000000..27cbdb9 --- /dev/null +++ b/collector/nodeinfo_collector.go @@ -0,0 +1,90 @@ +package collector + +import ( + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/common/log" + "strconv" +) + +// NodeInfoCollector type +type NodeInfoCollector struct { + endpoint string + + NodeInfos *prometheus.Desc + OsInfos *prometheus.Desc + JvmInfos *prometheus.Desc +} + +// NewNodeInfoCollector function +func NewNodeInfoCollector(logstashEndpoint string) (Collector, error) { + const subsystem = "info" + + return &NodeInfoCollector{ + endpoint: logstashEndpoint, + + NodeInfos: prometheus.NewDesc( + prometheus.BuildFQName(Namespace, subsystem, "node"), + "A metric with a constant '1' value labeled by Logstash version.", + []string{"version"}, + nil, + ), + + OsInfos: prometheus.NewDesc( + prometheus.BuildFQName(Namespace, subsystem, "os"), + "A metric with a constant '1' value labeled by name, arch, version and available_processors to the OS running Logstash.", + []string{"name", "arch", "version", "available_processors"}, + nil, + ), + + JvmInfos: prometheus.NewDesc( + prometheus.BuildFQName(Namespace, subsystem, "jvm"), + "A metric with a constant '1' value labeled by name, version and vendor of the JVM running Logstash.", + []string{"name", "version", "vendor"}, + nil, + ), + }, nil +} + +// Collect function implements nodestats_collector collector +func (c *NodeInfoCollector) Collect(ch chan<- prometheus.Metric) error { + if desc, err := c.collect(ch); err != nil { + log.Error("Failed collecting info metrics", desc, err) + return err + } + return nil +} + +func (c *NodeInfoCollector) collect(ch chan<- prometheus.Metric) (*prometheus.Desc, error) { + stats, err := NodeInfo(c.endpoint) + if err != nil { + return nil, err + } + + ch <- prometheus.MustNewConstMetric( + c.NodeInfos, + prometheus.CounterValue, + float64(1), + stats.Version, + ) + + ch <- prometheus.MustNewConstMetric( + c.OsInfos, + prometheus.CounterValue, + float64(1), + stats.Os.Name, + stats.Os.Arch, + stats.Os.Version, + strconv.Itoa(stats.Os.AvailableProcessors), + ) + + ch <- prometheus.MustNewConstMetric( + c.JvmInfos, + prometheus.CounterValue, + float64(1), + stats.Jvm.VMName, + stats.Jvm.VMVersion, + stats.Jvm.VMVendor, + ) + + return nil, nil +} diff --git a/collector/nodestats_api.go b/collector/nodestats_api.go index 11a748e..8bd3dc5 100644 --- a/collector/nodestats_api.go +++ b/collector/nodestats_api.go @@ -1,11 +1,5 @@ package collector -import ( - "encoding/json" - "github.com/prometheus/common/log" - "net/http" -) - // Pipeline type type Pipeline struct { Events struct { @@ -143,56 +137,15 @@ type NodeStatsResponse struct { Pipelines map[string]Pipeline `json:"pipelines"` // Logstash >=6 } -// HTTPHandler type -type HTTPHandler struct { - Endpoint string -} - -// Get method for HTTPHandler -func (h *HTTPHandler) Get() (http.Response, error) { - response, err := http.Get(h.Endpoint + "/_node/stats") - if err != nil { - return http.Response{}, err - } - - return *response, nil -} - -// HTTPHandlerInterface interface -type HTTPHandlerInterface interface { - Get() (http.Response, error) -} - -func getNodeStats(h HTTPHandlerInterface, target interface{}) error { - response, err := h.Get() - if err != nil { - log.Errorf("Cannot retrieve metrics: %s", err) - return nil - } - - defer func() { - err = response.Body.Close() - if err != nil { - log.Errorf("Cannot close response body: %v", err) - } - }() - - if err := json.NewDecoder(response.Body).Decode(target); err != nil { - log.Errorf("Cannot parse Logstash response json: %s", err) - } - - return nil -} - // NodeStats function func NodeStats(endpoint string) (NodeStatsResponse, error) { var response NodeStatsResponse handler := &HTTPHandler{ - Endpoint: endpoint, + Endpoint: endpoint + "/_node/stats", } - err := getNodeStats(handler, &response) + err := getMetrics(handler, &response) return response, err } diff --git a/collector/nodestats_collector.go b/collector/nodestats_collector.go index 8963bd0..5bade5f 100644 --- a/collector/nodestats_collector.go +++ b/collector/nodestats_collector.go @@ -655,7 +655,6 @@ func (c *NodeStatsCollector) collect(ch chan<- prometheus.Metric) (*prometheus.D ) } - log.Errorf("%v", pipeline.DeadLetterQueue.QueueSizeInBytes) if pipeline.DeadLetterQueue.QueueSizeInBytes != 0 { ch <- prometheus.MustNewConstMetric( c.PipelineDeadLetterQueueSizeInBytes, diff --git a/collector/nodestats_collector_test.go b/collector/nodestats_collector_test.go index ee71227..504c235 100644 --- a/collector/nodestats_collector_test.go +++ b/collector/nodestats_collector_test.go @@ -278,7 +278,7 @@ func TestPipelineNoQueueStats(t *testing.T) { var response NodeStatsResponse m := &MockHTTPHandler{ReturnJSON: noQueueJSON} - getNodeStats(m, &response) + getMetrics(m, &response) if response.Pipeline.Queue.Capacity.MaxUnreadEvents == 12 { t.Fail() @@ -289,7 +289,7 @@ func TestPipelineQueueStats(t *testing.T) { var response NodeStatsResponse m := &MockHTTPHandler{ReturnJSON: queueJSON} - getNodeStats(m, &response) + getMetrics(m, &response) if response.Pipeline.Queue.Capacity.MaxUnreadEvents != 12 { t.Fail() @@ -300,7 +300,7 @@ func TestPipelineDLQueueStats(t *testing.T) { var response NodeStatsResponse m := &MockHTTPHandler{ReturnJSON: dlQueueJSON} - getNodeStats(m, &response) + getMetrics(m, &response) if response.Pipeline.DeadLetterQueue.QueueSizeInBytes != 1337 { t.Fail() diff --git a/logstash_exporter.go b/logstash_exporter.go index fc4e884..18235e6 100644 --- a/logstash_exporter.go +++ b/logstash_exporter.go @@ -36,9 +36,15 @@ func NewLogstashCollector(logstashEndpoint string) (*LogstashCollector, error) { log.Fatalf("Cannot register a new collector: %v", err) } + nodeInfoCollector, err := collector.NewNodeInfoCollector(logstashEndpoint) + if err != nil { + log.Fatalf("Cannot register a new collector: %v", err) + } + return &LogstashCollector{ collectors: map[string]collector.Collector{ "node": nodeStatsCollector, + "info": nodeInfoCollector, }, }, nil }