infrastructure/cdn-in-a-box/varnish/vstats.go (80 lines of code) (raw):
package main
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import (
"encoding/json"
"flag"
"fmt"
"log"
"net/http"
"os"
"os/exec"
"strconv"
"strings"
)
type vstats struct {
ProcLoadavg string `json:"proc.loadavg"`
ProcNetDev string `json:"proc.net.dev"`
InfSpeed int64 `json:"inf_speed"`
NotAvailable bool `json:"not_available"`
// TODO: stats
}
func getSystemData(inf string) vstats {
var vstats vstats
loadavg, err := os.ReadFile("/proc/loadavg")
if err != nil {
log.Printf("failed to read /proc/loadavg: %s\n", err)
}
vstats.ProcLoadavg = strings.TrimSpace(string(loadavg))
procNetDev, err := os.ReadFile("/proc/net/dev")
if err != nil {
log.Printf("failed to read /proc/net/dev: %s\n", err)
}
parts := strings.Split(string(procNetDev), "\n")
for _, line := range parts {
if strings.HasPrefix(strings.TrimSpace(line), inf) {
vstats.ProcNetDev = strings.TrimSpace(line)
break
}
}
infSpeedFile := fmt.Sprintf("/sys/class/net/%s/speed", inf)
speedStr, err := os.ReadFile(infSpeedFile)
if err != nil {
log.Printf("failed to read %s: %s\n", infSpeedFile, err)
}
speed, err := strconv.ParseInt(strings.TrimSpace(string(speedStr)), 10, 64)
if err != nil {
log.Printf("failed to convert speed '%s' to int: %s\n", speedStr, err)
}
vstats.InfSpeed = speed
cmd := exec.Command("systemctl", "status", "varnish.service")
err = cmd.Run()
if err != nil {
log.Printf("failed to run systemctl: %s\n", err)
}
if cmd.ProcessState.ExitCode() != 0 {
vstats.NotAvailable = true
}
return vstats
}
func getStats(w http.ResponseWriter, r *http.Request) {
inf := r.URL.Query().Get("inf.name")
if inf == "" {
// assume default eth0?
inf = "eth0"
}
inf = strings.ReplaceAll(inf, ".", "")
inf = strings.ReplaceAll(inf, "/", "")
vstats := getSystemData(inf)
encoder := json.NewEncoder(w)
err := encoder.Encode(vstats)
if err != nil {
log.Printf("failed to write Varnish stats: %s", err)
}
}
func main() {
var port int
flag.IntVar(&port, "port", 2000, "port to run vstats on")
flag.Parse()
http.HandleFunc("/", getStats)
listenAddress := fmt.Sprintf(":%d", port)
if err := http.ListenAndServe(listenAddress, nil); err != nil {
log.Printf("server stopped %s", err)
}
}