Skip to content

Commit

Permalink
Merge pull request #12 from BonnierNews/issue-11
Browse files Browse the repository at this point in the history
Expose Logstash/OS/JVM info as labels on a static metric
  • Loading branch information
christoe authored Dec 22, 2017
2 parents dfaef24 + 9066f58 commit d039196
Show file tree
Hide file tree
Showing 8 changed files with 201 additions and 54 deletions.
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.1.1
0.1.2
48 changes: 48 additions & 0 deletions collector/api_base.go
Original file line number Diff line number Diff line change
@@ -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
}
51 changes: 51 additions & 0 deletions collector/nodeinfo_api.go
Original file line number Diff line number Diff line change
@@ -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
}
90 changes: 90 additions & 0 deletions collector/nodeinfo_collector.go
Original file line number Diff line number Diff line change
@@ -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
}
51 changes: 2 additions & 49 deletions collector/nodestats_api.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
package collector

import (
"encoding/json"
"github.com/prometheus/common/log"
"net/http"
)

// Pipeline type
type Pipeline struct {
Events struct {
Expand Down Expand Up @@ -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
}
1 change: 0 additions & 1 deletion collector/nodestats_collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
6 changes: 3 additions & 3 deletions collector/nodestats_collector_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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()
Expand All @@ -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()
Expand Down
6 changes: 6 additions & 0 deletions logstash_exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down

0 comments on commit d039196

Please sign in to comment.