diff --git a/backend/.env b/backend/.env index 5ae0b8b..c5e8034 100644 --- a/backend/.env +++ b/backend/.env @@ -1,3 +1,3 @@ OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf -OTEL_EXPORTER_OTLP_HEADERS='authorization=590f929c-5368-460d-ac52-dad6eeab04f7' +# OTEL_EXPORTER_OTLP_HEADERS='authorization=590f929c-5368-460d-ac52-dad6eeab04f7' diff --git a/backend/internal/song/stream.go b/backend/internal/song/stream.go index 7bc6774..da27456 100644 --- a/backend/internal/song/stream.go +++ b/backend/internal/song/stream.go @@ -4,19 +4,16 @@ import ( "net/http" "os" "path/filepath" - "strings" - "echsen.club/radio/internal/user" + "echsen.club/radio/internal/otel" "github.com/google/uuid" + "go.opentelemetry.io/otel/codes" ) func (h *SongHandler) StreamSong(w http.ResponseWriter, r *http.Request) { - _, err := user.RequireUser(r.Context()) - if err != nil { - http.Error(w, "unauthorized", http.StatusUnauthorized) - return - } - songIDStr := strings.TrimPrefix(r.URL.Path, "/stream/song/") + rootSpan := otel.GetRootSpan(r.Context()) + songIDStr := r.PathValue("id") + songID, err := uuid.Parse(songIDStr) if err != nil { http.Error(w, "Invalid Song ID", http.StatusBadRequest) @@ -32,6 +29,8 @@ func (h *SongHandler) StreamSong(w http.ResponseWriter, r *http.Request) { fullPath := filepath.Join(h.config.SongDirectory, song.Filename) if _, err := os.Stat(fullPath); os.IsNotExist(err) { + rootSpan.RecordError(err) + rootSpan.SetStatus(codes.Error, "stream_song_failed") http.Error(w, "File missing on server", http.StatusNotFound) return } diff --git a/backend/internal/state/state.go b/backend/internal/state/state.go index af79fa8..eb959ab 100644 --- a/backend/internal/state/state.go +++ b/backend/internal/state/state.go @@ -19,6 +19,7 @@ import ( "echsen.club/radio/internal/user" "github.com/jmoiron/sqlx" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" + "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" ) @@ -92,10 +93,22 @@ func (state *State) RegisterHandlers() { state.mux.HandleFunc("/auth/login", state.oauth.LoginHandler) state.mux.HandleFunc("/auth/callback", state.oauth.CallbackHandler(state.handleAuthSuccess)) - state.mux.HandleFunc("/stream/song/", state.songHandler.StreamSong) + state.mux.HandleFunc(state.tracedHandler("GET /stream/song/{id}", state.songHandler.StreamSong)) state.mux.Handle(radiov1connect.NewChannelServiceHandler(state.channelHandler, connect.WithInterceptors(state.validateInterceptor, otelInterceptor))) state.mux.Handle(radiov1connect.NewSongServiceHandler(state.songHandler, connect.WithInterceptors(state.validateInterceptor, otelInterceptor))) state.mux.Handle(radiov1connect.NewUserServiceHandler(state.userHandler, connect.WithInterceptors(state.validateInterceptor, otelInterceptor))) } + +func (state *State) tracedHandler(pattern string, handler http.HandlerFunc) (string, http.HandlerFunc) { + return pattern, func(w http.ResponseWriter, r *http.Request) { + span := trace.SpanFromContext(r.Context()) + + if r.Pattern != "" { + span.SetAttributes(attribute.String("http.route", pattern)) + } + + handler(w, r) + } +} diff --git a/docker-compose.yaml b/docker-compose.yaml index afe1b52..53985e1 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -23,10 +23,18 @@ services: - "5556:5556" command: ["dex", "serve", "/etc/dex/config.yaml"] - clickstack: - image: clickhouse/clickstack-all-in-one:latest - container_name: radio_clickstack + # clickstack: + # image: clickhouse/clickstack-all-in-one:latest + # container_name: radio_clickstack + # ports: + # - "8081:8080" + # - "4317:4317" + # - "4318:4318" + + lgtm: + image: grafana/otel-lgtm + container_name: radio_lgtm ports: - - "8081:8080" + - "3000:3000" - "4317:4317" - "4318:4318"