2015-12-06 13:33:47 -08: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.
2021-10-03 04:35:24 -07:00
//go:build !nosystemd
2015-12-06 13:33:47 -08:00
// +build !nosystemd
package collector
import (
2022-05-04 13:14:18 -07:00
"context"
2020-06-11 23:24:29 -07:00
"errors"
2015-12-06 13:33:47 -08:00
"fmt"
2019-01-29 14:54:47 -08:00
"math"
2016-08-15 23:39:49 -07:00
"regexp"
2019-09-04 07:27:25 -07:00
"strconv"
2018-01-31 07:06:58 -08:00
"strings"
2019-02-11 14:27:21 -08:00
"sync"
"time"
2015-12-06 13:33:47 -08:00
2023-03-07 00:25:05 -08:00
"github.com/alecthomas/kingpin/v2"
2022-05-04 13:14:18 -07:00
"github.com/coreos/go-systemd/v22/dbus"
2020-11-14 02:53:51 -08:00
"github.com/go-kit/log"
"github.com/go-kit/log/level"
2015-12-06 13:33:47 -08:00
"github.com/prometheus/client_golang/prometheus"
2016-08-15 23:39:49 -07:00
)
2019-09-04 07:27:25 -07:00
const (
// minSystemdVersionSystemState is the minimum SystemD version for availability of
// the 'SystemState' manager property and the timer property 'LastTriggerUSec'
// https://github.com/prometheus/node_exporter/issues/291
minSystemdVersionSystemState = 212
)
2016-08-15 23:39:49 -07:00
var (
2023-07-10 03:25:18 -07:00
systemdUnitIncludeSet bool
systemdUnitInclude = kingpin . Flag ( "collector.systemd.unit-include" , "Regexp of systemd units to include. Units must both match include and not match exclude to be included." ) . Default ( ".+" ) . PreAction ( func ( c * kingpin . ParseContext ) error {
systemdUnitIncludeSet = true
2021-03-15 06:35:03 -07:00
return nil
} ) . String ( )
2023-07-10 03:25:18 -07:00
oldSystemdUnitInclude = kingpin . Flag ( "collector.systemd.unit-whitelist" , "DEPRECATED: Use --collector.systemd.unit-include" ) . Hidden ( ) . String ( )
systemdUnitExcludeSet bool
systemdUnitExclude = kingpin . Flag ( "collector.systemd.unit-exclude" , "Regexp of systemd units to exclude. Units must both match include and not match exclude to be included." ) . Default ( ".+\\.(automount|device|mount|scope|slice)" ) . PreAction ( func ( c * kingpin . ParseContext ) error {
systemdUnitExcludeSet = true
2021-03-15 06:35:03 -07:00
return nil
} ) . String ( )
2023-07-10 03:25:18 -07:00
oldSystemdUnitExclude = kingpin . Flag ( "collector.systemd.unit-blacklist" , "DEPRECATED: Use collector.systemd.unit-exclude" ) . Hidden ( ) . String ( )
2020-02-15 02:39:45 -08:00
systemdPrivate = kingpin . Flag ( "collector.systemd.private" , "Establish a private, direct connection to systemd without dbus (Strongly discouraged since it requires root. For testing purposes only)." ) . Hidden ( ) . Bool ( )
2019-02-11 14:27:21 -08:00
enableTaskMetrics = kingpin . Flag ( "collector.systemd.enable-task-metrics" , "Enables service unit tasks metrics unit_tasks_current and unit_tasks_max" ) . Bool ( )
enableRestartsMetrics = kingpin . Flag ( "collector.systemd.enable-restarts-metrics" , "Enables service unit metric service_restart_total" ) . Bool ( )
enableStartTimeMetrics = kingpin . Flag ( "collector.systemd.enable-start-time-metrics" , "Enables service unit metric unit_start_time_seconds" ) . Bool ( )
2022-02-06 06:33:30 -08:00
systemdVersionRE = regexp . MustCompile ( ` [0-9] { 3,}(\.[0-9]+)? ` )
2015-12-06 13:33:47 -08:00
)
type systemdCollector struct {
2018-07-05 07:26:48 -07:00
unitDesc * prometheus . Desc
2018-07-18 07:02:05 -07:00
unitStartTimeDesc * prometheus . Desc
2018-11-14 01:50:39 -08:00
unitTasksCurrentDesc * prometheus . Desc
unitTasksMaxDesc * prometheus . Desc
2018-07-05 07:26:48 -07:00
systemRunningDesc * prometheus . Desc
summaryDesc * prometheus . Desc
nRestartsDesc * prometheus . Desc
timerLastTriggerDesc * prometheus . Desc
socketAcceptedConnectionsDesc * prometheus . Desc
socketCurrentConnectionsDesc * prometheus . Desc
2018-07-16 07:01:42 -07:00
socketRefusedConnectionsDesc * prometheus . Desc
2019-09-04 07:27:25 -07:00
systemdVersionDesc * prometheus . Desc
2023-07-10 03:25:18 -07:00
// Use regexps for more flexability than device_filter.go allows
systemdUnitIncludePattern * regexp . Regexp
systemdUnitExcludePattern * regexp . Regexp
logger log . Logger
2015-12-06 13:33:47 -08:00
}
var unitStatesName = [ ] string { "active" , "activating" , "deactivating" , "inactive" , "failed" }
func init ( ) {
2017-09-28 06:06:26 -07:00
registerCollector ( "systemd" , defaultDisabled , NewSystemdCollector )
2015-12-06 13:33:47 -08:00
}
2017-02-28 08:44:53 -08:00
// NewSystemdCollector returns a new Collector exposing systemd statistics.
2019-12-31 08:19:37 -08:00
func NewSystemdCollector ( logger log . Logger ) ( Collector , error ) {
2015-12-17 10:30:35 -08:00
const subsystem = "systemd"
2015-12-06 13:33:47 -08:00
unitDesc := prometheus . NewDesc (
2017-09-28 06:06:26 -07:00
prometheus . BuildFQName ( namespace , subsystem , "unit_state" ) ,
2019-01-29 14:54:47 -08:00
"Systemd unit" , [ ] string { "name" , "state" , "type" } , nil ,
2015-12-06 13:33:47 -08:00
)
2018-07-18 07:02:05 -07:00
unitStartTimeDesc := prometheus . NewDesc (
prometheus . BuildFQName ( namespace , subsystem , "unit_start_time_seconds" ) ,
"Start time of the unit since unix epoch in seconds." , [ ] string { "name" } , nil ,
)
2018-11-14 01:50:39 -08:00
unitTasksCurrentDesc := prometheus . NewDesc (
prometheus . BuildFQName ( namespace , subsystem , "unit_tasks_current" ) ,
"Current number of tasks per Systemd unit" , [ ] string { "name" } , nil ,
)
unitTasksMaxDesc := prometheus . NewDesc (
prometheus . BuildFQName ( namespace , subsystem , "unit_tasks_max" ) ,
"Maximum number of tasks per Systemd unit" , [ ] string { "name" } , nil ,
)
2015-12-17 10:30:35 -08:00
systemRunningDesc := prometheus . NewDesc (
2017-09-28 06:06:26 -07:00
prometheus . BuildFQName ( namespace , subsystem , "system_running" ) ,
2015-12-17 10:30:35 -08:00
"Whether the system is operational (see 'systemctl is-system-running')" ,
nil , nil ,
)
2018-01-04 02:49:36 -08:00
summaryDesc := prometheus . NewDesc (
prometheus . BuildFQName ( namespace , subsystem , "units" ) ,
"Summary of systemd unit states" , [ ] string { "state" } , nil )
2018-07-05 04:31:45 -07:00
nRestartsDesc := prometheus . NewDesc (
prometheus . BuildFQName ( namespace , subsystem , "service_restart_total" ) ,
2019-06-25 00:37:48 -07:00
"Service unit count of Restart triggers" , [ ] string { "name" } , nil )
2018-01-31 07:06:58 -08:00
timerLastTriggerDesc := prometheus . NewDesc (
prometheus . BuildFQName ( namespace , subsystem , "timer_last_trigger_seconds" ) ,
"Seconds since epoch of last trigger." , [ ] string { "name" } , nil )
2018-07-05 07:26:48 -07:00
socketAcceptedConnectionsDesc := prometheus . NewDesc (
prometheus . BuildFQName ( namespace , subsystem , "socket_accepted_connections_total" ) ,
"Total number of accepted socket connections" , [ ] string { "name" } , nil )
socketCurrentConnectionsDesc := prometheus . NewDesc (
prometheus . BuildFQName ( namespace , subsystem , "socket_current_connections" ) ,
"Current number of socket connections" , [ ] string { "name" } , nil )
2018-07-16 07:01:42 -07:00
socketRefusedConnectionsDesc := prometheus . NewDesc (
prometheus . BuildFQName ( namespace , subsystem , "socket_refused_connections_total" ) ,
"Total number of refused socket connections" , [ ] string { "name" } , nil )
2019-09-04 07:27:25 -07:00
systemdVersionDesc := prometheus . NewDesc (
prometheus . BuildFQName ( namespace , subsystem , "version" ) ,
2022-02-17 05:25:49 -08:00
"Detected systemd version" , [ ] string { "version" } , nil )
2020-06-11 23:24:29 -07:00
2023-07-10 03:25:18 -07:00
if * oldSystemdUnitExclude != "" {
if ! systemdUnitExcludeSet {
2020-06-11 23:24:29 -07:00
level . Warn ( logger ) . Log ( "msg" , "--collector.systemd.unit-blacklist is DEPRECATED and will be removed in 2.0.0, use --collector.systemd.unit-exclude" )
2023-07-10 03:25:18 -07:00
* systemdUnitExclude = * oldSystemdUnitExclude
2020-06-11 23:24:29 -07:00
} else {
return nil , errors . New ( "--collector.systemd.unit-blacklist and --collector.systemd.unit-exclude are mutually exclusive" )
}
}
2023-07-10 03:25:18 -07:00
if * oldSystemdUnitInclude != "" {
if ! systemdUnitIncludeSet {
2020-06-11 23:24:29 -07:00
level . Warn ( logger ) . Log ( "msg" , "--collector.systemd.unit-whitelist is DEPRECATED and will be removed in 2.0.0, use --collector.systemd.unit-include" )
2023-07-10 03:25:18 -07:00
* systemdUnitInclude = * oldSystemdUnitInclude
2020-06-11 23:24:29 -07:00
} else {
return nil , errors . New ( "--collector.systemd.unit-whitelist and --collector.systemd.unit-include are mutually exclusive" )
}
}
2023-07-10 03:25:18 -07:00
level . Info ( logger ) . Log ( "msg" , "Parsed flag --collector.systemd.unit-include" , "flag" , * systemdUnitInclude )
systemdUnitIncludePattern := regexp . MustCompile ( fmt . Sprintf ( "^(?:%s)$" , * systemdUnitInclude ) )
level . Info ( logger ) . Log ( "msg" , "Parsed flag --collector.systemd.unit-exclude" , "flag" , * systemdUnitExclude )
systemdUnitExcludePattern := regexp . MustCompile ( fmt . Sprintf ( "^(?:%s)$" , * systemdUnitExclude ) )
2015-12-06 13:33:47 -08:00
return & systemdCollector {
2018-07-05 07:26:48 -07:00
unitDesc : unitDesc ,
2018-07-18 07:02:05 -07:00
unitStartTimeDesc : unitStartTimeDesc ,
2018-11-14 01:50:39 -08:00
unitTasksCurrentDesc : unitTasksCurrentDesc ,
unitTasksMaxDesc : unitTasksMaxDesc ,
2018-07-05 07:26:48 -07:00
systemRunningDesc : systemRunningDesc ,
summaryDesc : summaryDesc ,
nRestartsDesc : nRestartsDesc ,
timerLastTriggerDesc : timerLastTriggerDesc ,
socketAcceptedConnectionsDesc : socketAcceptedConnectionsDesc ,
socketCurrentConnectionsDesc : socketCurrentConnectionsDesc ,
2018-07-16 07:01:42 -07:00
socketRefusedConnectionsDesc : socketRefusedConnectionsDesc ,
2019-09-04 07:27:25 -07:00
systemdVersionDesc : systemdVersionDesc ,
2023-07-10 03:25:18 -07:00
systemdUnitIncludePattern : systemdUnitIncludePattern ,
systemdUnitExcludePattern : systemdUnitExcludePattern ,
2019-12-31 08:19:37 -08:00
logger : logger ,
2015-12-06 13:33:47 -08:00
} , nil
}
2019-02-11 14:27:21 -08:00
// Update gathers metrics from systemd. Dbus collection is done in parallel
// to reduce wait time for responses.
2017-02-28 10:47:20 -08:00
func ( c * systemdCollector ) Update ( ch chan <- prometheus . Metric ) error {
2019-02-11 14:27:21 -08:00
begin := time . Now ( )
2019-09-04 07:27:25 -07:00
conn , err := newSystemdDbusConn ( )
2019-02-11 14:27:21 -08:00
if err != nil {
2020-06-15 13:27:14 -07:00
return fmt . Errorf ( "couldn't get dbus connection: %w" , err )
2019-02-11 14:27:21 -08:00
}
defer conn . Close ( )
2022-02-17 05:25:49 -08:00
systemdVersion , systemdVersionFull := c . getSystemdVersion ( conn )
2022-02-06 06:33:30 -08:00
if systemdVersion < minSystemdVersionSystemState {
level . Debug ( c . logger ) . Log ( "msg" , "Detected systemd version is lower than minimum, some systemd state and timer metrics will not be available" , "current" , systemdVersion , "minimum" , minSystemdVersionSystemState )
}
ch <- prometheus . MustNewConstMetric (
2022-02-17 05:25:49 -08:00
c . systemdVersionDesc ,
prometheus . GaugeValue ,
systemdVersion ,
systemdVersionFull ,
)
2022-02-06 06:33:30 -08:00
2019-02-11 14:27:21 -08:00
allUnits , err := c . getAllUnits ( conn )
2015-12-06 13:33:47 -08:00
if err != nil {
2020-06-15 13:27:14 -07:00
return fmt . Errorf ( "couldn't get units: %w" , err )
2015-12-06 13:33:47 -08:00
}
2019-12-31 08:19:37 -08:00
level . Debug ( c . logger ) . Log ( "msg" , "getAllUnits took" , "duration_seconds" , time . Since ( begin ) . Seconds ( ) )
2018-01-04 02:49:36 -08:00
2019-02-11 14:27:21 -08:00
begin = time . Now ( )
2018-01-04 02:49:36 -08:00
summary := summarizeUnits ( allUnits )
c . collectSummaryMetrics ( ch , summary )
2019-12-31 08:19:37 -08:00
level . Debug ( c . logger ) . Log ( "msg" , "collectSummaryMetrics took" , "duration_seconds" , time . Since ( begin ) . Seconds ( ) )
2018-01-04 02:49:36 -08:00
2019-02-11 14:27:21 -08:00
begin = time . Now ( )
2023-07-10 03:25:18 -07:00
units := filterUnits ( allUnits , c . systemdUnitIncludePattern , c . systemdUnitExcludePattern , c . logger )
2019-12-31 08:19:37 -08:00
level . Debug ( c . logger ) . Log ( "msg" , "filterUnits took" , "duration_seconds" , time . Since ( begin ) . Seconds ( ) )
2019-02-11 14:27:21 -08:00
var wg sync . WaitGroup
defer wg . Wait ( )
wg . Add ( 1 )
go func ( ) {
defer wg . Done ( )
begin = time . Now ( )
c . collectUnitStatusMetrics ( conn , ch , units )
2019-12-31 08:19:37 -08:00
level . Debug ( c . logger ) . Log ( "msg" , "collectUnitStatusMetrics took" , "duration_seconds" , time . Since ( begin ) . Seconds ( ) )
2019-02-11 14:27:21 -08:00
} ( )
if * enableStartTimeMetrics {
wg . Add ( 1 )
go func ( ) {
defer wg . Done ( )
begin = time . Now ( )
c . collectUnitStartTimeMetrics ( conn , ch , units )
2019-12-31 08:19:37 -08:00
level . Debug ( c . logger ) . Log ( "msg" , "collectUnitStartTimeMetrics took" , "duration_seconds" , time . Since ( begin ) . Seconds ( ) )
2019-02-11 14:27:21 -08:00
} ( )
2015-12-17 10:30:35 -08:00
}
2015-12-06 13:33:47 -08:00
2019-02-11 14:27:21 -08:00
if * enableTaskMetrics {
wg . Add ( 1 )
go func ( ) {
defer wg . Done ( )
begin = time . Now ( )
c . collectUnitTasksMetrics ( conn , ch , units )
2019-12-31 08:19:37 -08:00
level . Debug ( c . logger ) . Log ( "msg" , "collectUnitTasksMetrics took" , "duration_seconds" , time . Since ( begin ) . Seconds ( ) )
2019-02-11 14:27:21 -08:00
} ( )
}
2022-02-06 06:33:30 -08:00
if systemdVersion >= minSystemdVersionSystemState {
2019-09-04 07:27:25 -07:00
wg . Add ( 1 )
go func ( ) {
defer wg . Done ( )
begin = time . Now ( )
c . collectTimers ( conn , ch , units )
2019-12-31 08:19:37 -08:00
level . Debug ( c . logger ) . Log ( "msg" , "collectTimers took" , "duration_seconds" , time . Since ( begin ) . Seconds ( ) )
2019-09-04 07:27:25 -07:00
} ( )
}
2019-02-11 14:27:21 -08:00
wg . Add ( 1 )
go func ( ) {
defer wg . Done ( )
begin = time . Now ( )
c . collectSockets ( conn , ch , units )
2019-12-31 08:19:37 -08:00
level . Debug ( c . logger ) . Log ( "msg" , "collectSockets took" , "duration_seconds" , time . Since ( begin ) . Seconds ( ) )
2019-02-11 14:27:21 -08:00
} ( )
2022-02-06 06:33:30 -08:00
if systemdVersion >= minSystemdVersionSystemState {
2019-09-04 07:27:25 -07:00
begin = time . Now ( )
err = c . collectSystemState ( conn , ch )
2019-12-31 08:19:37 -08:00
level . Debug ( c . logger ) . Log ( "msg" , "collectSystemState took" , "duration_seconds" , time . Since ( begin ) . Seconds ( ) )
2019-09-04 07:27:25 -07:00
}
2019-02-11 14:27:21 -08:00
return err
2015-12-06 13:33:47 -08:00
}
2019-02-11 14:27:21 -08:00
func ( c * systemdCollector ) collectUnitStatusMetrics ( conn * dbus . Conn , ch chan <- prometheus . Metric , units [ ] unit ) {
2015-12-06 13:33:47 -08:00
for _ , unit := range units {
2019-02-11 14:27:21 -08:00
serviceType := ""
if strings . HasSuffix ( unit . Name , ".service" ) {
2022-05-04 13:14:18 -07:00
serviceTypeProperty , err := conn . GetUnitTypePropertyContext ( context . TODO ( ) , unit . Name , "Service" , "Type" )
2019-02-11 14:27:21 -08:00
if err != nil {
2019-12-31 08:19:37 -08:00
level . Debug ( c . logger ) . Log ( "msg" , "couldn't get unit type" , "unit" , unit . Name , "err" , err )
2019-02-11 14:27:21 -08:00
} else {
serviceType = serviceTypeProperty . Value . Value ( ) . ( string )
}
} else if strings . HasSuffix ( unit . Name , ".mount" ) {
2022-05-04 13:14:18 -07:00
serviceTypeProperty , err := conn . GetUnitTypePropertyContext ( context . TODO ( ) , unit . Name , "Mount" , "Type" )
2019-02-11 14:27:21 -08:00
if err != nil {
2019-12-31 08:19:37 -08:00
level . Debug ( c . logger ) . Log ( "msg" , "couldn't get unit type" , "unit" , unit . Name , "err" , err )
2019-02-11 14:27:21 -08:00
} else {
serviceType = serviceTypeProperty . Value . Value ( ) . ( string )
}
}
2015-12-06 13:33:47 -08:00
for _ , stateName := range unitStatesName {
isActive := 0.0
if stateName == unit . ActiveState {
isActive = 1.0
}
ch <- prometheus . MustNewConstMetric (
c . unitDesc , prometheus . GaugeValue , isActive ,
2019-02-11 14:27:21 -08:00
unit . Name , stateName , serviceType )
2015-12-06 13:33:47 -08:00
}
2019-02-11 14:27:21 -08:00
if * enableRestartsMetrics && strings . HasSuffix ( unit . Name , ".service" ) {
// NRestarts wasn't added until systemd 235.
2022-05-04 13:14:18 -07:00
restartsCount , err := conn . GetUnitTypePropertyContext ( context . TODO ( ) , unit . Name , "Service" , "NRestarts" )
2019-02-11 14:27:21 -08:00
if err != nil {
2019-12-31 08:19:37 -08:00
level . Debug ( c . logger ) . Log ( "msg" , "couldn't get unit NRestarts" , "unit" , unit . Name , "err" , err )
2019-02-11 14:27:21 -08:00
} else {
ch <- prometheus . MustNewConstMetric (
c . nRestartsDesc , prometheus . CounterValue ,
float64 ( restartsCount . Value . Value ( ) . ( uint32 ) ) , unit . Name )
}
2018-07-05 04:31:45 -07:00
}
2015-12-06 13:33:47 -08:00
}
}
2019-02-11 14:27:21 -08:00
func ( c * systemdCollector ) collectSockets ( conn * dbus . Conn , ch chan <- prometheus . Metric , units [ ] unit ) {
2018-07-05 07:26:48 -07:00
for _ , unit := range units {
if ! strings . HasSuffix ( unit . Name , ".socket" ) {
continue
}
2022-05-04 13:14:18 -07:00
acceptedConnectionCount , err := conn . GetUnitTypePropertyContext ( context . TODO ( ) , unit . Name , "Socket" , "NAccepted" )
2019-02-11 14:27:21 -08:00
if err != nil {
2019-12-31 08:19:37 -08:00
level . Debug ( c . logger ) . Log ( "msg" , "couldn't get unit NAccepted" , "unit" , unit . Name , "err" , err )
2019-02-11 14:27:21 -08:00
continue
}
2018-07-05 07:26:48 -07:00
ch <- prometheus . MustNewConstMetric (
c . socketAcceptedConnectionsDesc , prometheus . CounterValue ,
2019-02-11 14:27:21 -08:00
float64 ( acceptedConnectionCount . Value . Value ( ) . ( uint32 ) ) , unit . Name )
2022-05-04 13:14:18 -07:00
currentConnectionCount , err := conn . GetUnitTypePropertyContext ( context . TODO ( ) , unit . Name , "Socket" , "NConnections" )
2019-02-11 14:27:21 -08:00
if err != nil {
2019-12-31 08:19:37 -08:00
level . Debug ( c . logger ) . Log ( "msg" , "couldn't get unit NConnections" , "unit" , unit . Name , "err" , err )
2019-02-11 14:27:21 -08:00
continue
}
2018-07-05 07:26:48 -07:00
ch <- prometheus . MustNewConstMetric (
c . socketCurrentConnectionsDesc , prometheus . GaugeValue ,
2019-02-11 14:27:21 -08:00
float64 ( currentConnectionCount . Value . Value ( ) . ( uint32 ) ) , unit . Name )
// NRefused wasn't added until systemd 239.
2022-05-04 13:14:18 -07:00
refusedConnectionCount , err := conn . GetUnitTypePropertyContext ( context . TODO ( ) , unit . Name , "Socket" , "NRefused" )
2023-07-18 01:46:59 -07:00
if err == nil {
2018-08-14 05:28:26 -07:00
ch <- prometheus . MustNewConstMetric (
c . socketRefusedConnectionsDesc , prometheus . GaugeValue ,
2019-02-11 14:27:21 -08:00
float64 ( refusedConnectionCount . Value . Value ( ) . ( uint32 ) ) , unit . Name )
2018-08-14 05:28:26 -07:00
}
2018-07-05 07:26:48 -07:00
}
}
2019-02-11 14:27:21 -08:00
func ( c * systemdCollector ) collectUnitStartTimeMetrics ( conn * dbus . Conn , ch chan <- prometheus . Metric , units [ ] unit ) {
var startTimeUsec uint64
2018-07-18 07:02:05 -07:00
for _ , unit := range units {
2019-02-11 14:27:21 -08:00
if unit . ActiveState != "active" {
startTimeUsec = 0
} else {
2022-05-04 13:14:18 -07:00
timestampValue , err := conn . GetUnitPropertyContext ( context . TODO ( ) , unit . Name , "ActiveEnterTimestamp" )
2019-02-11 14:27:21 -08:00
if err != nil {
2019-12-31 08:19:37 -08:00
level . Debug ( c . logger ) . Log ( "msg" , "couldn't get unit StartTimeUsec" , "unit" , unit . Name , "err" , err )
2019-02-11 14:27:21 -08:00
continue
}
startTimeUsec = timestampValue . Value . Value ( ) . ( uint64 )
}
2018-07-18 07:02:05 -07:00
ch <- prometheus . MustNewConstMetric (
c . unitStartTimeDesc , prometheus . GaugeValue ,
2019-02-11 14:27:21 -08:00
float64 ( startTimeUsec ) / 1e6 , unit . Name )
2018-07-18 07:02:05 -07:00
}
}
2019-02-11 14:27:21 -08:00
func ( c * systemdCollector ) collectUnitTasksMetrics ( conn * dbus . Conn , ch chan <- prometheus . Metric , units [ ] unit ) {
var val uint64
2018-11-14 01:50:39 -08:00
for _ , unit := range units {
2019-02-11 14:27:21 -08:00
if strings . HasSuffix ( unit . Name , ".service" ) {
2022-05-04 13:14:18 -07:00
tasksCurrentCount , err := conn . GetUnitTypePropertyContext ( context . TODO ( ) , unit . Name , "Service" , "TasksCurrent" )
2019-02-11 14:27:21 -08:00
if err != nil {
2019-12-31 08:19:37 -08:00
level . Debug ( c . logger ) . Log ( "msg" , "couldn't get unit TasksCurrent" , "unit" , unit . Name , "err" , err )
2019-02-11 14:27:21 -08:00
} else {
val = tasksCurrentCount . Value . Value ( ) . ( uint64 )
// Don't set if tasksCurrent if dbus reports MaxUint64.
if val != math . MaxUint64 {
ch <- prometheus . MustNewConstMetric (
c . unitTasksCurrentDesc , prometheus . GaugeValue ,
float64 ( val ) , unit . Name )
}
}
2022-05-04 13:14:18 -07:00
tasksMaxCount , err := conn . GetUnitTypePropertyContext ( context . TODO ( ) , unit . Name , "Service" , "TasksMax" )
2019-02-11 14:27:21 -08:00
if err != nil {
2019-12-31 08:19:37 -08:00
level . Debug ( c . logger ) . Log ( "msg" , "couldn't get unit TasksMax" , "unit" , unit . Name , "err" , err )
2019-02-11 14:27:21 -08:00
} else {
val = tasksMaxCount . Value . Value ( ) . ( uint64 )
// Don't set if tasksMax if dbus reports MaxUint64.
if val != math . MaxUint64 {
ch <- prometheus . MustNewConstMetric (
c . unitTasksMaxDesc , prometheus . GaugeValue ,
float64 ( val ) , unit . Name )
}
}
2018-11-14 01:50:39 -08:00
}
}
}
2019-02-11 14:27:21 -08:00
func ( c * systemdCollector ) collectTimers ( conn * dbus . Conn , ch chan <- prometheus . Metric , units [ ] unit ) {
2018-11-14 01:50:39 -08:00
for _ , unit := range units {
2019-02-11 14:27:21 -08:00
if ! strings . HasSuffix ( unit . Name , ".timer" ) {
continue
2018-11-14 01:50:39 -08:00
}
2022-05-04 13:14:18 -07:00
lastTriggerValue , err := conn . GetUnitTypePropertyContext ( context . TODO ( ) , unit . Name , "Timer" , "LastTriggerUSec" )
2019-02-11 14:27:21 -08:00
if err != nil {
2019-12-31 08:19:37 -08:00
level . Debug ( c . logger ) . Log ( "msg" , "couldn't get unit LastTriggerUSec" , "unit" , unit . Name , "err" , err )
2018-01-31 07:06:58 -08:00
continue
}
ch <- prometheus . MustNewConstMetric (
c . timerLastTriggerDesc , prometheus . GaugeValue ,
2019-02-11 14:27:21 -08:00
float64 ( lastTriggerValue . Value . Value ( ) . ( uint64 ) ) / 1e6 , unit . Name )
2018-01-31 07:06:58 -08:00
}
}
2018-01-04 02:49:36 -08:00
func ( c * systemdCollector ) collectSummaryMetrics ( ch chan <- prometheus . Metric , summary map [ string ] float64 ) {
for stateName , count := range summary {
ch <- prometheus . MustNewConstMetric (
c . summaryDesc , prometheus . GaugeValue , count , stateName )
}
}
2019-02-11 14:27:21 -08:00
func ( c * systemdCollector ) collectSystemState ( conn * dbus . Conn , ch chan <- prometheus . Metric ) error {
systemState , err := conn . GetManagerProperty ( "SystemState" )
if err != nil {
2020-06-15 13:27:14 -07:00
return fmt . Errorf ( "couldn't get system state: %w" , err )
2019-02-11 14:27:21 -08:00
}
2015-12-17 10:30:35 -08:00
isSystemRunning := 0.0
if systemState == ` "running" ` {
isSystemRunning = 1.0
}
ch <- prometheus . MustNewConstMetric ( c . systemRunningDesc , prometheus . GaugeValue , isSystemRunning )
2019-02-11 14:27:21 -08:00
return nil
2015-12-17 10:30:35 -08:00
}
2019-09-04 07:27:25 -07:00
func newSystemdDbusConn ( ) ( * dbus . Conn , error ) {
2016-03-29 07:19:47 -07:00
if * systemdPrivate {
2022-05-04 13:14:18 -07:00
return dbus . NewSystemdConnectionContext ( context . TODO ( ) )
2016-03-29 07:19:47 -07:00
}
2022-05-04 13:14:18 -07:00
return dbus . NewWithContext ( context . TODO ( ) )
2016-03-29 07:19:47 -07:00
}
2018-01-31 07:19:18 -08:00
type unit struct {
dbus . UnitStatus
2019-01-29 14:54:47 -08:00
}
2019-02-11 14:27:21 -08:00
func ( c * systemdCollector ) getAllUnits ( conn * dbus . Conn ) ( [ ] unit , error ) {
2022-05-04 13:14:18 -07:00
allUnits , err := conn . ListUnitsContext ( context . TODO ( ) )
2016-08-15 23:39:49 -07:00
if err != nil {
2018-01-31 07:19:18 -08:00
return nil , err
}
result := make ( [ ] unit , 0 , len ( allUnits ) )
for _ , status := range allUnits {
unit := unit {
UnitStatus : status ,
}
result = append ( result , unit )
2016-08-15 23:39:49 -07:00
}
2018-01-31 07:19:18 -08:00
return result , nil
2018-01-04 02:49:36 -08:00
}
2018-01-31 07:19:18 -08:00
func summarizeUnits ( units [ ] unit ) map [ string ] float64 {
2018-01-04 02:49:36 -08:00
summarized := make ( map [ string ] float64 )
for _ , unitStateName := range unitStatesName {
summarized [ unitStateName ] = 0.0
}
for _ , unit := range units {
summarized [ unit . ActiveState ] += 1.0
}
return summarized
2016-08-15 23:39:49 -07:00
}
2020-06-11 23:24:29 -07:00
func filterUnits ( units [ ] unit , includePattern , excludePattern * regexp . Regexp , logger log . Logger ) [ ] unit {
2018-01-31 07:19:18 -08:00
filtered := make ( [ ] unit , 0 , len ( units ) )
2016-08-15 23:39:49 -07:00
for _ , unit := range units {
2020-06-11 23:24:29 -07:00
if includePattern . MatchString ( unit . Name ) && ! excludePattern . MatchString ( unit . Name ) && unit . LoadState == "loaded" {
2019-12-31 08:19:37 -08:00
level . Debug ( logger ) . Log ( "msg" , "Adding unit" , "unit" , unit . Name )
2016-08-15 23:39:49 -07:00
filtered = append ( filtered , unit )
} else {
2019-12-31 08:19:37 -08:00
level . Debug ( logger ) . Log ( "msg" , "Ignoring unit" , "unit" , unit . Name )
2016-08-15 23:39:49 -07:00
}
}
return filtered
2015-12-06 13:33:47 -08:00
}
2019-09-04 07:27:25 -07:00
2022-02-17 05:25:49 -08:00
func ( c * systemdCollector ) getSystemdVersion ( conn * dbus . Conn ) ( float64 , string ) {
2019-09-04 07:27:25 -07:00
version , err := conn . GetManagerProperty ( "Version" )
if err != nil {
2022-02-06 06:33:30 -08:00
level . Debug ( c . logger ) . Log ( "msg" , "Unable to get systemd version property, defaulting to 0" )
2022-02-17 05:25:49 -08:00
return 0 , ""
2019-09-04 07:27:25 -07:00
}
2022-02-17 05:25:49 -08:00
version = strings . TrimPrefix ( strings . TrimSuffix ( version , ` " ` ) , ` " ` )
2022-02-06 06:33:30 -08:00
level . Debug ( c . logger ) . Log ( "msg" , "Got systemd version" , "version" , version )
2022-02-17 05:25:49 -08:00
parsedVersion := systemdVersionRE . FindString ( version )
v , err := strconv . ParseFloat ( parsedVersion , 64 )
2019-09-04 07:27:25 -07:00
if err != nil {
2022-02-06 06:33:30 -08:00
level . Debug ( c . logger ) . Log ( "msg" , "Got invalid systemd version" , "version" , version )
2022-02-17 05:25:49 -08:00
return 0 , ""
2019-09-04 07:27:25 -07:00
}
2022-02-17 05:25:49 -08:00
return v , version
2019-09-04 07:27:25 -07:00
}