mirror of
				https://github.com/prometheus/node_exporter.git
				synced 2025-08-20 18:33:52 -07:00 
			
		
		
		
	Merge pull request #174 from audebert/systemd
collector: add systemd services status
This commit is contained in:
		
						commit
						613f531280
					
				| 
						 | 
				
			
			@ -50,6 +50,7 @@ megacli | Exposes RAID statistics from MegaCLI.
 | 
			
		|||
ntp | Exposes time drift from an NTP server.
 | 
			
		||||
runit | Exposes service status from [runit](http://smarden.org/runit/).
 | 
			
		||||
supervisord | Exposes service status from [supervisord](http://supervisord.org/).
 | 
			
		||||
systemd | Exposes service and system status from [systemd](http://www.freedesktop.org/wiki/Software/systemd/).
 | 
			
		||||
tcpstat | Exposes TCP connection status information from `/proc/net/tcp` and `/proc/net/tcp6`. (Warning: the current version has potential performance issues in high load situations.)
 | 
			
		||||
 | 
			
		||||
## Textfile Collector
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										113
									
								
								collector/systemd_linux.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								collector/systemd_linux.go
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,113 @@
 | 
			
		|||
// Copyright 2015 The Prometheus Authors
 | 
			
		||||
// Licensed 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.
 | 
			
		||||
 | 
			
		||||
// +build !nosystemd
 | 
			
		||||
 | 
			
		||||
package collector
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"github.com/coreos/go-systemd/dbus"
 | 
			
		||||
	"github.com/prometheus/client_golang/prometheus"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type systemdCollector struct {
 | 
			
		||||
	unitDesc          *prometheus.Desc
 | 
			
		||||
	systemRunningDesc *prometheus.Desc
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var unitStatesName = []string{"active", "activating", "deactivating", "inactive", "failed"}
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	Factories["systemd"] = NewSystemdCollector
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Takes a prometheus registry and returns a new Collector exposing
 | 
			
		||||
// systemd statistics.
 | 
			
		||||
func NewSystemdCollector() (Collector, error) {
 | 
			
		||||
	const subsystem = "systemd"
 | 
			
		||||
 | 
			
		||||
	unitDesc := prometheus.NewDesc(
 | 
			
		||||
		prometheus.BuildFQName(Namespace, subsystem, "unit_state"),
 | 
			
		||||
		"Systemd unit", []string{"name", "state"}, nil,
 | 
			
		||||
	)
 | 
			
		||||
	systemRunningDesc := prometheus.NewDesc(
 | 
			
		||||
		prometheus.BuildFQName(Namespace, subsystem, "system_running"),
 | 
			
		||||
		"Whether the system is operational (see 'systemctl is-system-running')",
 | 
			
		||||
		nil, nil,
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	return &systemdCollector{
 | 
			
		||||
		unitDesc:          unitDesc,
 | 
			
		||||
		systemRunningDesc: systemRunningDesc,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *systemdCollector) Update(ch chan<- prometheus.Metric) (err error) {
 | 
			
		||||
	units, err := c.listUnits()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("couldn't get units states: %s", err)
 | 
			
		||||
	}
 | 
			
		||||
	c.collectUnitStatusMetrics(ch, units)
 | 
			
		||||
 | 
			
		||||
	systemState, err := c.getSystemState()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("couldn't get system state: %s", err)
 | 
			
		||||
	}
 | 
			
		||||
	c.collectSystemState(ch, systemState)
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *systemdCollector) collectUnitStatusMetrics(ch chan<- prometheus.Metric, units []dbus.UnitStatus) {
 | 
			
		||||
	for _, unit := range units {
 | 
			
		||||
		for _, stateName := range unitStatesName {
 | 
			
		||||
			isActive := 0.0
 | 
			
		||||
			if stateName == unit.ActiveState {
 | 
			
		||||
				isActive = 1.0
 | 
			
		||||
			}
 | 
			
		||||
			ch <- prometheus.MustNewConstMetric(
 | 
			
		||||
				c.unitDesc, prometheus.GaugeValue, isActive,
 | 
			
		||||
				unit.Name, stateName)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *systemdCollector) collectSystemState(ch chan<- prometheus.Metric, systemState string) {
 | 
			
		||||
	isSystemRunning := 0.0
 | 
			
		||||
	if systemState == `"running"` {
 | 
			
		||||
		isSystemRunning = 1.0
 | 
			
		||||
	}
 | 
			
		||||
	ch <- prometheus.MustNewConstMetric(c.systemRunningDesc, prometheus.GaugeValue, isSystemRunning)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *systemdCollector) listUnits() ([]dbus.UnitStatus, error) {
 | 
			
		||||
	conn, err := dbus.New()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("couldn't get dbus connection: %s", err)
 | 
			
		||||
	}
 | 
			
		||||
	units, err := conn.ListUnits()
 | 
			
		||||
	conn.Close()
 | 
			
		||||
	return units, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *systemdCollector) getSystemState() (state string, err error) {
 | 
			
		||||
	conn, err := dbus.New()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", fmt.Errorf("couldn't get dbus connection: %s", err)
 | 
			
		||||
	}
 | 
			
		||||
	state, err = conn.GetManagerProperty("SystemState")
 | 
			
		||||
	conn.Close()
 | 
			
		||||
	return state, err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										74
									
								
								collector/systemd_linux_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								collector/systemd_linux_test.go
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,74 @@
 | 
			
		|||
// Copyright 2015 The Prometheus Authors
 | 
			
		||||
// Licensed 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 collector
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/coreos/go-systemd/dbus"
 | 
			
		||||
	"github.com/prometheus/client_golang/prometheus"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Creates mock UnitLists
 | 
			
		||||
func getUnitListFixtures() [][]dbus.UnitStatus {
 | 
			
		||||
	fixture1 := []dbus.UnitStatus{
 | 
			
		||||
		dbus.UnitStatus{
 | 
			
		||||
			Name:        "foo",
 | 
			
		||||
			Description: "foo desc",
 | 
			
		||||
			LoadState:   "loaded",
 | 
			
		||||
			ActiveState: "active",
 | 
			
		||||
			SubState:    "running",
 | 
			
		||||
			Followed:    "",
 | 
			
		||||
			Path:        "/org/freedesktop/systemd1/unit/foo",
 | 
			
		||||
			JobId:       0,
 | 
			
		||||
			JobType:     "",
 | 
			
		||||
			JobPath:     "/",
 | 
			
		||||
		},
 | 
			
		||||
		dbus.UnitStatus{
 | 
			
		||||
			Name:        "bar",
 | 
			
		||||
			Description: "bar desc",
 | 
			
		||||
			LoadState:   "not-found",
 | 
			
		||||
			ActiveState: "inactive",
 | 
			
		||||
			SubState:    "dead",
 | 
			
		||||
			Followed:    "",
 | 
			
		||||
			Path:        "/org/freedesktop/systemd1/unit/bar",
 | 
			
		||||
			JobId:       0,
 | 
			
		||||
			JobType:     "",
 | 
			
		||||
			JobPath:     "/",
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fixture2 := []dbus.UnitStatus{}
 | 
			
		||||
 | 
			
		||||
	return [][]dbus.UnitStatus{fixture1, fixture2}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSystemdCollectorDoesntCrash(t *testing.T) {
 | 
			
		||||
	c, err := NewSystemdCollector()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	sink := make(chan prometheus.Metric)
 | 
			
		||||
	go func() {
 | 
			
		||||
		for {
 | 
			
		||||
			<-sink
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	fixtures := getUnitListFixtures()
 | 
			
		||||
	collector := (c).(*systemdCollector)
 | 
			
		||||
	for _, units := range fixtures {
 | 
			
		||||
		collector.collectUnitStatusMetrics(sink, units)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in a new issue