Skip to content

Instantly share code, notes, and snippets.

@jingkaihe
Created April 27, 2023 08:47
Show Gist options
  • Save jingkaihe/1775eb7f12778aa808e31d5dd227bdfd to your computer and use it in GitHub Desktop.
Save jingkaihe/1775eb7f12778aa808e31d5dd227bdfd to your computer and use it in GitHub Desktop.
package main
import (
"bufio"
"context"
"io"
"log"
"net/http"
"os"
"regexp"
"syscall"
"time"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
var (
oopsCounter = prometheus.NewCounterVec(prometheus.CounterOpts{
Name: "kernel_oops_total",
Help: "Total number of kernel oops",
},
// XXX: kernel/sys metadata can probably be grouped lefted with kube_node_info or node exporter
// metrics, but here we go..
[]string{"kernel_version", "kernel_release"},
)
oopsPattern = regexp.MustCompile(`kernel: \[.*\] Oops: \d+`)
kernelVersion string
kernelRelease string
)
func init() {
prometheus.MustRegister(oopsCounter)
}
func initInventory() error {
var (
uname syscall.Utsname
int8ToStr = func(arr []int8) string {
b := make([]byte, 0, len(arr))
for _, c := range arr {
if c == 0 {
break
}
b = append(b, byte(c))
}
return string(b)
}
)
if err := syscall.Uname(&uname); err != nil {
return err
}
kernelRelease = int8ToStr(uname.Release[:])
kernelVersion = int8ToStr(uname.Version[:])
log.Printf("kernel release: %s, kernel version: %s\n", kernelRelease, kernelVersion)
return nil
}
func oopsWatch(ctx context.Context) error {
f, err := os.Open("/var/log/kern.log")
if err != nil {
return err
}
defer f.Close()
f.Seek(0, 2)
r := bufio.NewReader(f)
for {
select {
case <-ctx.Done():
return nil
default:
line, err := r.ReadString('\n')
if err != nil {
if err == io.EOF {
<-time.After(1 * time.Second)
continue
}
}
if oopsPattern.MatchString(line) {
oopsCounter.With(prometheus.Labels{
"kernel_version": kernelVersion,
"kernel_release": kernelRelease,
}).Inc()
}
}
}
}
func main() {
ctx := context.Background()
if err := initInventory(); err != nil {
log.Fatal(err)
}
go func() {
if err := oopsWatch(ctx); err != nil {
log.Fatal(err)
}
}()
http.Handle("/metrics", promhttp.Handler())
log.Fatal(http.ListenAndServe(":8080", nil))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment