github.com/Psiphon-Inc/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  }