mirror of
https://github.com/ClusterCockpit/cc-backend
synced 2024-12-26 05:19:05 +01:00
Add REST endpoint for metrics
This commit is contained in:
parent
32c32ba949
commit
1c1b043246
48
api/rest.go
48
api/rest.go
@ -43,6 +43,8 @@ func (api *RestApi) MountRoutes(r *mux.Router) {
|
|||||||
r.HandleFunc("/jobs/{id}", api.getJob).Methods(http.MethodGet)
|
r.HandleFunc("/jobs/{id}", api.getJob).Methods(http.MethodGet)
|
||||||
r.HandleFunc("/jobs/tag_job/{id}", api.tagJob).Methods(http.MethodPost, http.MethodPatch)
|
r.HandleFunc("/jobs/tag_job/{id}", api.tagJob).Methods(http.MethodPost, http.MethodPatch)
|
||||||
|
|
||||||
|
r.HandleFunc("/jobs/metrics/{id}", api.getJobMetrics).Methods(http.MethodGet)
|
||||||
|
|
||||||
if api.MachineStateDir != "" {
|
if api.MachineStateDir != "" {
|
||||||
r.HandleFunc("/machine_state/{cluster}/{host}", api.getMachineState).Methods(http.MethodGet)
|
r.HandleFunc("/machine_state/{cluster}/{host}", api.getMachineState).Methods(http.MethodGet)
|
||||||
r.HandleFunc("/machine_state/{cluster}/{host}", api.putMachineState).Methods(http.MethodPut, http.MethodPost)
|
r.HandleFunc("/machine_state/{cluster}/{host}", api.putMachineState).Methods(http.MethodPut, http.MethodPost)
|
||||||
@ -370,6 +372,52 @@ func (api *RestApi) stopJob(rw http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (api *RestApi) getJobMetrics(rw http.ResponseWriter, r *http.Request) {
|
||||||
|
id := mux.Vars(r)["id"]
|
||||||
|
metrics := r.URL.Query()["metric"]
|
||||||
|
var scopes []schema.MetricScope
|
||||||
|
for _, scope := range r.URL.Query()["scope"] {
|
||||||
|
var s schema.MetricScope
|
||||||
|
if err := s.UnmarshalGQL(scope); err != nil {
|
||||||
|
http.Error(rw, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
scopes = append(scopes, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
rw.Header().Add("Content-Type", "application/json")
|
||||||
|
rw.WriteHeader(http.StatusOK)
|
||||||
|
|
||||||
|
type Respone struct {
|
||||||
|
Data *struct {
|
||||||
|
JobMetrics []*model.JobMetricWithName `json:"jobMetrics"`
|
||||||
|
} `json:"data"`
|
||||||
|
Error *struct {
|
||||||
|
Message string `json:"message"`
|
||||||
|
} `json:"error"`
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := api.Resolver.Query().JobMetrics(r.Context(), id, metrics, scopes)
|
||||||
|
if err != nil {
|
||||||
|
if err := json.NewEncoder(rw).Encode(Respone{
|
||||||
|
Error: &struct {
|
||||||
|
Message string "json:\"message\""
|
||||||
|
}{Message: err.Error()},
|
||||||
|
}); err != nil {
|
||||||
|
log.Println(err.Error())
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.NewEncoder(rw).Encode(Respone{
|
||||||
|
Data: &struct {
|
||||||
|
JobMetrics []*model.JobMetricWithName "json:\"jobMetrics\""
|
||||||
|
}{JobMetrics: data},
|
||||||
|
}); err != nil {
|
||||||
|
log.Println(err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (api *RestApi) putMachineState(rw http.ResponseWriter, r *http.Request) {
|
func (api *RestApi) putMachineState(rw http.ResponseWriter, r *http.Request) {
|
||||||
if api.MachineStateDir == "" {
|
if api.MachineStateDir == "" {
|
||||||
http.Error(rw, "not enabled", http.StatusNotFound)
|
http.Error(rw, "not enabled", http.StatusNotFound)
|
||||||
|
@ -103,9 +103,9 @@ type Series {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type MetricStatistics {
|
type MetricStatistics {
|
||||||
avg: NullableFloat!
|
avg: Float!
|
||||||
min: NullableFloat!
|
min: Float!
|
||||||
max: NullableFloat!
|
max: Float!
|
||||||
}
|
}
|
||||||
|
|
||||||
type StatsSeries {
|
type StatsSeries {
|
||||||
|
@ -65,3 +65,41 @@ func (f Float) MarshalGQL(w io.Writer) {
|
|||||||
w.Write(strconv.AppendFloat(make([]byte, 0, 10), float64(f), 'f', 2, 64))
|
w.Write(strconv.AppendFloat(make([]byte, 0, 10), float64(f), 'f', 2, 64))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only used via REST-API, not via GraphQL.
|
||||||
|
// This uses a lot less allocations per series,
|
||||||
|
// but it turns out that the performance increase
|
||||||
|
// from using this is not that big.
|
||||||
|
func (s *Series) MarshalJSON() ([]byte, error) {
|
||||||
|
buf := make([]byte, 0, 512+len(s.Data)*8)
|
||||||
|
buf = append(buf, `{"hostname":"`...)
|
||||||
|
buf = append(buf, s.Hostname...)
|
||||||
|
buf = append(buf, '"')
|
||||||
|
if s.Id != nil {
|
||||||
|
buf = append(buf, `,"id":`...)
|
||||||
|
buf = strconv.AppendInt(buf, int64(*s.Id), 10)
|
||||||
|
}
|
||||||
|
if s.Statistics != nil {
|
||||||
|
buf = append(buf, `,"statistics":{"min":`...)
|
||||||
|
buf = strconv.AppendFloat(buf, s.Statistics.Min, 'f', 2, 64)
|
||||||
|
buf = append(buf, `,"avg":`...)
|
||||||
|
buf = strconv.AppendFloat(buf, s.Statistics.Avg, 'f', 2, 64)
|
||||||
|
buf = append(buf, `,"max":`...)
|
||||||
|
buf = strconv.AppendFloat(buf, s.Statistics.Max, 'f', 2, 64)
|
||||||
|
buf = append(buf, '}')
|
||||||
|
}
|
||||||
|
buf = append(buf, `,"data":[`...)
|
||||||
|
for i := 0; i < len(s.Data); i++ {
|
||||||
|
if i != 0 {
|
||||||
|
buf = append(buf, ',')
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.Data[i].IsNaN() {
|
||||||
|
buf = append(buf, `null`...)
|
||||||
|
} else {
|
||||||
|
buf = strconv.AppendFloat(buf, float64(s.Data[i]), 'f', 2, 32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buf = append(buf, ']', '}')
|
||||||
|
return buf, nil
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user