Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion internal/collector/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func (collector *Icinga2APICollector) Describe(ch chan<- *prometheus.Desc) {
}

func (collector *Icinga2APICollector) Collect(ch chan<- prometheus.Metric) {
result, err := collector.icingaClient.GetAPIMetrics()
result, err := collector.icingaClient.GetAPIListenerMetrics()

if err != nil {
collector.logger.Error("Could not retrieve ApiListener metrics", "error", err.Error())
Expand Down
2 changes: 1 addition & 1 deletion internal/collector/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ func TestIcinga2APICollector_Collect(t *testing.T) {
data, _ := os.ReadFile("testdata/api.json")
json.Unmarshal(data, &result)

client.SetAPIMetrics(result)
client.SetAPIListenerMetrics(result)

logger := slog.New(slog.NewTextHandler(io.Discard, nil))
collector := NewIcinga2APICollector(client, logger)
Expand Down
225 changes: 52 additions & 173 deletions internal/collector/cib.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,187 +202,66 @@ func (collector *Icinga2CIBCollector) Collect(ch chan<- prometheus.Metric) {

r := result.Results[0]

if v, ok := r.Status["uptime"]; ok {
ch <- prometheus.MustNewConstMetric(collector.uptime, prometheus.CounterValue, v)
}

if v, ok := r.Status["avg_execution_time"]; ok {
ch <- prometheus.MustNewConstMetric(collector.avg_execution_time, prometheus.GaugeValue, v)
}

if v, ok := r.Status["avg_latency"]; ok {
ch <- prometheus.MustNewConstMetric(collector.avg_latency, prometheus.GaugeValue, v)
}

if v, ok := r.Status["max_execution_time"]; ok {
ch <- prometheus.MustNewConstMetric(collector.max_execution_time, prometheus.GaugeValue, v)
}

if v, ok := r.Status["max_latency"]; ok {
ch <- prometheus.MustNewConstMetric(collector.max_latency, prometheus.GaugeValue, v)
}

if v, ok := r.Status["min_execution_time"]; ok {
ch <- prometheus.MustNewConstMetric(collector.min_execution_time, prometheus.GaugeValue, v)
}

if v, ok := r.Status["min_latency"]; ok {
ch <- prometheus.MustNewConstMetric(collector.min_latency, prometheus.GaugeValue, v)
}

if v, ok := r.Status["current_concurrent_checks"]; ok {
ch <- prometheus.MustNewConstMetric(collector.current_concurrent_checks, prometheus.GaugeValue, v)
}

if v, ok := r.Status["current_pending_callbacks"]; ok {
ch <- prometheus.MustNewConstMetric(collector.current_pending_callbacks, prometheus.GaugeValue, v)
}
// Icinga Statistics
emitMetric(ch, collector.uptime, prometheus.CounterValue, r.Status, "uptime")
emitMetric(ch, collector.avg_execution_time, prometheus.GaugeValue, r.Status, "avg_execution_time")
emitMetric(ch, collector.avg_latency, prometheus.GaugeValue, r.Status, "avg_latency")
emitMetric(ch, collector.max_execution_time, prometheus.GaugeValue, r.Status, "max_execution_time")
emitMetric(ch, collector.max_latency, prometheus.GaugeValue, r.Status, "max_latency")
emitMetric(ch, collector.min_execution_time, prometheus.GaugeValue, r.Status, "min_execution_time")
emitMetric(ch, collector.min_latency, prometheus.GaugeValue, r.Status, "min_latency")
emitMetric(ch, collector.current_concurrent_checks, prometheus.GaugeValue, r.Status, "current_concurrent_checks")
emitMetric(ch, collector.current_pending_callbacks, prometheus.GaugeValue, r.Status, "current_pending_callbacks")
emitMetric(ch, collector.remote_check_queue, prometheus.GaugeValue, r.Status, "remote_check_queue")

if v, ok := r.Status["remote_check_queue"]; ok {
ch <- prometheus.MustNewConstMetric(collector.remote_check_queue, prometheus.GaugeValue, v)
}
// Active Checks
if v, ok := r.Status["active_host_checks"]; ok {
ch <- prometheus.MustNewConstMetric(collector.active_host_checks, prometheus.GaugeValue, v)
}

if v, ok := r.Status["active_host_checks_15min"]; ok {
ch <- prometheus.MustNewConstMetric(collector.active_host_checks_15min, prometheus.GaugeValue, v)
}

if v, ok := r.Status["active_host_checks_1min"]; ok {
ch <- prometheus.MustNewConstMetric(collector.active_host_checks_1min, prometheus.GaugeValue, v)
}

if v, ok := r.Status["active_host_checks_5min"]; ok {
ch <- prometheus.MustNewConstMetric(collector.active_host_checks_5min, prometheus.GaugeValue, v)
}

if v, ok := r.Status["active_service_checks"]; ok {
ch <- prometheus.MustNewConstMetric(collector.active_service_checks, prometheus.GaugeValue, v)
}

if v, ok := r.Status["active_service_checks_15min"]; ok {
ch <- prometheus.MustNewConstMetric(collector.active_service_checks_15min, prometheus.GaugeValue, v)
}

if v, ok := r.Status["active_service_checks_1min"]; ok {
ch <- prometheus.MustNewConstMetric(collector.active_service_checks_1min, prometheus.GaugeValue, v)
}
emitMetric(ch, collector.active_host_checks, prometheus.GaugeValue, r.Status, "active_host_checks")
emitMetric(ch, collector.active_host_checks_15min, prometheus.GaugeValue, r.Status, "active_host_checks_15min")
emitMetric(ch, collector.active_host_checks_1min, prometheus.GaugeValue, r.Status, "active_host_checks_1min")
emitMetric(ch, collector.active_host_checks_5min, prometheus.GaugeValue, r.Status, "active_host_checks_5min")
emitMetric(ch, collector.active_service_checks, prometheus.GaugeValue, r.Status, "active_service_checks")
emitMetric(ch, collector.active_service_checks_15min, prometheus.GaugeValue, r.Status, "active_service_checks_15min")
emitMetric(ch, collector.active_service_checks_1min, prometheus.GaugeValue, r.Status, "active_service_checks_1min")
emitMetric(ch, collector.active_service_checks_5min, prometheus.GaugeValue, r.Status, "active_service_checks_5min")

if v, ok := r.Status["active_service_checks_5min"]; ok {
ch <- prometheus.MustNewConstMetric(collector.active_service_checks_5min, prometheus.GaugeValue, v)
}
// Passive Checks
if v, ok := r.Status["passive_host_checks"]; ok {
ch <- prometheus.MustNewConstMetric(collector.passive_host_checks, prometheus.GaugeValue, v)
}

if v, ok := r.Status["passive_host_checks_15min"]; ok {
ch <- prometheus.MustNewConstMetric(collector.passive_host_checks_15min, prometheus.GaugeValue, v)
}

if v, ok := r.Status["passive_host_checks_1min"]; ok {
ch <- prometheus.MustNewConstMetric(collector.passive_host_checks_1min, prometheus.GaugeValue, v)
}

if v, ok := r.Status["passive_host_checks_5min"]; ok {
ch <- prometheus.MustNewConstMetric(collector.passive_host_checks_5min, prometheus.GaugeValue, v)
}

if v, ok := r.Status["passive_service_checks"]; ok {
ch <- prometheus.MustNewConstMetric(collector.passive_service_checks, prometheus.GaugeValue, v)
}
emitMetric(ch, collector.passive_host_checks, prometheus.GaugeValue, r.Status, "passive_host_checks")
emitMetric(ch, collector.passive_host_checks_15min, prometheus.GaugeValue, r.Status, "passive_host_checks_15min")
emitMetric(ch, collector.passive_host_checks_1min, prometheus.GaugeValue, r.Status, "passive_host_checks_1min")
emitMetric(ch, collector.passive_host_checks_5min, prometheus.GaugeValue, r.Status, "passive_host_checks_5min")
emitMetric(ch, collector.passive_service_checks, prometheus.GaugeValue, r.Status, "passive_service_checks")
emitMetric(ch, collector.passive_service_checks_15min, prometheus.GaugeValue, r.Status, "passive_service_checks_15min")
emitMetric(ch, collector.passive_service_checks_1min, prometheus.GaugeValue, r.Status, "passive_service_checks_1min")
emitMetric(ch, collector.passive_service_checks_5min, prometheus.GaugeValue, r.Status, "passive_service_checks_5min")

if v, ok := r.Status["passive_service_checks_15min"]; ok {
ch <- prometheus.MustNewConstMetric(collector.passive_service_checks_15min, prometheus.GaugeValue, v)
}

if v, ok := r.Status["passive_service_checks_1min"]; ok {
ch <- prometheus.MustNewConstMetric(collector.passive_service_checks_1min, prometheus.GaugeValue, v)
}

if v, ok := r.Status["passive_service_checks_5min"]; ok {
ch <- prometheus.MustNewConstMetric(collector.passive_service_checks_5min, prometheus.GaugeValue, v)
}
// Hosts
if v, ok := r.Status["num_hosts_up"]; ok {
ch <- prometheus.MustNewConstMetric(collector.num_hosts_up, prometheus.GaugeValue, v)
}
emitMetric(ch, collector.num_hosts_up, prometheus.GaugeValue, r.Status, "num_hosts_up")
emitMetric(ch, collector.num_hosts_down, prometheus.GaugeValue, r.Status, "num_hosts_down")
emitMetric(ch, collector.num_hosts_acknowledged, prometheus.GaugeValue, r.Status, "num_hosts_acknowledged")
emitMetric(ch, collector.num_hosts_flapping, prometheus.GaugeValue, r.Status, "num_hosts_flapping")
emitMetric(ch, collector.num_hosts_handled, prometheus.GaugeValue, r.Status, "num_hosts_handled")
emitMetric(ch, collector.num_hosts_in_downtime, prometheus.GaugeValue, r.Status, "num_hosts_in_downtime")
emitMetric(ch, collector.num_hosts_pending, prometheus.GaugeValue, r.Status, "num_hosts_pending")
emitMetric(ch, collector.num_hosts_problem, prometheus.GaugeValue, r.Status, "num_hosts_problem")
emitMetric(ch, collector.num_hosts_unreachable, prometheus.GaugeValue, r.Status, "num_hosts_unreachable")

if v, ok := r.Status["num_hosts_down"]; ok {
ch <- prometheus.MustNewConstMetric(collector.num_hosts_down, prometheus.GaugeValue, v)
}

if v, ok := r.Status["num_hosts_acknowledged"]; ok {
ch <- prometheus.MustNewConstMetric(collector.num_hosts_acknowledged, prometheus.GaugeValue, v)
}

if v, ok := r.Status["num_hosts_flapping"]; ok {
ch <- prometheus.MustNewConstMetric(collector.num_hosts_flapping, prometheus.GaugeValue, v)
}

if v, ok := r.Status["num_hosts_handled"]; ok {
ch <- prometheus.MustNewConstMetric(collector.num_hosts_handled, prometheus.GaugeValue, v)
}

if v, ok := r.Status["num_hosts_in_downtime"]; ok {
ch <- prometheus.MustNewConstMetric(collector.num_hosts_in_downtime, prometheus.GaugeValue, v)
}

if v, ok := r.Status["num_hosts_pending"]; ok {
ch <- prometheus.MustNewConstMetric(collector.num_hosts_pending, prometheus.GaugeValue, v)
}

if v, ok := r.Status["num_hosts_problem"]; ok {
ch <- prometheus.MustNewConstMetric(collector.num_hosts_problem, prometheus.GaugeValue, v)
}

if v, ok := r.Status["num_hosts_unreachable"]; ok {
ch <- prometheus.MustNewConstMetric(collector.num_hosts_unreachable, prometheus.GaugeValue, v)
}
// Services
if v, ok := r.Status["num_services_ok"]; ok {
ch <- prometheus.MustNewConstMetric(collector.num_services_ok, prometheus.GaugeValue, v)
}

if v, ok := r.Status["num_services_critical"]; ok {
ch <- prometheus.MustNewConstMetric(collector.num_services_critical, prometheus.GaugeValue, v)
}

if v, ok := r.Status["num_services_acknowledged"]; ok {
ch <- prometheus.MustNewConstMetric(collector.num_services_acknowledged, prometheus.GaugeValue, v)
}

if v, ok := r.Status["num_services_flapping"]; ok {
ch <- prometheus.MustNewConstMetric(collector.num_services_flapping, prometheus.GaugeValue, v)
}

if v, ok := r.Status["num_services_handled"]; ok {
ch <- prometheus.MustNewConstMetric(collector.num_services_handled, prometheus.GaugeValue, v)
}

if v, ok := r.Status["num_services_in_downtime"]; ok {
ch <- prometheus.MustNewConstMetric(collector.num_services_in_downtime, prometheus.GaugeValue, v)
}

if v, ok := r.Status["num_services_pending"]; ok {
ch <- prometheus.MustNewConstMetric(collector.num_services_pending, prometheus.GaugeValue, v)
}

if v, ok := r.Status["num_services_problem"]; ok {
ch <- prometheus.MustNewConstMetric(collector.num_services_problem, prometheus.GaugeValue, v)
}

if v, ok := r.Status["num_services_unknown"]; ok {
ch <- prometheus.MustNewConstMetric(collector.num_services_unknown, prometheus.GaugeValue, v)
}

if v, ok := r.Status["num_services_unreachable"]; ok {
ch <- prometheus.MustNewConstMetric(collector.num_services_unreachable, prometheus.GaugeValue, v)
}
emitMetric(ch, collector.num_services_ok, prometheus.GaugeValue, r.Status, "num_services_ok")
emitMetric(ch, collector.num_services_critical, prometheus.GaugeValue, r.Status, "num_services_critical")
emitMetric(ch, collector.num_services_acknowledged, prometheus.GaugeValue, r.Status, "num_services_acknowledged")
emitMetric(ch, collector.num_services_flapping, prometheus.GaugeValue, r.Status, "num_services_flapping")
emitMetric(ch, collector.num_services_handled, prometheus.GaugeValue, r.Status, "num_services_handled")
emitMetric(ch, collector.num_services_in_downtime, prometheus.GaugeValue, r.Status, "num_services_in_downtime")
emitMetric(ch, collector.num_services_pending, prometheus.GaugeValue, r.Status, "num_services_pending")
emitMetric(ch, collector.num_services_problem, prometheus.GaugeValue, r.Status, "num_services_problem")
emitMetric(ch, collector.num_services_unknown, prometheus.GaugeValue, r.Status, "num_services_unknown")
emitMetric(ch, collector.num_services_unreachable, prometheus.GaugeValue, r.Status, "num_services_unreachable")
emitMetric(ch, collector.num_services_warning, prometheus.GaugeValue, r.Status, "num_services_warning")
}

if v, ok := r.Status["num_services_warning"]; ok {
ch <- prometheus.MustNewConstMetric(collector.num_services_warning, prometheus.GaugeValue, v)
// emitMetric checks if the given key exists in the status map and emits the metric if so.
func emitMetric(ch chan<- prometheus.Metric, desc *prometheus.Desc, metricType prometheus.ValueType, status map[string]float64, key string) {
if v, ok := status[key]; ok {
ch <- prometheus.MustNewConstMetric(desc, metricType, v)
}
}
4 changes: 2 additions & 2 deletions internal/collector/testing.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ func (m *MockIcingaClient) GetCIBMetrics() (icinga.CIBResult, error) {
return m.cib, nil
}

func (m *MockIcingaClient) SetAPIMetrics(api icinga.APIResult) {
func (m *MockIcingaClient) SetAPIListenerMetrics(api icinga.APIResult) {
m.api = api
}

func (m *MockIcingaClient) GetAPIMetrics() (icinga.APIResult, error) {
func (m *MockIcingaClient) GetAPIListenerMetrics() (icinga.APIResult, error) {
return m.api, nil
}

Expand Down
32 changes: 24 additions & 8 deletions internal/icinga/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@ import (
"time"
)

const (
defaultDialTimeout = 10 * time.Second
defaultKeepAlive = 10 * time.Second
defaultTLSHandshake = 10 * time.Second
defaultIdleConnTimeout = 90 * time.Second
defaultMaxIdleConns = 100
defaultMaxIdleConnsPerHost = 10
)

const (
EndpointApiListener = "/status/ApiListener"
EndpointApplication = "/status/IcingaApplication"
Expand Down Expand Up @@ -54,11 +63,12 @@ type Client struct {
}

// IcingaClient is an interface that we use to simplify testing
// Note, the methods use a context internally.
type IcingaClient interface {
GetPerfdataMetrics(endpoint string) (PerfdataResult, error)
GetCIBMetrics() (CIBResult, error)
GetApplicationMetrics() (ApplicationResult, error)
GetAPIMetrics() (APIResult, error)
GetAPIListenerMetrics() (APIResult, error)
GetCheckerComponentMetrics() (CheckerComponentResult, error)
}

Expand All @@ -79,14 +89,14 @@ func NewClient(c Config) (*Client, error) {
var rt http.RoundTripper = &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 10 * time.Second,
KeepAlive: 10 * time.Second,
Timeout: defaultDialTimeout,
KeepAlive: defaultKeepAlive,
}).DialContext,
TLSHandshakeTimeout: 10 * time.Second,
TLSHandshakeTimeout: defaultTLSHandshake,
TLSClientConfig: tlsConfig,
IdleConnTimeout: 90 * time.Second,
MaxIdleConns: 100,
MaxIdleConnsPerHost: 10,
IdleConnTimeout: defaultIdleConnTimeout,
MaxIdleConns: defaultMaxIdleConns,
MaxIdleConnsPerHost: defaultMaxIdleConnsPerHost,
}

// Using a BasicAuth for authentication
Expand All @@ -109,6 +119,7 @@ func NewClient(c Config) (*Client, error) {
}

// GetPerfdataMetrics returns the perfdata from a given status API endpoint
// There is some duplication here, but that is fine for now
func (c *Client) GetPerfdataMetrics(endpoint string) (PerfdataResult, error) {
var result PerfdataResult

Expand All @@ -131,6 +142,7 @@ func (c *Client) GetPerfdataMetrics(endpoint string) (PerfdataResult, error) {
return result, nil
}

// GetCIBMetrics returns the Common Information Base metrics
func (c *Client) GetCIBMetrics() (CIBResult, error) {
var result CIBResult

Expand All @@ -149,6 +161,7 @@ func (c *Client) GetCIBMetrics() (CIBResult, error) {
return result, nil
}

// GetApplicationMetrics returns the base application metrics
func (c *Client) GetApplicationMetrics() (ApplicationResult, error) {
var result ApplicationResult

Expand All @@ -167,7 +180,8 @@ func (c *Client) GetApplicationMetrics() (ApplicationResult, error) {
return result, nil
}

func (c *Client) GetAPIMetrics() (APIResult, error) {
// GetAPIListenerMetrics returns the APIListener metrics
func (c *Client) GetAPIListenerMetrics() (APIResult, error) {
var result APIResult

body, errBody := c.fetchJSON(EndpointApiListener)
Expand All @@ -185,6 +199,7 @@ func (c *Client) GetAPIMetrics() (APIResult, error) {
return result, nil
}

// GetCheckerComponentMetrics returns the CheckerComponent metrics
func (c *Client) GetCheckerComponentMetrics() (CheckerComponentResult, error) {
var result CheckerComponentResult

Expand All @@ -203,6 +218,7 @@ func (c *Client) GetCheckerComponentMetrics() (CheckerComponentResult, error) {
return result, nil
}

// fetchJSON calls the given endpoint and returns the JSON result
func (c *Client) fetchJSON(endpoint string) ([]byte, error) {
// Lookup data in the cache we go out and bother the Icinga API
if elem, ok := c.cache.Get(endpoint); ok {
Expand Down