Skip to content

Commit

Permalink
feat(core): contextual information
Browse files Browse the repository at this point in the history
  • Loading branch information
ConsoleTVs committed Aug 6, 2024
1 parent 7657791 commit 7c94d30
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 50 deletions.
71 changes: 29 additions & 42 deletions builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"bytes"
"encoding/json"
"io"
"log/slog"
"net/http"
)

Expand Down Expand Up @@ -42,16 +41,13 @@ func DefaultResponderHandler(writer http.ResponseWriter, request *http.Request,

if builder.writer != nil {
if writeHeaders(writer, builder) {
logger, ok := request.Context().Value(LoggerKey{}).(*slog.Logger)

if ok && logger != nil {
logger.Error(
"detected server error",
"code", builder.status,
"text", http.StatusText(builder.status),
"url", request.URL.String(),
"kind", "writer",
)
if ctx, ok := Context(request); ok {
ctx.handleError(ServerError{
Code: builder.status,
URL: request.URL.String(),
Text: http.StatusText(builder.status),
Kind: ServerErrorWriter,
})
}
}

Expand All @@ -71,17 +67,14 @@ func DefaultResponderHandler(writer http.ResponseWriter, request *http.Request,
}

if writeHeaders(writer, builder) {
logger, ok := request.Context().Value(LoggerKey{}).(*slog.Logger)

if ok && logger != nil {
logger.Error(
"detected server error",
"code", builder.status,
"text", http.StatusText(builder.status),
"url", request.URL.String(),
"kind", "body",
"body", string(body),
)
if ctx, ok := Context(request); ok {
ctx.handleError(ServerError{
Code: builder.status,
URL: request.URL.String(),
Text: http.StatusText(builder.status),
Kind: ServerErrorBody,
Body: string(body),
})
}
}

Expand All @@ -92,16 +85,13 @@ func DefaultResponderHandler(writer http.ResponseWriter, request *http.Request,

if builder.stream != nil {
if writeHeaders(writer, builder) {
logger, ok := request.Context().Value(LoggerKey{}).(*slog.Logger)

if ok && logger != nil {
logger.Error(
"detected server error",
"code", builder.status,
"text", http.StatusText(builder.status),
"url", request.URL.String(),
"kind", "stream",
)
if ctx, ok := Context(request); ok {
ctx.handleError(ServerError{
Code: builder.status,
URL: request.URL.String(),
Text: http.StatusText(builder.status),
Kind: ServerErrorStream,
})
}
}

Expand All @@ -123,16 +113,13 @@ func DefaultResponderHandler(writer http.ResponseWriter, request *http.Request,
}

if writeHeaders(writer, builder) {
logger, ok := request.Context().Value(LoggerKey{}).(*slog.Logger)

if ok && logger != nil {
logger.Error(
"detected server error",
"code", builder.status,
"text", http.StatusText(builder.status),
"url", request.URL.String(),
"kind", "default",
)
if ctx, ok := Context(request); ok {
ctx.handleError(ServerError{
Code: builder.status,
URL: request.URL.String(),
Text: http.StatusText(builder.status),
Kind: ServerErrorDefault,
})
}
}
}
Expand Down
53 changes: 53 additions & 0 deletions context.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package akumu

import (
"net/http"
"sync"
)

type ContextKey struct{}

type OnErrorNext func(ServerError)
type OnErrorCallback func(ServerError, OnErrorNext)

// Contextual is a concurrent-safe implementation
// to append akumu-specific context to the given request.
type Contextual struct {
mutex sync.Mutex
onError []OnErrorCallback
}

func NewContext() *Contextual {
return &Contextual{}
}

func Context(request *http.Request) (*Contextual, bool) {
ctx, ok := request.Context().Value(ContextKey{}).(*Contextual)

return ctx, ok
}

func (ctx *Contextual) OnError(callback OnErrorCallback) {
ctx.mutex.Lock()
defer ctx.mutex.Unlock()

ctx.onError = append(ctx.onError, callback)
}

func (ctx *Contextual) handleError(err ServerError) {
ctx.mutex.Lock()
defer ctx.mutex.Unlock()

var index int
var next func(ServerError)

next = func(err ServerError) {
if index < len(ctx.onError) {
callback := ctx.onError[index]
index++
callback(err, next)
}
}

next(err)
}
28 changes: 28 additions & 0 deletions errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package akumu

import "fmt"

type ServerErrorKind string

type ServerError struct {
Code int
URL string
Text string
Kind ServerErrorKind
Body string
}

var (
ServerErrorWriter ServerErrorKind = "writer"
ServerErrorBody ServerErrorKind = "body"
ServerErrorStream ServerErrorKind = "stream"
ServerErrorDefault ServerErrorKind = "default"
)

func (err ServerError) Error() string {
return fmt.Sprintf(
"%d: %s",
err.Code,
err.Text,
)
}
5 changes: 4 additions & 1 deletion handler.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package akumu

import (
"context"
"net/http"
)

Expand Down Expand Up @@ -64,7 +65,9 @@ func handleError(writer http.ResponseWriter, request *http.Request, err error, p
}

func (handler Handler) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
handleError(writer, request, handler(request), nil)
ctx := context.WithValue(context.Background(), ContextKey{}, NewContext())

handleError(writer, request, handler(request.WithContext(ctx)), nil)
}

func (handler Handler) HandlerFunc() http.HandlerFunc {
Expand Down
3 changes: 0 additions & 3 deletions logger.go

This file was deleted.

20 changes: 16 additions & 4 deletions middleware/logger.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package middleware

import (
"context"
"log/slog"
"net/http"

Expand All @@ -22,8 +21,21 @@ func LoggerDefault() func(http.Handler) http.Handler {

func LoggerWith(handler http.Handler, logger *slog.Logger) http.Handler {
return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
handler.ServeHTTP(writer, request.WithContext(
context.WithValue(request.Context(), akumu.LoggerKey{}, logger),
))
if ctx, ok := akumu.Context(request); ok {
ctx.OnError(func(err akumu.ServerError, next akumu.OnErrorNext) {
logger.ErrorContext(
request.Context(),
"server error",
"code", err.Code,
"text", err.Text,
"url", err.URL,
"kind", err.Kind,
)

next(err)
})
}

handler.ServeHTTP(writer, request)
})
}

0 comments on commit 7c94d30

Please sign in to comment.