Initial commit: stats-gateway gRPC service + dashboard + CLI
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
|
||||
statsv1 "github.com/bergabruh/stats-gateway/gen/stats/v1"
|
||||
)
|
||||
|
||||
func Aggregate(args []string) {
|
||||
fs := flag.NewFlagSet("aggregate", flag.ExitOnError)
|
||||
server := fs.String("server", "stats.projectshitpost.fun:443", "gRPC endpoint host:port")
|
||||
node := fs.String("node", "", "fl|pl1 (empty = both)")
|
||||
since := fs.String("since", "", "RFC3339 lower bound (defaults to 24h ago)")
|
||||
until := fs.String("until", "", "RFC3339 upper bound (defaults to now)")
|
||||
timeout := fs.Duration("timeout", 10*time.Second, "")
|
||||
fs.Parse(args)
|
||||
|
||||
if *since == "" {
|
||||
// Default to 24h ago for convenience.
|
||||
*since = time.Now().UTC().Add(-24 * time.Hour).Format(time.RFC3339)
|
||||
}
|
||||
|
||||
conn, err := grpc.NewClient(*server,
|
||||
grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{})))
|
||||
if err != nil {
|
||||
log.Fatalf("dial: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
client := statsv1.NewSpeedStatusClient(conn)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), *timeout)
|
||||
defer cancel()
|
||||
|
||||
hist, err := client.Aggregate(ctx, &statsv1.Range{
|
||||
Node: *node,
|
||||
Since: *since,
|
||||
Until: *until,
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatalf("Aggregate: %v", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Histogram of HTTP latency (ms) — node=%q since=%s\n", *node, *since)
|
||||
for _, b := range hist.Buckets {
|
||||
bar := ""
|
||||
if b.Count > 0 {
|
||||
n := int(b.Count)
|
||||
if n > 60 {
|
||||
n = 60
|
||||
}
|
||||
bar = strings.Repeat("#", n)
|
||||
}
|
||||
fmt.Printf(" <= %6.0fms %5d %s\n", b.UpperMs, b.Count, bar)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
|
||||
statsv1 "github.com/bergabruh/stats-gateway/gen/stats/v1"
|
||||
)
|
||||
|
||||
func Recent(args []string) {
|
||||
fs := flag.NewFlagSet("recent", flag.ExitOnError)
|
||||
server := fs.String("server", "stats.projectshitpost.fun:443", "gRPC endpoint host:port")
|
||||
node := fs.String("node", "", "fl|pl1 (empty = both)")
|
||||
limit := fs.Int("limit", 20, "max samples (1..1000)")
|
||||
since := fs.String("since", "", "RFC3339 lower bound (optional)")
|
||||
timeout := fs.Duration("timeout", 10*time.Second, "")
|
||||
fs.Parse(args)
|
||||
|
||||
conn, err := grpc.NewClient(*server,
|
||||
grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{})))
|
||||
if err != nil {
|
||||
log.Fatalf("dial: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
client := statsv1.NewSpeedStatusClient(conn)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), *timeout)
|
||||
defer cancel()
|
||||
|
||||
stream, err := client.RecentResults(ctx, &statsv1.Filter{
|
||||
Node: *node,
|
||||
Limit: int32(*limit),
|
||||
Since: *since,
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatalf("RecentResults: %v", err)
|
||||
}
|
||||
|
||||
count := 0
|
||||
for {
|
||||
s, err := stream.Recv()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "recv: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("%s %-3s http=%6.1fms tls=%6.1fms tcp=%6.1fms dns=%5.1fms\n",
|
||||
s.Timestamp, s.Node, s.HttpLatencyMs, s.TlsHandshakeMs, s.TcpRttMs, s.DnsResolveMs)
|
||||
count++
|
||||
}
|
||||
if count == 0 {
|
||||
fmt.Fprintln(os.Stderr, "(no samples)")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user