github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/syz-verifier/monitoring_api.go (about)

     1  // Copyright 2021 syzkaller project authors. All rights reserved.
     2  // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
     3  
     4  package main
     5  
     6  import (
     7  	"encoding/json"
     8  	"net/http"
     9  	"time"
    10  )
    11  
    12  // Monitor provides http based data for the syz-verifier monitoring.
    13  // TODO: Add tests to monitoring_api.
    14  type Monitor struct {
    15  	externalStats *Stats
    16  }
    17  
    18  // MakeMonitor creates the Monitor instance.
    19  func MakeMonitor() *Monitor {
    20  	instance := &Monitor{}
    21  	instance.initHTTPHandlers()
    22  	return instance
    23  }
    24  
    25  // ListenAndServe starts the server.
    26  func (monitor *Monitor) ListenAndServe(addr string) error {
    27  	return http.ListenAndServe(addr, nil)
    28  }
    29  
    30  // SetStatsTracking points Monitor to the Stats object to monitor.
    31  func (monitor *Monitor) SetStatsTracking(s *Stats) {
    32  	monitor.externalStats = s
    33  }
    34  
    35  // InitHTTPHandlers initializes the API routing.
    36  func (monitor *Monitor) initHTTPHandlers() {
    37  	http.Handle("/api/stats.json", jsonResponse(monitor.renderStats))
    38  
    39  	http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
    40  		writer.Write([]byte("<a href='api/stats.json'>stats_json</a>"))
    41  	})
    42  }
    43  
    44  // statsJSON provides information for the "/api/stats.json" render.
    45  type statsJSON struct {
    46  	StartTime           time.Time
    47  	TotalCallMismatches uint64
    48  	TotalProgs          uint64
    49  	ExecErrorProgs      uint64
    50  	FlakyProgs          uint64
    51  	MismatchingProgs    uint64
    52  	AverExecSpeed       uint64
    53  }
    54  
    55  // renderStats renders the statsJSON object.
    56  func (monitor *Monitor) renderStats() interface{} {
    57  	stats := monitor.externalStats
    58  
    59  	return &statsJSON{
    60  		StartTime:           stats.StartTime.Get(),
    61  		TotalCallMismatches: stats.TotalCallMismatches.Get(),
    62  		TotalProgs:          stats.TotalProgs.Get(),
    63  		ExecErrorProgs:      stats.ExecErrorProgs.Get(),
    64  		FlakyProgs:          stats.FlakyProgs.Get(),
    65  		MismatchingProgs:    stats.MismatchingProgs.Get(),
    66  		AverExecSpeed:       60 * stats.TotalProgs.Get() / uint64(1+time.Since(stats.StartTime.Get()).Seconds()),
    67  	}
    68  }
    69  
    70  // jsonResponse provides general response forming logic.
    71  func jsonResponse(getData func() interface{}) http.Handler {
    72  	return http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
    73  		w.Header().Set("Content-Type", "application/json")
    74  
    75  		data := getData()
    76  		json, err := json.MarshalIndent(
    77  			data,
    78  			"",
    79  			"\t",
    80  		)
    81  		if err != nil {
    82  			http.Error(w, err.Error(), 500) // Internal Server Error.
    83  			return
    84  		}
    85  
    86  		w.Write(json)
    87  	})
    88  }