Add tracing
This commit is contained in:
@@ -1,10 +1,13 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/go-chi/chi/v5/middleware"
|
||||
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
func (s *Server) MiddlewareLogging(next http.Handler) http.Handler {
|
||||
@@ -28,3 +31,14 @@ func (s *Server) MiddlewareLogging(next http.Handler) http.Handler {
|
||||
}
|
||||
return http.HandlerFunc(fn)
|
||||
}
|
||||
|
||||
func (s *Server) MiddlewareTracing(next http.Handler) http.Handler {
|
||||
fn := func(w http.ResponseWriter, r *http.Request) {
|
||||
span := trace.SpanFromContext(r.Context())
|
||||
span.AddEvent("event")
|
||||
|
||||
h := otelhttp.NewHandler(next, fmt.Sprintf("%s %s", r.Method, r.URL.Path))
|
||||
h.ServeHTTP(w, r)
|
||||
}
|
||||
return http.HandlerFunc(fn)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
@@ -19,6 +20,13 @@ import (
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
"github.com/google/uuid"
|
||||
"github.com/nats-io/nats.go"
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
|
||||
"go.opentelemetry.io/otel/propagation"
|
||||
"go.opentelemetry.io/otel/sdk/resource"
|
||||
sdktrace "go.opentelemetry.io/otel/sdk/trace"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.21.0"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
const DefaultTokenDuration time.Duration = 24 * time.Hour
|
||||
@@ -38,10 +46,17 @@ type Server struct {
|
||||
func NewServer(config *Config) (*Server, error) {
|
||||
srv := &Server{}
|
||||
|
||||
tp, err := tracerProvider("jaeger:4318")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
otel.SetTracerProvider(tp)
|
||||
|
||||
r := chi.NewRouter()
|
||||
|
||||
r.Use(middleware.RequestID)
|
||||
r.Use(srv.MiddlewareLogging)
|
||||
r.Use(srv.MiddlewareTracing)
|
||||
|
||||
r.Get("/key", srv.PubkeyHandler)
|
||||
r.Post("/{id}/token", srv.TokenHandler)
|
||||
@@ -79,6 +94,26 @@ func NewServer(config *Config) (*Server, error) {
|
||||
return srv, nil
|
||||
}
|
||||
|
||||
func tracerProvider(url string) (*sdktrace.TracerProvider, error) {
|
||||
exp, err := otlptracehttp.New(context.Background(), otlptracehttp.WithEndpoint(url), otlptracehttp.WithInsecure())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res := resource.NewWithAttributes(semconv.SchemaURL,
|
||||
semconv.ServiceName("mf-auth"),
|
||||
semconv.ServiceVersion(auth.Version),
|
||||
)
|
||||
tp := sdktrace.NewTracerProvider(
|
||||
sdktrace.WithBatcher(exp, sdktrace.WithBatchTimeout(time.Second)),
|
||||
sdktrace.WithResource(res),
|
||||
)
|
||||
otel.SetTracerProvider(tp)
|
||||
otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))
|
||||
|
||||
return tp, nil
|
||||
}
|
||||
|
||||
func InfoHandler(w http.ResponseWriter, r *http.Request) {
|
||||
enc := json.NewEncoder(w)
|
||||
|
||||
@@ -96,6 +131,9 @@ func WriteError(w http.ResponseWriter, response auth.ErrorResponse) {
|
||||
}
|
||||
|
||||
func (s *Server) PubkeyHandler(w http.ResponseWriter, r *http.Request) {
|
||||
span := trace.SpanFromContext(r.Context())
|
||||
|
||||
span.AddEvent("Start marshalling public key.")
|
||||
enc := json.NewEncoder(w)
|
||||
key, err := x509.MarshalPKIXPublicKey(s.signingKey.Public())
|
||||
if err != nil {
|
||||
@@ -106,6 +144,7 @@ func (s *Server) PubkeyHandler(w http.ResponseWriter, r *http.Request) {
|
||||
})
|
||||
return
|
||||
}
|
||||
span.AddEvent("Finished marshalling public key.")
|
||||
response := auth.PubkeyResponse{
|
||||
PubKey: key,
|
||||
}
|
||||
@@ -114,6 +153,7 @@ func (s *Server) PubkeyHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func (s *Server) TokenHandler(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
decoder := json.NewDecoder(r.Body)
|
||||
defer r.Body.Close()
|
||||
|
||||
@@ -135,7 +175,7 @@ func (s *Server) TokenHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if err := s.userClient.VerifyUserPassword(userIdentifier, request.Password); err != nil {
|
||||
if err := s.userClient.VerifyUserPassword(ctx, userIdentifier, request.Password); err != nil {
|
||||
WriteError(w, auth.ErrorResponse{
|
||||
Status: http.StatusUnauthorized,
|
||||
Message: fmt.Sprintf("Unable to verify password: %s", err),
|
||||
@@ -143,7 +183,7 @@ func (s *Server) TokenHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
u, err := s.userClient.GetUser(userIdentifier)
|
||||
u, err := s.userClient.GetUser(ctx, userIdentifier)
|
||||
if err != nil {
|
||||
WriteError(w, auth.ErrorResponse{
|
||||
Status: http.StatusUnauthorized,
|
||||
|
||||
@@ -9,20 +9,31 @@ import (
|
||||
"time"
|
||||
|
||||
"git.t-juice.club/microfilm/users"
|
||||
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
|
||||
"go.opentelemetry.io/otel"
|
||||
)
|
||||
|
||||
type UserClient struct {
|
||||
BaseURL string
|
||||
client *http.Client
|
||||
}
|
||||
|
||||
const defaultTimeout time.Duration = 5 * time.Second
|
||||
|
||||
func NewUserClient(baseurl string) *UserClient {
|
||||
return &UserClient{BaseURL: baseurl}
|
||||
return &UserClient{
|
||||
BaseURL: baseurl,
|
||||
client: &http.Client{
|
||||
Transport: otelhttp.NewTransport(http.DefaultTransport),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (c *UserClient) VerifyUserPassword(username, password string) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
|
||||
func (c *UserClient) VerifyUserPassword(ctx context.Context, username, password string) error {
|
||||
ctx, span := otel.GetTracerProvider().Tracer("").Start(ctx, "verify-user-password")
|
||||
defer span.End()
|
||||
|
||||
ctx, cancel := context.WithTimeout(ctx, defaultTimeout)
|
||||
defer cancel()
|
||||
|
||||
url := fmt.Sprintf("%s/%s/verify", c.BaseURL, username)
|
||||
@@ -42,12 +53,11 @@ func (c *UserClient) VerifyUserPassword(username, password string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
client := http.Client{}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
resp, err := c.client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("authentication failed")
|
||||
@@ -56,10 +66,13 @@ func (c *UserClient) VerifyUserPassword(username, password string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *UserClient) GetUser(identifier string) (users.User, error) {
|
||||
func (c *UserClient) GetUser(ctx context.Context, identifier string) (users.User, error) {
|
||||
var u users.User
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
|
||||
ctx, span := otel.GetTracerProvider().Tracer("").Start(ctx, "get-user")
|
||||
defer span.End()
|
||||
|
||||
ctx, cancel := context.WithTimeout(ctx, defaultTimeout)
|
||||
defer cancel()
|
||||
|
||||
url := fmt.Sprintf("%s/%s", c.BaseURL, identifier)
|
||||
@@ -69,9 +82,7 @@ func (c *UserClient) GetUser(identifier string) (users.User, error) {
|
||||
return u, err
|
||||
}
|
||||
|
||||
client := http.Client{}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
resp, err := c.client.Do(req)
|
||||
if err != nil {
|
||||
return u, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user