github.com/aristanetworks/goarista@v0.0.0-20240514173732-cca2755bbd44/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  	"net"
    13  	"net/http"
    14  	_ "net/http/pprof" // Go documentation recommended usage
    15  
    16  	"github.com/aristanetworks/goarista/netns"
    17  
    18  	"github.com/aristanetworks/glog"
    19  )
    20  
    21  // Server represents a monitoring server
    22  type Server interface {
    23  	Run(serveMux *http.ServeMux)
    24  	Serve(serveMux *http.ServeMux) error
    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  	loglevel   *logsetSrv
    33  }
    34  
    35  // NewServer creates a new server struct
    36  func NewServer(address string) Server {
    37  	vrfName, addr, err := netns.ParseAddress(address)
    38  	if err != nil {
    39  		glog.Errorf("Failed to parse address: %s", err)
    40  	}
    41  	return &server{
    42  		vrfName:    vrfName,
    43  		serverName: addr,
    44  		loglevel:   newLogsetSrv(),
    45  	}
    46  }
    47  
    48  func debugHandler(w http.ResponseWriter, r *http.Request) {
    49  	indexTmpl := `<html>
    50  	<head>
    51  	<title>/debug</title>
    52  	</head>
    53  	<body>
    54  	<p>/debug</p>
    55  	<div><a href="/debug/vars">vars</a></div>
    56  	<div><a href="/debug/pprof">pprof</a></div>
    57  	</body>
    58  	</html>
    59  	`
    60  	fmt.Fprintf(w, indexTmpl)
    61  }
    62  
    63  // PrintableHistogram represents a Histogram that can be printed as
    64  // a chart.
    65  type PrintableHistogram interface {
    66  	Print() string
    67  }
    68  
    69  // Pretty prints the latency histograms
    70  func histogramHandler(w http.ResponseWriter, r *http.Request) {
    71  	expvar.Do(func(kv expvar.KeyValue) {
    72  		if hist, ok := kv.Value.(PrintableHistogram); ok {
    73  			w.Write([]byte(hist.Print()))
    74  		}
    75  	})
    76  }
    77  
    78  // Run calls Serve. On error the program exits.
    79  func (s *server) Run(serveMux *http.ServeMux) {
    80  	if err := s.Serve(serveMux); err != nil {
    81  		glog.Fatal(err)
    82  	}
    83  }
    84  
    85  // Serve registers handlers and starts serving.
    86  func (s *server) Serve(serveMux *http.ServeMux) error {
    87  	serveMux.HandleFunc("/debug", debugHandler)
    88  	serveMux.HandleFunc("/debug/histograms", histogramHandler)
    89  	// for example, to set glog verbosity to 5: curl localhost:6060/debug/loglevel?glog=5
    90  	serveMux.Handle("/debug/loglevel", s.loglevel)
    91  
    92  	var listener net.Listener
    93  	err := netns.Do(s.vrfName, func() error {
    94  		var err error
    95  		listener, err = net.Listen("tcp", s.serverName)
    96  		return err
    97  	})
    98  	if err != nil {
    99  		return fmt.Errorf("could not start monitor server in VRF %q: %s", s.vrfName, err)
   100  	}
   101  
   102  	return http.Serve(listener, serveMux)
   103  }