collector: Implement uname collector for FreeBSD (#1239)

* collector: Implement uname collector for FreeBSD

Signed-off-by: David O'Rourke <david.orourke@gmail.com>
This commit is contained in:
David O'Rourke 2019-02-05 16:39:24 +00:00 committed by Ben Kochie
parent 2b81bff518
commit d442108d7a
5 changed files with 145 additions and 41 deletions

View file

@ -14,6 +14,7 @@ The cpufreq metrics now separate the `cpufreq` and `scaling` data based on what
* [ENHANCEMENT] Add Infiniband counters #1120
* [FEATURE] Add a flag to disable exporter metrics #1148
* [FEATURE] Add kstat-based Solaris metrics for boottime, cpu and zfs collectors #1197
* [FEATURE] Add uname collector for FreeBSD #1239
## 0.17.0 / 2018-11-30

View file

@ -54,7 +54,7 @@ stat | Exposes various statistics from `/proc/stat`. This includes boot time, fo
textfile | Exposes statistics read from local disk. The `--collector.textfile.directory` flag must be set. | _any_
time | Exposes the current system time. | _any_
timex | Exposes selected adjtimex(2) system call stats. | Linux
uname | Exposes system information as provided by the uname system call. | Linux
uname | Exposes system information as provided by the uname system call. | FreeBSD, Linux
vmstat | Exposes statistics from `/proc/vmstat`. | Linux
xfs | Exposes XFS runtime statistics. | Linux (kernel 4.4+)
zfs | Exposes [ZFS](http://open-zfs.org/) performance statistics. | [Linux](http://zfsonlinux.org/), Solaris

72
collector/uname.go Normal file
View file

@ -0,0 +1,72 @@
// Copyright 2019 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 freebsd linux
// +build !nouname
package collector
import (
"github.com/prometheus/client_golang/prometheus"
)
var unameDesc = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "uname", "info"),
"Labeled system information as provided by the uname system call.",
[]string{
"sysname",
"release",
"version",
"machine",
"nodename",
"domainname",
},
nil,
)
type unameCollector struct{}
type uname struct {
SysName string
Release string
Version string
Machine string
NodeName string
DomainName string
}
func init() {
registerCollector("uname", defaultEnabled, newUnameCollector)
}
// NewUnameCollector returns new unameCollector.
func newUnameCollector() (Collector, error) {
return &unameCollector{}, nil
}
func (c unameCollector) Update(ch chan<- prometheus.Metric) error {
uname, err := getUname()
if err != nil {
return err
}
ch <- prometheus.MustNewConstMetric(unameDesc, prometheus.GaugeValue, 1,
uname.SysName,
uname.Release,
uname.Version,
uname.Machine,
uname.NodeName,
uname.DomainName,
)
return nil
}

View file

@ -0,0 +1,57 @@
// Copyright 2019 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 !nouname
package collector
import (
"bytes"
"strings"
"golang.org/x/sys/unix"
)
func getUname() (uname, error) {
var utsname unix.Utsname
if err := unix.Uname(&utsname); err != nil {
return uname{}, err
}
// We do a little bit of work here to emulate what happens in the Linux
// uname calls since FreeBSD uname doesn't have a Domainname.
nodename := string(utsname.Nodename[:bytes.IndexByte(utsname.Nodename[:], 0)])
split := strings.SplitN(nodename, ".", 2)
// We'll always have at least a single element in the array. We assume this
// is the hostname.
hostname := split[0]
// If we have more than one element, we assume this is the domainname.
// Otherwise leave it to "(none)" like Linux.
domainname := "(none)"
if len(split) > 1 {
domainname = split[1]
}
output := uname{
SysName: string(utsname.Sysname[:bytes.IndexByte(utsname.Sysname[:], 0)]),
Release: string(utsname.Release[:bytes.IndexByte(utsname.Release[:], 0)]),
Version: string(utsname.Version[:bytes.IndexByte(utsname.Version[:], 0)]),
Machine: string(utsname.Machine[:bytes.IndexByte(utsname.Machine[:], 0)]),
NodeName: hostname,
DomainName: domainname,
}
return output, nil
}

View file

@ -18,49 +18,23 @@ package collector
import (
"bytes"
"github.com/prometheus/client_golang/prometheus"
"golang.org/x/sys/unix"
)
var unameDesc = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "uname", "info"),
"Labeled system information as provided by the uname system call.",
[]string{
"sysname",
"release",
"version",
"machine",
"nodename",
"domainname",
},
nil,
)
type unameCollector struct{}
func init() {
registerCollector("uname", defaultEnabled, newUnameCollector)
}
// NewUnameCollector returns new unameCollector.
func newUnameCollector() (Collector, error) {
return &unameCollector{}, nil
}
func (c unameCollector) Update(ch chan<- prometheus.Metric) error {
var uname unix.Utsname
if err := unix.Uname(&uname); err != nil {
return err
func getUname() (uname, error) {
var utsname unix.Utsname
if err := unix.Uname(&utsname); err != nil {
return uname{}, err
}
ch <- prometheus.MustNewConstMetric(unameDesc, prometheus.GaugeValue, 1,
string(uname.Sysname[:bytes.IndexByte(uname.Sysname[:], 0)]),
string(uname.Release[:bytes.IndexByte(uname.Release[:], 0)]),
string(uname.Version[:bytes.IndexByte(uname.Version[:], 0)]),
string(uname.Machine[:bytes.IndexByte(uname.Machine[:], 0)]),
string(uname.Nodename[:bytes.IndexByte(uname.Nodename[:], 0)]),
string(uname.Domainname[:bytes.IndexByte(uname.Domainname[:], 0)]),
)
return nil
output := uname{
SysName: string(utsname.Sysname[:bytes.IndexByte(utsname.Sysname[:], 0)]),
Release: string(utsname.Release[:bytes.IndexByte(utsname.Release[:], 0)]),
Version: string(utsname.Version[:bytes.IndexByte(utsname.Version[:], 0)]),
Machine: string(utsname.Machine[:bytes.IndexByte(utsname.Machine[:], 0)]),
NodeName: string(utsname.Nodename[:bytes.IndexByte(utsname.Nodename[:], 0)]),
DomainName: string(utsname.Domainname[:bytes.IndexByte(utsname.Domainname[:], 0)]),
}
return output, nil
}