mirror of
https://gitea.com/Lydanne/buildx.git
synced 2025-07-13 06:57:09 +08:00
history: add UI view to traces
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
This commit is contained in:
172
vendor/github.com/tonistiigi/jaeger-ui-rest/server.go
generated
vendored
Normal file
172
vendor/github.com/tonistiigi/jaeger-ui-rest/server.go
generated
vendored
Normal file
@ -0,0 +1,172 @@
|
||||
package jaegerui
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func NewServer(cfg Config) *Server {
|
||||
mux := &http.ServeMux{}
|
||||
s := &Server{
|
||||
config: cfg,
|
||||
server: &http.Server{
|
||||
Handler: mux,
|
||||
},
|
||||
}
|
||||
|
||||
fsHandler := http.FileServer(FS(cfg))
|
||||
|
||||
mux.HandleFunc("GET /api/services", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte(`{"data": [], "total": 0}`))
|
||||
})
|
||||
mux.HandleFunc("GET /trace/", redirectRoot(fsHandler))
|
||||
mux.HandleFunc("GET /search", redirectRoot(fsHandler))
|
||||
|
||||
mux.HandleFunc("POST /api/traces/", func(w http.ResponseWriter, r *http.Request) {
|
||||
traceID := strings.TrimPrefix(r.URL.Path, "/api/traces/")
|
||||
if traceID == "" || strings.Contains(traceID, "/") {
|
||||
http.Error(w, "Invalid trace ID", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
handleHTTPError(s.AddTrace(traceID, r.Body), w)
|
||||
})
|
||||
|
||||
mux.HandleFunc("GET /api/traces/", func(w http.ResponseWriter, r *http.Request) {
|
||||
traceID := strings.TrimPrefix(r.URL.Path, "/api/traces/")
|
||||
if traceID == "" {
|
||||
qry := r.URL.Query()
|
||||
ids := qry["traceID"]
|
||||
if len(ids) > 0 {
|
||||
dt, err := s.GetTraces(ids...)
|
||||
if err != nil {
|
||||
handleHTTPError(err, w)
|
||||
return
|
||||
}
|
||||
w.Write(dt)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if traceID == "" || strings.Contains(traceID, "/") {
|
||||
http.Error(w, "Invalid trace ID", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
dt, err := s.GetTraces(traceID)
|
||||
if err != nil {
|
||||
handleHTTPError(err, w)
|
||||
return
|
||||
}
|
||||
w.Write(dt)
|
||||
})
|
||||
|
||||
mux.Handle("/", fsHandler)
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
config Config
|
||||
server *http.Server
|
||||
|
||||
mu sync.Mutex
|
||||
traces map[string][]byte
|
||||
}
|
||||
|
||||
func (s *Server) AddTrace(traceID string, rdr io.Reader) error {
|
||||
var payload struct {
|
||||
Data []struct {
|
||||
TraceID string `json:"traceID"`
|
||||
} `json:"data"`
|
||||
}
|
||||
buf := &bytes.Buffer{}
|
||||
if _, err := io.Copy(buf, rdr); err != nil {
|
||||
return errors.Wrapf(err, "failed to read trace data")
|
||||
}
|
||||
dt := buf.Bytes()
|
||||
|
||||
if err := json.Unmarshal(dt, &payload); err != nil {
|
||||
return errors.Wrapf(err, "failed to unmarshal trace data")
|
||||
}
|
||||
|
||||
if len(payload.Data) != 1 {
|
||||
return errors.Errorf("expected 1 trace, got %d", len(payload.Data))
|
||||
}
|
||||
|
||||
if payload.Data[0].TraceID != traceID {
|
||||
return errors.Errorf("trace ID mismatch: %s != %s", payload.Data[0].TraceID, traceID)
|
||||
}
|
||||
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
if s.traces == nil {
|
||||
s.traces = make(map[string][]byte)
|
||||
}
|
||||
s.traces[traceID] = dt
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) GetTraces(traceIDs ...string) ([]byte, error) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
if len(traceIDs) == 0 {
|
||||
return nil, errors.Errorf("trace ID is required")
|
||||
}
|
||||
|
||||
if len(traceIDs) == 1 {
|
||||
dt, ok := s.traces[traceIDs[0]]
|
||||
if !ok {
|
||||
return nil, errors.Wrapf(os.ErrNotExist, "trace %s not found", traceIDs[0])
|
||||
}
|
||||
return dt, nil
|
||||
}
|
||||
|
||||
type payloadT struct {
|
||||
Data []interface{} `json:"data"`
|
||||
}
|
||||
var payload payloadT
|
||||
|
||||
for _, traceID := range traceIDs {
|
||||
dt, ok := s.traces[traceID]
|
||||
if !ok {
|
||||
return nil, errors.Wrapf(os.ErrNotExist, "trace %s not found", traceID)
|
||||
}
|
||||
var p payloadT
|
||||
if err := json.Unmarshal(dt, &p); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to unmarshal trace data")
|
||||
}
|
||||
payload.Data = append(payload.Data, p.Data...)
|
||||
}
|
||||
|
||||
return json.MarshalIndent(payload, "", " ")
|
||||
}
|
||||
|
||||
func (s *Server) Serve(l net.Listener) error {
|
||||
return s.server.Serve(l)
|
||||
}
|
||||
|
||||
func redirectRoot(h http.Handler) func(w http.ResponseWriter, r *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
r.URL.Path = "/"
|
||||
h.ServeHTTP(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
func handleHTTPError(err error, w http.ResponseWriter) {
|
||||
switch {
|
||||
case err == nil:
|
||||
return
|
||||
case errors.Is(err, os.ErrNotExist):
|
||||
http.Error(w, err.Error(), http.StatusNotFound)
|
||||
default:
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user