Skip to content

Commit

Permalink
chore: add request log intercepter
Browse files Browse the repository at this point in the history
Signed-off-by: Praveen Yadav <pyadav9678@gmail.com>
  • Loading branch information
pyadav committed Feb 22, 2024
1 parent 6c6831c commit 11fd53d
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 5 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ clean: clean-gateway ## Clean missing studio
.PHONY: clean

clean-gateway:
@echo "🧹 Cleaning gateway.."
@echo "Cleaning gateway.."
sh -c "cd ./gateway && make clean"
.PHONY: clean-gateway

Expand Down
101 changes: 101 additions & 0 deletions common/logger/logger.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,23 @@
package logger

import (
"bytes"
"context"
"encoding/binary"
"encoding/gob"
"fmt"
"log/slog"
"os"
"time"

"connectrpc.com/connect"
"google.golang.org/protobuf/types/known/durationpb"
)

type (
SpanIDKey struct{}
TraceIDKey struct{}
RequestTimeKey struct{}
)

type Option func(*slog.HandlerOptions)
Expand All @@ -28,3 +43,89 @@ func New(formatAsJson bool, options ...Option) *slog.Logger {

return slog.New(slog.NewTextHandler(os.Stdout, handlerOptions))
}

type httpRequest struct {
RequestMethod string `json:"requestMethod,omitempty"`
RequestUrl string `json:"requestUrl,omitempty"`
RequestSize string `json:"requestSize,omitempty"`
Status int `json:"status,omitempty"`
ResponseSize string `json:"responseSize,omitempty"`
UserAgent string `json:"userAgent,omitempty"`
Protocol string `json:"protocol,omitempty"`
RemoteIp string `json:"remoteIp,omitempty"`
ServerIp string `json:"serverIp,omitempty"`
Referer string `json:"referer,omitempty"`
Latency *durationpb.Duration `json:"latency,omitempty"`
}

type connectRequestLogger struct {
Logger *slog.Logger
Status int
Req connect.AnyRequest
Resp connect.AnyResponse
}

func NewConnectRequestLogger(l *slog.Logger, status int, req connect.AnyRequest, resp connect.AnyResponse) *connectRequestLogger {
return &connectRequestLogger{
Logger: l,
Status: status,
Req: req,
Resp: resp,
}
}

func binarySize(v any) int {
var buf bytes.Buffer
enc := gob.NewEncoder(&buf)
if err := enc.Encode(v); err != nil {
return 0
}
return binary.Size(buf.Bytes())
}

func defaultLogAttrs(severity slog.Level, traceID, spanID string) []slog.Attr {
return []slog.Attr{
slog.String("severity", severity.String()),
slog.String("spanId", spanID),
slog.String("traceId", traceID),
}
}

func (l *connectRequestLogger) ConnectRequestf(ctx context.Context) {
req := l.Req
resp := l.Resp

spanID, ok := ctx.Value(SpanIDKey{}).(string)
if !ok {
spanID = ""
}
traceID, ok := ctx.Value(TraceIDKey{}).(string)
if !ok {
traceID = ""
}

requestTime, ok := ctx.Value(RequestTimeKey{}).(time.Time)
if !ok {
requestTime = time.Now()
}

msg := "Connect request info"
attrs := append(
defaultLogAttrs(slog.LevelInfo, traceID, spanID),
slog.Any("httpRequest", httpRequest{
RequestMethod: req.HTTPMethod(),
Status: l.Status,
RequestUrl: "https://" + req.Header().Get("Host") + req.Spec().Procedure,
RequestSize: fmt.Sprint(binarySize(req)),
UserAgent: req.Header().Get("User-Agent"),
Protocol: req.Header().Get("Protocol"),
RemoteIp: req.Header().Get("X-Forwarded-For"),
ServerIp: req.Peer().Addr,
ResponseSize: fmt.Sprint(binarySize(resp)),
Latency: durationpb.New(time.Since(requestTime)),
}),
slog.Time("time", requestTime),
slog.Any("rawHttpHeader", req.Header()),
)
l.Logger.LogAttrs(ctx, slog.LevelInfo, msg, attrs...)
}
22 changes: 18 additions & 4 deletions gateway/internal/interceptor/logging.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ package interceptor
import (
"context"
"log/slog"
"net/http"

"connectrpc.com/connect"
"github.com/missingstudio/studio/common/logger"
)

var _ connect.Interceptor = &loggingInterceptor{}
Expand All @@ -25,12 +27,24 @@ func (l *loggingInterceptor) WrapUnary(next connect.UnaryFunc) connect.UnaryFunc
req connect.AnyRequest,
) (connect.AnyResponse, error) {
res, err := next(ctx, req)

resultStatus := http.StatusOK
if err != nil {
l.logger.Error("response with error",
"err", err.Error(),
"endpoint", req.Spec().Procedure,
"addr", req.Peer().Addr)
if err, ok := err.(*connect.Error); ok {
switch err.Code() {
case connect.CodeUnknown:
resultStatus = http.StatusInternalServerError
default:
// error code の分類分け
resultStatus = http.StatusBadRequest
}
}
}

defer func() {
l := logger.NewConnectRequestLogger(l.logger, resultStatus, req, res)
l.ConnectRequestf(ctx)
}()
return res, err
})
}
Expand Down

0 comments on commit 11fd53d

Please sign in to comment.