2015-12-06 22:33:47 +01:00
// 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 (
2016-03-29 16:19:47 +02:00
"flag"
2015-12-06 22:33:47 +01:00
"fmt"
2016-08-16 08:39:49 +02:00
"regexp"
2015-12-06 22:33:47 +01:00
"github.com/coreos/go-systemd/dbus"
"github.com/prometheus/client_golang/prometheus"
2016-08-16 08:39:49 +02:00
"github.com/prometheus/common/log"
)
var (
unitWhitelist = flag . String ( "collector.systemd.unit-whitelist" , ".+" , "Regexp of systemd units to whitelist. Units must both match whitelist and not match blacklist to be included." )
unitBlacklist = flag . String ( "collector.systemd.unit-blacklist" , "" , "Regexp of systemd units to blacklist. Units must both match whitelist and not match blacklist to be included." )
2015-12-06 22:33:47 +01:00
)
type systemdCollector struct {
2016-08-16 08:39:49 +02:00
unitDesc * prometheus . Desc
systemRunningDesc * prometheus . Desc
unitWhitelistPattern * regexp . Regexp
unitBlacklistPattern * regexp . Regexp
2015-12-06 22:33:47 +01:00
}
var unitStatesName = [ ] string { "active" , "activating" , "deactivating" , "inactive" , "failed" }
2016-03-29 16:19:47 +02:00
var (
systemdPrivate = flag . Bool (
"collector.systemd.private" ,
false ,
"Establish a private, direct connection to systemd without dbus." ,
)
)
2015-12-06 22:33:47 +01:00
func init ( ) {
Factories [ "systemd" ] = NewSystemdCollector
}
2017-02-28 17:44:53 +01:00
// NewSystemdCollector returns a new Collector exposing systemd statistics.
2015-12-06 22:33:47 +01:00
func NewSystemdCollector ( ) ( Collector , error ) {
2015-12-17 19:30:35 +01:00
const subsystem = "systemd"
2015-12-06 22:33:47 +01:00
unitDesc := prometheus . NewDesc (
2015-12-17 19:30:35 +01:00
prometheus . BuildFQName ( Namespace , subsystem , "unit_state" ) ,
2015-12-06 22:33:47 +01:00
"Systemd unit" , [ ] string { "name" , "state" } , nil ,
)
2015-12-17 19:30:35 +01:00
systemRunningDesc := prometheus . NewDesc (
prometheus . BuildFQName ( Namespace , subsystem , "system_running" ) ,
"Whether the system is operational (see 'systemctl is-system-running')" ,
nil , nil ,
)
2016-08-16 08:39:49 +02:00
unitWhitelistPattern := regexp . MustCompile ( fmt . Sprintf ( "^(?:%s)$" , * unitWhitelist ) )
unitBlacklistPattern := regexp . MustCompile ( fmt . Sprintf ( "^(?:%s)$" , * unitBlacklist ) )
2015-12-06 22:33:47 +01:00
return & systemdCollector {
2016-08-16 08:39:49 +02:00
unitDesc : unitDesc ,
systemRunningDesc : systemRunningDesc ,
unitWhitelistPattern : unitWhitelistPattern ,
unitBlacklistPattern : unitBlacklistPattern ,
2015-12-06 22:33:47 +01:00
} , nil
}
2017-02-28 19:47:20 +01:00
func ( c * systemdCollector ) Update ( ch chan <- prometheus . Metric ) error {
2015-12-06 22:33:47 +01:00
units , err := c . listUnits ( )
if err != nil {
return fmt . Errorf ( "couldn't get units states: %s" , err )
}
2015-12-17 19:30:35 +01:00
c . collectUnitStatusMetrics ( ch , units )
2015-12-06 22:33:47 +01:00
2015-12-17 19:30:35 +01:00
systemState , err := c . getSystemState ( )
if err != nil {
return fmt . Errorf ( "couldn't get system state: %s" , err )
}
c . collectSystemState ( ch , systemState )
2015-12-06 22:33:47 +01:00
return nil
}
2015-12-17 19:30:35 +01:00
func ( c * systemdCollector ) collectUnitStatusMetrics ( ch chan <- prometheus . Metric , units [ ] dbus . UnitStatus ) {
2015-12-06 22:33:47 +01:00
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 )
}
}
}
2015-12-17 19:30:35 +01:00
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 )
}
2016-03-29 16:19:47 +02:00
func ( c * systemdCollector ) newDbus ( ) ( * dbus . Conn , error ) {
if * systemdPrivate {
return dbus . NewSystemdConnection ( )
}
return dbus . New ( )
}
2015-12-06 22:33:47 +01:00
func ( c * systemdCollector ) listUnits ( ) ( [ ] dbus . UnitStatus , error ) {
2016-03-29 16:19:47 +02:00
conn , err := c . newDbus ( )
2015-12-06 22:33:47 +01:00
if err != nil {
return nil , fmt . Errorf ( "couldn't get dbus connection: %s" , err )
}
2016-08-16 08:39:49 +02:00
allUnits , err := conn . ListUnits ( )
2015-12-06 22:33:47 +01:00
conn . Close ( )
2016-08-16 08:39:49 +02:00
if err != nil {
return [ ] dbus . UnitStatus { } , err
}
units := filterUnits ( allUnits , c . unitWhitelistPattern , c . unitBlacklistPattern )
return units , nil
}
func filterUnits ( units [ ] dbus . UnitStatus , whitelistPattern , blacklistPattern * regexp . Regexp ) [ ] dbus . UnitStatus {
filtered := make ( [ ] dbus . UnitStatus , 0 , len ( units ) )
for _ , unit := range units {
if whitelistPattern . MatchString ( unit . Name ) && ! blacklistPattern . MatchString ( unit . Name ) {
filtered = append ( filtered , unit )
} else {
log . Debugf ( "Ignoring unit: %s" , unit . Name )
}
}
return filtered
2015-12-06 22:33:47 +01:00
}
2015-12-17 19:30:35 +01:00
func ( c * systemdCollector ) getSystemState ( ) ( state string , err error ) {
2016-03-29 16:19:47 +02:00
conn , err := c . newDbus ( )
2015-12-17 19:30:35 +01:00
if err != nil {
return "" , fmt . Errorf ( "couldn't get dbus connection: %s" , err )
}
state , err = conn . GetManagerProperty ( "SystemState" )
conn . Close ( )
return state , err
}