Restructure project

We previously didn't really had any structure in our project apart
from creating a new folder for each package in our project root.
Now that we have accumulated some packages, we use the well-known
Golang project layout in order to clearly communicate our intent
with packages. See https://github.com/golang-standards/project-layout
This commit is contained in:
sirkrypt0
2021-07-16 09:19:42 +02:00
parent 2f1383b743
commit 8b26ecbe5f
66 changed files with 95 additions and 95 deletions

83
pkg/logging/logging.go Normal file
View File

@ -0,0 +1,83 @@
package logging
import (
"bufio"
"fmt"
"github.com/sirupsen/logrus"
"net"
"net/http"
"os"
"time"
)
var log = &logrus.Logger{
Out: os.Stderr,
Formatter: &logrus.TextFormatter{
DisableColors: true,
FullTimestamp: true,
},
Hooks: make(logrus.LevelHooks),
Level: logrus.InfoLevel,
}
func InitializeLogging(loglevel string) {
level, err := logrus.ParseLevel(loglevel)
if err != nil {
log.WithError(err).Fatal("Error parsing loglevel")
return
}
log.SetLevel(level)
}
func GetLogger(pkg string) *logrus.Entry {
return log.WithField("package", pkg)
}
// loggingResponseWriter wraps the default http.ResponseWriter and catches the status code
// that is written.
type loggingResponseWriter struct {
http.ResponseWriter
statusCode int
}
func NewLoggingResponseWriter(w http.ResponseWriter) *loggingResponseWriter {
return &loggingResponseWriter{w, http.StatusOK}
}
func (writer *loggingResponseWriter) WriteHeader(code int) {
writer.statusCode = code
writer.ResponseWriter.WriteHeader(code)
}
func (writer *loggingResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
conn, rw, err := writer.ResponseWriter.(http.Hijacker).Hijack()
if err != nil {
return conn, nil, fmt.Errorf("hijacking connection failed: %w", err)
}
return conn, rw, nil
}
// HTTPLoggingMiddleware returns an http.Handler that logs different information about every request.
func HTTPLoggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now().UTC()
path := r.URL.Path
lrw := NewLoggingResponseWriter(w)
next.ServeHTTP(lrw, r)
latency := time.Now().UTC().Sub(start)
logEntry := log.WithFields(logrus.Fields{
"code": lrw.statusCode,
"method": r.Method,
"path": path,
"duration": latency,
"user_agent": r.UserAgent(),
})
if lrw.statusCode >= http.StatusInternalServerError {
logEntry.Warn()
} else {
logEntry.Debug()
}
})
}

View File

@ -0,0 +1,48 @@
package logging
import (
"github.com/sirupsen/logrus"
"github.com/sirupsen/logrus/hooks/test"
"github.com/stretchr/testify/assert"
"net/http"
"net/http/httptest"
"testing"
)
func mockHTTPStatusHandler(status int) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(status)
})
}
func TestHTTPMiddlewareWarnsWhenInternalServerError(t *testing.T) {
var hook *test.Hook
log, hook = test.NewNullLogger()
InitializeLogging(logrus.DebugLevel.String())
request, err := http.NewRequest(http.MethodGet, "/", nil)
if err != nil {
t.Fatal(err)
}
recorder := httptest.NewRecorder()
HTTPLoggingMiddleware(mockHTTPStatusHandler(500)).ServeHTTP(recorder, request)
assert.Equal(t, 1, len(hook.Entries))
assert.Equal(t, logrus.WarnLevel, hook.LastEntry().Level)
}
func TestHTTPMiddlewareDebugsWhenStatusOK(t *testing.T) {
var hook *test.Hook
log, hook = test.NewNullLogger()
InitializeLogging(logrus.DebugLevel.String())
request, err := http.NewRequest(http.MethodGet, "/", nil)
if err != nil {
t.Fatal(err)
}
recorder := httptest.NewRecorder()
HTTPLoggingMiddleware(mockHTTPStatusHandler(200)).ServeHTTP(recorder, request)
assert.Equal(t, 1, len(hook.Entries))
assert.Equal(t, logrus.DebugLevel, hook.LastEntry().Level)
}