github.com/Psiphon-Labs/goarista@v0.0.0-20160825065156-d002785f4c67/monitor/server.go (about) 1 // Copyright (C) 2015 Arista Networks, Inc. 2 // Use of this source code is governed by the Apache License 2.0 3 // that can be found in the COPYING file. 4 5 // Package monitor provides an embedded HTTP server to expose 6 // metrics for monitoring 7 package monitor 8 9 import ( 10 "expvar" 11 "fmt" 12 "html/template" 13 "net" 14 "net/http" 15 _ "net/http/pprof" // Go documentation recommended usage 16 "strings" 17 18 "github.com/aristanetworks/glog" 19 "github.com/aristanetworks/goarista/netns" 20 ) 21 22 // Server represents a monitoring server 23 type Server interface { 24 Run() 25 } 26 27 // server contains information for the monitoring server 28 type server struct { 29 vrfName string 30 // Server name e.g. host[:port] 31 serverName string 32 } 33 34 // NewServer creates a new server struct 35 func NewServer(address string) Server { 36 vrfName, addr, err := netns.ParseAddress(address) 37 if err != nil { 38 glog.Errorf("Failed to parse address: %s", err) 39 } 40 return &server{ 41 vrfName: vrfName, 42 serverName: addr, 43 } 44 } 45 46 func debugHandler(w http.ResponseWriter, r *http.Request) { 47 indexTmpl := `<html> 48 <head> 49 <title>/debug</title> 50 </head> 51 <body> 52 <p>/debug</p> 53 <div><a href="/debug/vars">vars</a></div> 54 <div><a href="/debug/pprof">pprof</a></div> 55 </body> 56 </html> 57 ` 58 fmt.Fprintf(w, indexTmpl) 59 } 60 61 // Pretty prints the latency histograms 62 func latencyHandler(w http.ResponseWriter, r *http.Request) { 63 expvar.Do(func(kv expvar.KeyValue) { 64 if strings.HasSuffix(kv.Key, "Histogram") { 65 template.Must(template.New("latency").Parse( 66 `<html> 67 <head> 68 <title>/debug/latency</title> 69 </head> 70 <body> 71 <pre>{{.}}</pre> 72 </body> 73 </html> 74 `)).Execute(w, template.HTML(strings.Replace(kv.Value.String(), "\\n", "<br />", -1))) 75 } 76 }) 77 } 78 79 // Run sets up the HTTP server and any handlers 80 func (s *server) Run() { 81 http.HandleFunc("/debug", debugHandler) 82 http.HandleFunc("/debug/latency", latencyHandler) 83 84 var listener net.Listener 85 var listenErr error 86 err := netns.Do(s.vrfName, func() { 87 listener, listenErr = net.Listen("tcp", s.serverName) 88 }) 89 if err != nil { 90 glog.Fatalf("Failed to go to network namespace for vrf %s: %s", s.vrfName, err) 91 } 92 if listenErr != nil { 93 glog.Fatal("Could not start monitor server:", listenErr) 94 } 95 96 err = http.Serve(listener, nil) 97 if err != nil { 98 glog.Fatal("http serve returned with error:", err) 99 } 100 }