mirror of
https://github.com/weaveworks/scope.git
synced 2026-03-04 10:41:14 +00:00
137 lines
2.9 KiB
Go
137 lines
2.9 KiB
Go
package main
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"log"
|
|
"net"
|
|
"net/http"
|
|
"os"
|
|
"os/exec"
|
|
"os/signal"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
func main() {
|
|
hostname, _ := os.Hostname()
|
|
var (
|
|
addr = flag.String("addr", "/var/run/scope/plugins/iowait.sock", "unix socket to listen for connections on")
|
|
hostID = flag.String("hostname", hostname, "hostname of the host running this plugin")
|
|
)
|
|
flag.Parse()
|
|
|
|
log.Printf("Starting on %s...\n", *hostID)
|
|
|
|
// Check we can get the iowait for the system
|
|
_, err := iowait()
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
os.Remove(*addr)
|
|
interrupt := make(chan os.Signal, 1)
|
|
signal.Notify(interrupt, os.Interrupt)
|
|
go func() {
|
|
<-interrupt
|
|
os.Remove(*addr)
|
|
os.Exit(0)
|
|
}()
|
|
|
|
listener, err := net.Listen("unix", *addr)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
defer func() {
|
|
listener.Close()
|
|
os.Remove(*addr)
|
|
}()
|
|
|
|
log.Printf("Listening on: unix://%s", *addr)
|
|
|
|
plugin := &Plugin{HostID: *hostID}
|
|
http.HandleFunc("/report", plugin.Report)
|
|
if err := http.Serve(listener, nil); err != nil {
|
|
log.Printf("error: %v", err)
|
|
}
|
|
}
|
|
|
|
// Plugin groups the methods a plugin needs
|
|
type Plugin struct {
|
|
HostID string
|
|
}
|
|
|
|
// Report is called by scope when a new report is needed. It is part of the
|
|
// "reporter" interface, which all plugins must implement.
|
|
func (p *Plugin) Report(w http.ResponseWriter, r *http.Request) {
|
|
log.Println(r.URL.String())
|
|
now := time.Now()
|
|
nowISO := now.Format(time.RFC3339)
|
|
value, err := iowait()
|
|
if err != nil {
|
|
log.Printf("error: %v", err)
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
fmt.Fprintf(w, `{
|
|
"Host": {
|
|
"nodes": {
|
|
%q: {
|
|
"metrics": {
|
|
"iowait": {
|
|
"samples": [ {"date": %q, "value": %f} ],
|
|
"min": 0,
|
|
"max": 100
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"metric_templates": {
|
|
"iowait": {
|
|
"id": "iowait",
|
|
"label": "IO Wait",
|
|
"format": "percent",
|
|
"priority": 0.1
|
|
}
|
|
}
|
|
},
|
|
"Plugins": [
|
|
{
|
|
"id": "iowait",
|
|
"label": "iowait",
|
|
"description": "Adds a graph of CPU IO Wait to hosts",
|
|
"interfaces": ["reporter"],
|
|
"api_version": "1"
|
|
}
|
|
]
|
|
}`, p.HostID+";<host>", nowISO, value)
|
|
if err != nil {
|
|
log.Printf("error: %v", err)
|
|
}
|
|
}
|
|
|
|
// Get the latest iowait value
|
|
func iowait() (float64, error) {
|
|
out, err := exec.Command("iostat", "-c").Output()
|
|
if err != nil {
|
|
return 0, fmt.Errorf("iowait: %v", err)
|
|
}
|
|
|
|
// Linux 4.2.0-25-generic (a109563eab38) 04/01/16 _x86_64_(4 CPU)
|
|
//
|
|
// avg-cpu: %user %nice %system %iowait %steal %idle
|
|
// 2.37 0.00 1.58 0.01 0.00 96.04
|
|
lines := strings.Split(string(out), "\n")
|
|
if len(lines) < 4 {
|
|
return 0, fmt.Errorf("iowait: unexpected output: %q", out)
|
|
}
|
|
|
|
values := strings.Fields(lines[3])
|
|
if len(values) != 6 {
|
|
return 0, fmt.Errorf("iowait: unexpected output: %q", out)
|
|
}
|
|
|
|
return strconv.ParseFloat(values[3], 64)
|
|
}
|