remove openbsd amd64 cgo dependecies

I have rewritten all CGO dependencies for OpenBSD amd64
using pure go, be able to crosscompile node_exporter.

Signed-off-by: ston1th <ston1th@giftfish.de>
This commit is contained in:
ston1th 2020-07-02 14:43:14 +02:00
parent f645d49242
commit f8609aeee2
17 changed files with 658 additions and 5 deletions

View file

@ -31,3 +31,4 @@ crossbuild:
- linux/ppc64
- linux/ppc64le
- linux/s390x
- openbsd/amd64

View file

@ -5,6 +5,7 @@
* [FEATURE]
* [ENHANCEMENT] Include TCP OutRsts in netstat metrics
* [ENHANCEMENT] Added XFS inode operations to XFS metrics
* [ENHANCEMENT] Remove CGO dependencies for OpenBSD amd64
* [BUGFIX]
## 1.0.1 / 2020-06-15

View file

@ -45,7 +45,16 @@ else
PROMU_CONF ?= .promu-cgo.yml
endif
else
PROMU_CONF ?= .promu-cgo.yml
# Do not use CGO for openbsd/amd64 builds
ifeq ($(GOOS), openbsd)
ifeq ($(GOARCH), amd64)
PROMU_CONF ?= .promu.yml
else
PROMU_CONF ?= .promu-cgo.yml
endif
else
PROMU_CONF ?= .promu-cgo.yml
endif
endif
endif

View file

@ -31,7 +31,7 @@ bcache | Exposes bcache statistics from `/sys/fs/bcache/`. | Linux
bonding | Exposes the number of configured and active slaves of Linux bonding interfaces. | Linux
boottime | Exposes system boot time derived from the `kern.boottime` sysctl. | Darwin, Dragonfly, FreeBSD, NetBSD, OpenBSD, Solaris
conntrack | Shows conntrack statistics (does nothing if no `/proc/sys/net/netfilter/` present). | Linux
cpu | Exposes CPU statistics | Darwin, Dragonfly, FreeBSD, Linux, Solaris
cpu | Exposes CPU statistics | Darwin, Dragonfly, FreeBSD, Linux, Solaris, OpenBSD
cpufreq | Exposes CPU frequency statistics | Linux, Solaris
diskstats | Exposes disk I/O statistics. | Darwin, Linux, OpenBSD
edac | Exposes error detection and correction statistics. | Linux

View file

@ -11,7 +11,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// +build freebsd dragonfly openbsd netbsd darwin
// +build freebsd dragonfly openbsd,!amd64 netbsd darwin
// +build !noboottime
package collector

View file

@ -0,0 +1,61 @@
// Copyright 2020 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 !noboottime
package collector
import (
"github.com/go-kit/kit/log"
"github.com/prometheus/client_golang/prometheus"
"golang.org/x/sys/unix"
"unsafe"
)
type bootTimeCollector struct {
name, description string
logger log.Logger
}
func init() {
registerCollector("boottime", defaultEnabled, newBootTimeCollector)
}
// newBootTimeCollector returns a new Collector exposing system boot time on BSD systems.
func newBootTimeCollector(logger log.Logger) (Collector, error) {
return &bootTimeCollector{
name: "boot_time_seconds",
description: "Unix time of last boot, including microseconds.",
logger: logger,
}, nil
}
// Update pushes boot time onto ch
func (c *bootTimeCollector) Update(ch chan<- prometheus.Metric) error {
raw, err := unix.SysctlRaw("kern.boottime")
if err != nil {
return err
}
tv := *(*unix.Timeval)(unsafe.Pointer(&raw[0]))
v := (float64(tv.Sec) + (float64(tv.Usec) / float64(1000*1000)))
ch <- prometheus.MustNewConstMetric(
prometheus.NewDesc(
prometheus.BuildFQName(namespace, "", c.name),
c.description,
nil, nil,
), prometheus.GaugeValue, v)
return nil
}

View file

@ -11,6 +11,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// +build openbsd,!amd64
// +build !nocpu
package collector

View file

@ -0,0 +1,95 @@
// Copyright 2020 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 !nocpu
package collector
import (
"strconv"
"unsafe"
"github.com/go-kit/kit/log"
"github.com/prometheus/client_golang/prometheus"
"golang.org/x/sys/unix"
)
type clockinfo struct {
hz int32
tick int32
tickadj int32
stathz int32
profhz int32
}
const (
CP_USER = 0
CP_NICE = 1
CP_SYS = 2
CP_SPIN = 3
CP_INTR = 4
CP_IDLE = 5
CPUSTATES = 6
)
type cpuCollector struct {
cpu typedDesc
logger log.Logger
}
func init() {
registerCollector("cpu", defaultEnabled, NewCPUCollector)
}
func NewCPUCollector(logger log.Logger) (Collector, error) {
return &cpuCollector{
cpu: typedDesc{nodeCPUSecondsDesc, prometheus.CounterValue},
logger: logger,
}, nil
}
func (c *cpuCollector) Update(ch chan<- prometheus.Metric) (err error) {
clockb, err := unix.SysctlRaw("kern.clockrate")
if err != nil {
return err
}
clock := *(*clockinfo)(unsafe.Pointer(&clockb[0]))
hz := float64(clock.stathz)
ncpus, err := unix.SysctlUint32("hw.ncpu")
if err != nil {
return err
}
var cpTime [][CPUSTATES]int64
for i := 0; i < int(ncpus); i++ {
cpb, err := unix.SysctlRaw("kern.cp_time2", i)
if err != nil && err != unix.ENODEV {
return err
}
if err != unix.ENODEV {
cpTime = append(cpTime, *(*[CPUSTATES]int64)(unsafe.Pointer(&cpb[0])))
}
}
for cpu, time := range cpTime {
lcpu := strconv.Itoa(cpu)
ch <- c.cpu.mustNewConstMetric(float64(time[CP_USER])/hz, lcpu, "user")
ch <- c.cpu.mustNewConstMetric(float64(time[CP_NICE])/hz, lcpu, "nice")
ch <- c.cpu.mustNewConstMetric(float64(time[CP_SYS])/hz, lcpu, "system")
ch <- c.cpu.mustNewConstMetric(float64(time[CP_SPIN])/hz, lcpu, "spin")
ch <- c.cpu.mustNewConstMetric(float64(time[CP_INTR])/hz, lcpu, "interrupt")
ch <- c.cpu.mustNewConstMetric(float64(time[CP_IDLE])/hz, lcpu, "idle")
}
return err
}

View file

@ -11,6 +11,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// +build openbsd,!amd64
// +build !nodiskstats
package collector

View file

@ -0,0 +1,89 @@
// Copyright 2020 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 !nodiskstats
package collector
import (
"unsafe"
"github.com/go-kit/kit/log"
"github.com/prometheus/client_golang/prometheus"
"golang.org/x/sys/unix"
)
const (
DS_DISKNAMELEN = 16
)
type DiskStats struct {
Name [DS_DISKNAMELEN]int8
Busy int32
Rxfer uint64
Wxfer uint64
Seek uint64
Rbytes uint64
Wbytes uint64
Attachtime unix.Timeval
Timestamp unix.Timeval
Time unix.Timeval
}
type diskstatsCollector struct {
rxfer typedDesc
rbytes typedDesc
wxfer typedDesc
wbytes typedDesc
time typedDesc
logger log.Logger
}
func init() {
registerCollector("diskstats", defaultEnabled, NewDiskstatsCollector)
}
// NewDiskstatsCollector returns a new Collector exposing disk device stats.
func NewDiskstatsCollector(logger log.Logger) (Collector, error) {
return &diskstatsCollector{
rxfer: typedDesc{readsCompletedDesc, prometheus.CounterValue},
rbytes: typedDesc{readBytesDesc, prometheus.CounterValue},
wxfer: typedDesc{writesCompletedDesc, prometheus.CounterValue},
wbytes: typedDesc{writtenBytesDesc, prometheus.CounterValue},
time: typedDesc{ioTimeSecondsDesc, prometheus.CounterValue},
logger: logger,
}, nil
}
func (c *diskstatsCollector) Update(ch chan<- prometheus.Metric) (err error) {
diskstatsb, err := unix.SysctlRaw("hw.diskstats")
if err != nil {
return err
}
ndisks := len(diskstatsb) / int(unsafe.Sizeof(DiskStats{}))
diskstats := *(*[]DiskStats)(unsafe.Pointer(&diskstatsb))
for i := 0; i < ndisks; i++ {
dn := *(*[DS_DISKNAMELEN]int8)(unsafe.Pointer(&diskstats[i].Name[0]))
diskname := int8ToString(dn[:])
ch <- c.rxfer.mustNewConstMetric(float64(diskstats[i].Rxfer), diskname)
ch <- c.rbytes.mustNewConstMetric(float64(diskstats[i].Rbytes), diskname)
ch <- c.wxfer.mustNewConstMetric(float64(diskstats[i].Wxfer), diskname)
ch <- c.wbytes.mustNewConstMetric(float64(diskstats[i].Wbytes), diskname)
time := float64(diskstats[i].Time.Sec) + float64(diskstats[i].Time.Usec)/1000000
ch <- c.time.mustNewConstMetric(time, diskname)
}
return nil
}

View file

@ -11,7 +11,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// +build openbsd darwin,amd64 dragonfly
// +build openbsd,!amd64 darwin,amd64 dragonfly
// +build !nofilesystem
package collector

View file

@ -0,0 +1,77 @@
// Copyright 2020 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 openbsd darwin,amd64 dragonfly
// +build !nofilesystem
package collector
import (
"github.com/go-kit/kit/log/level"
"golang.org/x/sys/unix"
)
const (
defIgnoredMountPoints = "^/(dev)($|/)"
defIgnoredFSTypes = "^devfs$"
)
// Expose filesystem fullness.
func (c *filesystemCollector) GetStats() (stats []filesystemStats, err error) {
var mnt []unix.Statfs_t
size, err := unix.Getfsstat(mnt, unix.MNT_NOWAIT)
if err != nil {
return nil, err
}
mnt = make([]unix.Statfs_t, size)
_, err = unix.Getfsstat(mnt, unix.MNT_NOWAIT)
if err != nil {
return nil, err
}
stats = []filesystemStats{}
for _, v := range mnt {
mountpoint := int8ToString(v.F_mntonname[:])
if c.ignoredMountPointsPattern.MatchString(mountpoint) {
level.Debug(c.logger).Log("msg", "Ignoring mount point", "mountpoint", mountpoint)
continue
}
device := int8ToString(v.F_mntfromname[:])
fstype := int8ToString(v.F_fstypename[:])
if c.ignoredFSTypesPattern.MatchString(fstype) {
level.Debug(c.logger).Log("msg", "Ignoring fs type", "type", fstype)
continue
}
var ro float64
if (v.F_flags & unix.MNT_RDONLY) != 0 {
ro = 1
}
stats = append(stats, filesystemStats{
labels: filesystemLabels{
device: device,
mountPoint: mountpoint,
fsType: fstype,
},
size: float64(v.F_blocks) * float64(v.F_bsize),
free: float64(v.F_bfree) * float64(v.F_bsize),
avail: float64(v.F_bavail) * float64(v.F_bsize),
files: float64(v.F_files),
filesFree: float64(v.F_ffree),
ro: ro,
})
}
return stats, nil
}

View file

@ -0,0 +1,113 @@
// Copyright 2020 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 !nointerrupts
package collector
import (
"fmt"
"strconv"
"unsafe"
"github.com/prometheus/client_golang/prometheus"
"golang.org/x/sys/unix"
)
const (
KERN_INTRCNT = 63
KERN_INTRCNT_NUM = 1
KERN_INTRCNT_CNT = 2
KERN_INTRCNT_NAME = 3
KERN_INTRCNT_VECTOR = 4
)
func nintr() _C_int {
mib := [3]_C_int{unix.CTL_KERN, KERN_INTRCNT, KERN_INTRCNT_NUM}
buf, err := sysctl(mib[:])
if err != nil {
return 0
}
return *(*_C_int)(unsafe.Pointer(&buf[0]))
}
func intr(idx _C_int) (itr interrupt, err error) {
mib := [4]_C_int{unix.CTL_KERN, KERN_INTRCNT, KERN_INTRCNT_NAME, idx}
buf, err := sysctl(mib[:])
if err != nil {
return
}
dev := *(*[128]byte)(unsafe.Pointer(&buf[0]))
itr.device = string(dev[:])
mib[2] = KERN_INTRCNT_VECTOR
buf, err = sysctl(mib[:])
if err != nil {
return
}
itr.vector = *(*int)(unsafe.Pointer(&buf[0]))
mib[2] = KERN_INTRCNT_CNT
buf, err = sysctl(mib[:])
if err != nil {
return
}
count := *(*uint64)(unsafe.Pointer(&buf[0]))
itr.values = []float64{float64(count)}
return
}
var (
interruptLabelNames = []string{"cpu", "type", "devices"}
)
func (c *interruptsCollector) Update(ch chan<- prometheus.Metric) error {
interrupts, err := getInterrupts()
if err != nil {
return fmt.Errorf("couldn't get interrupts: %s", err)
}
for dev, interrupt := range interrupts {
for cpuNo, value := range interrupt.values {
ch <- c.desc.mustNewConstMetric(
value,
strconv.Itoa(cpuNo),
fmt.Sprintf("%d", interrupt.vector),
dev,
)
}
}
return nil
}
type interrupt struct {
vector int
device string
values []float64
}
func getInterrupts() (map[string]interrupt, error) {
var interrupts = map[string]interrupt{}
n := nintr()
for i := _C_int(0); i < n; i++ {
itr, err := intr(i)
if err != nil {
return nil, err
}
interrupts[itr.device] = itr
}
return interrupts, nil
}

View file

@ -11,7 +11,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// +build openbsd
// +build !nomeminfo
package collector

View file

@ -0,0 +1,45 @@
// Copyright 2020 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 !nomeminfo
package collector
import (
"golang.org/x/sys/unix"
"unsafe"
)
func (c *meminfoCollector) getMemInfo() (map[string]float64, error) {
uvmexpb, err := unix.SysctlRaw("vm.uvmexp")
if err != nil {
return nil, err
}
uvmexp := *(*unix.Uvmexp)(unsafe.Pointer(&uvmexpb[0]))
ps := float64(uvmexp.Pagesize)
// see uvm(9)
return map[string]float64{
"active_bytes": ps * float64(uvmexp.Active),
"cache_bytes": ps * float64(uvmexp.Vnodepages),
"free_bytes": ps * float64(uvmexp.Free),
"inactive_bytes": ps * float64(uvmexp.Inactive),
"size_bytes": ps * float64(uvmexp.Npages),
"swap_size_bytes": ps * float64(uvmexp.Swpages),
"swap_used_bytes": ps * float64(uvmexp.Swpginuse),
"swapped_in_pages_bytes_total": ps * float64(uvmexp.Pgswapin),
"swapped_out_pages_bytes_total": ps * float64(uvmexp.Pgswapout),
"wired_bytes": ps * float64(uvmexp.Wired),
}, nil
}

View file

@ -0,0 +1,79 @@
// Copyright 2020 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 !nonetdev
package collector
import (
"github.com/go-kit/kit/log"
"github.com/go-kit/kit/log/level"
"strconv"
"golang.org/x/sys/unix"
"regexp"
"unsafe"
)
func getNetDevStats(ignore *regexp.Regexp, accept *regexp.Regexp, logger log.Logger) (map[string]map[string]string, error) {
netDev := map[string]map[string]string{}
mib := [6]_C_int{unix.CTL_NET, unix.AF_ROUTE, 0, 0, unix.NET_RT_IFLIST, 0}
buf, err := sysctl(mib[:])
if err != nil {
return nil, err
}
n := uintptr(len(buf))
index := uintptr(unsafe.Pointer(&buf[0]))
next := uintptr(0)
var rtm *unix.RtMsghdr
for next = index; next < (index + n); next += uintptr(rtm.Msglen) {
rtm = (*unix.RtMsghdr)(unsafe.Pointer(next))
if rtm.Version != unix.RTM_VERSION || rtm.Type != unix.RTM_IFINFO {
continue
}
ifm := (*unix.IfMsghdr)(unsafe.Pointer(next))
if ifm.Addrs&unix.RTA_IFP == 0 {
continue
}
dl := (*unix.RawSockaddrDatalink)(unsafe.Pointer(next + uintptr(rtm.Hdrlen)))
if dl.Family != unix.AF_LINK {
continue
}
data := ifm.Data
dev := int8ToString(dl.Data[:dl.Nlen])
if ignore != nil && ignore.MatchString(dev) {
level.Debug(logger).Log("msg", "Ignoring device", "device", dev)
continue
}
if accept != nil && !accept.MatchString(dev) {
level.Debug(logger).Log("msg", "Ignoring device", "device", dev)
continue
}
devStats := map[string]string{}
devStats["receive_packets"] = strconv.Itoa(int(data.Ipackets))
devStats["transmit_packets"] = strconv.Itoa(int(data.Opackets))
devStats["receive_errs"] = strconv.Itoa(int(data.Ierrors))
devStats["transmit_errs"] = strconv.Itoa(int(data.Oerrors))
devStats["receive_bytes"] = strconv.Itoa(int(data.Ibytes))
devStats["transmit_bytes"] = strconv.Itoa(int(data.Obytes))
devStats["receive_multicast"] = strconv.Itoa(int(data.Imcasts))
devStats["transmit_multicast"] = strconv.Itoa(int(data.Omcasts))
devStats["receive_drop"] = strconv.Itoa(int(data.Iqdrops))
netDev[dev] = devStats
}
return netDev, nil
}

View file

@ -0,0 +1,82 @@
// Copyright 2020 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 (
"golang.org/x/sys/unix"
"syscall"
"unsafe"
)
func int8ToString(a []int8) string {
b := make([]byte, len(a))
for i, v := range a {
b[i] = byte(v)
}
return string(b)
}
// unix._C_int
type _C_int int32
var _zero uintptr
func errnoErr(e syscall.Errno) error {
switch e {
case 0:
return nil
case unix.EAGAIN:
return syscall.EAGAIN
case unix.EINVAL:
return syscall.EINVAL
case unix.ENOENT:
return syscall.ENOENT
}
return e
}
func _sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) {
var _p0 unsafe.Pointer
if len(mib) > 0 {
_p0 = unsafe.Pointer(&mib[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
for {
_, _, e1 := unix.Syscall6(unix.SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
if e1 != 0 {
err = errnoErr(e1)
}
if err != unix.EINTR {
return
}
}
return
}
func sysctl(mib []_C_int) ([]byte, error) {
n := uintptr(0)
if err := _sysctl(mib, nil, &n, nil, 0); err != nil {
return nil, err
}
if n == 0 {
return nil, nil
}
buf := make([]byte, n)
if err := _sysctl(mib, &buf[0], &n, nil, 0); err != nil {
return nil, err
}
return buf[:n], nil
}