Export metrics via prometheus.
This commit is contained in:
parent
10ab91179b
commit
e7d568551f
@ -6,27 +6,51 @@ import (
|
|||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
|
|
||||||
"golang.org/x/crypto/ssh"
|
"golang.org/x/crypto/ssh"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
host = flag.String("host", "localhost:22", "host:port to scp from")
|
addr = flag.String("addr", "localhost:9999", "HTTP listen address for prometheus /metrics")
|
||||||
user = flag.String("user", os.Getenv("USER"), "ssh user")
|
host = flag.String("host", "localhost:22", "host:port to scp from")
|
||||||
|
refreshInterval = flag.Duration("refresh", 5*time.Minute, "refresh interval time")
|
||||||
|
user = flag.String("user", os.Getenv("USER"), "ssh user")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const snapshotListCmd = "/sbin/zfs list -t snapshot -H -o name -s name"
|
||||||
|
|
||||||
// Example: @auto-20171001.1400-2w
|
// Example: @auto-20171001.1400-2w
|
||||||
var (
|
var (
|
||||||
snapshotPattern = regexp.MustCompile(`^([^@]+)@auto-(\d{8}\.\d{4})-\d+[mwy]$`)
|
snapshotPattern = regexp.MustCompile(`^([^@]+)@auto-(\d{8}\.\d{4})-\d+[mwy]$`)
|
||||||
snapshotFormat = "20060102.1504"
|
snapshotFormat = "20060102.1504"
|
||||||
|
|
||||||
|
fetchRequestDurationMetric = prometheus.NewGauge(prometheus.GaugeOpts{
|
||||||
|
Name: "ssh_fetch_duration_seconds",
|
||||||
|
Help: "Time to fetch and parse snapshot age over SSH",
|
||||||
|
})
|
||||||
|
snapshotAgesMetric = prometheus.NewGaugeVec(
|
||||||
|
prometheus.GaugeOpts{
|
||||||
|
Name: "zfs_snapshot_age_seconds",
|
||||||
|
Help: "Duration in seconds for most recent snapshot for `filesystem`",
|
||||||
|
},
|
||||||
|
[]string{"filesystem"},
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
prometheus.MustRegister(fetchRequestDurationMetric)
|
||||||
|
prometheus.MustRegister(snapshotAgesMetric)
|
||||||
|
}
|
||||||
|
|
||||||
func newPublicKey() ([]ssh.AuthMethod, error) {
|
func newPublicKey() ([]ssh.AuthMethod, error) {
|
||||||
var signers []ssh.AuthMethod
|
var signers []ssh.AuthMethod
|
||||||
|
|
||||||
@ -61,40 +85,25 @@ func newPublicKey() ([]ssh.AuthMethod, error) {
|
|||||||
return signers, nil
|
return signers, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func updateMetrics(c *ssh.Client) error {
|
||||||
flag.Parse()
|
now := time.Now()
|
||||||
defer glog.Flush()
|
defer func() {
|
||||||
|
delta := time.Since(now)
|
||||||
ams, err := newPublicKey()
|
fetchRequestDurationMetric.Set(delta.Seconds())
|
||||||
if err != nil {
|
glog.V(2).Infof("Update took %s", delta)
|
||||||
glog.Exitf("Error fetching public keys: %v", err)
|
}()
|
||||||
}
|
|
||||||
|
|
||||||
// An SSH client is represented with a ClientConn.
|
|
||||||
//
|
|
||||||
// To authenticate with the remote server you must pass at least one
|
|
||||||
// implementation of ClientAuth via the Auth field in ClientConfig.
|
|
||||||
config := &ssh.ClientConfig{
|
|
||||||
User: *user,
|
|
||||||
Auth: ams,
|
|
||||||
// TODO(wathiede); use FixedHostKey?
|
|
||||||
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
|
|
||||||
}
|
|
||||||
client, err := ssh.Dial("tcp", *host, config)
|
|
||||||
if err != nil {
|
|
||||||
glog.Exitf("Error dialing %q: %v", *host, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Each ClientConn can support multiple interactive sessions,
|
// Each ClientConn can support multiple interactive sessions,
|
||||||
// represented by a Session.
|
// represented by a Session.
|
||||||
s, err := client.NewSession()
|
s, err := c.NewSession()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Exitf("Error creating new session: %v", err)
|
return fmt.Errorf("error creating new session: %v", err)
|
||||||
}
|
}
|
||||||
cmd := "/sbin/zfs list -t snapshot -H -o name -s name"
|
defer s.Close()
|
||||||
b, err := s.CombinedOutput(cmd)
|
|
||||||
|
glog.V(2).Infof("Running %q", snapshotListCmd)
|
||||||
|
b, err := s.CombinedOutput(snapshotListCmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Exitf("Error running %q: %v", cmd, err)
|
return fmt.Errorf("error running %q: %v", snapshotListCmd, err)
|
||||||
}
|
}
|
||||||
scanner := bufio.NewScanner(bytes.NewReader(b))
|
scanner := bufio.NewScanner(bytes.NewReader(b))
|
||||||
snapshotAges := map[string]time.Time{}
|
snapshotAges := map[string]time.Time{}
|
||||||
@ -115,9 +124,49 @@ func main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := scanner.Err(); err != nil {
|
if err := scanner.Err(); err != nil {
|
||||||
glog.Exitf("Failed to scan response: %v", err)
|
return fmt.Errorf("failed to scan response: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for snapshot, snapshotTime := range snapshotAges {
|
for snapshot, snapshotTime := range snapshotAges {
|
||||||
fmt.Println(snapshot, snapshotTime, time.Since(snapshotTime))
|
snapshotAgesMetric.WithLabelValues(snapshot).Set(now.Sub(snapshotTime).Seconds())
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
flag.Parse()
|
||||||
|
defer glog.Flush()
|
||||||
|
|
||||||
|
ams, err := newPublicKey()
|
||||||
|
if err != nil {
|
||||||
|
glog.Exitf("Error fetching public keys: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// An SSH client is represented with a ClientConn.
|
||||||
|
//
|
||||||
|
// To authenticate with the remote server you must pass at least one
|
||||||
|
// implementation of ClientAuth via the Auth field in ClientConfig.
|
||||||
|
config := &ssh.ClientConfig{
|
||||||
|
User: *user,
|
||||||
|
Auth: ams,
|
||||||
|
// TODO(wathiede); use FixedHostKey?
|
||||||
|
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
|
||||||
|
}
|
||||||
|
c, err := ssh.Dial("tcp", *host, config)
|
||||||
|
if err != nil {
|
||||||
|
glog.Exitf("Error dialing %q: %v", *host, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
if err := updateMetrics(c); err != nil {
|
||||||
|
glog.Errorf("Failed to update metrics: %v", err)
|
||||||
|
}
|
||||||
|
time.Sleep(*refreshInterval)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Expose the registered metrics via HTTP.
|
||||||
|
http.Handle("/metrics", promhttp.Handler())
|
||||||
|
glog.Exitf("Failed to ListenAndServe: %v", http.ListenAndServe(*addr, nil))
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user