Skip to content

Commit

Permalink
feat(requestlogger): return close function & set directory
Browse files Browse the repository at this point in the history
This makes the function a lot more flexible and
predictable. Hiding the mechanism for cleaning
up the log writer is an anti-pattern.
  • Loading branch information
Jaeiya committed Jun 4, 2024
1 parent 16bf817 commit 6294a07
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 94 deletions.
11 changes: 7 additions & 4 deletions cmd/server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,23 +24,26 @@ func main() {

rootRouter := router.NewRouter()

closeLog, logByStatus := middleware.LogRequests(internal.Getwd() + "/logs")
defer closeLog()

routes.HandleAssets(
rootRouter,
cfg.ClientPath+"/assets",
middleware.LogRequests(http.StatusBadRequest),
logByStatus(http.StatusBadRequest),
)

routes.HandleSetup(
rootRouter,
cfg.DataPath+"/versions.json",
u,
middleware.LogRequests(http.StatusBadRequest),
logByStatus(http.StatusBadRequest),
)

routes.HandleIndex(
rootRouter,
cfg.ClientPath+"/index.html",
middleware.LogRequests(http.StatusBadRequest),
logByStatus(http.StatusBadRequest),
)

authRouter := router.NewRouter()
Expand All @@ -51,7 +54,7 @@ func main() {
"/authed",
rootRouter,
authRouter,
middleware.LogRequests(http.StatusBadRequest),
logByStatus(http.StatusBadRequest),
middleware.AuthGuard(u),
)

Expand Down
83 changes: 0 additions & 83 deletions internal/middleware/mw_req_logger.go

This file was deleted.

98 changes: 98 additions & 0 deletions internal/middleware/req_logger.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package middleware

import (
"fmt"
"net/http"
"strings"
"time"

"github.com/Everything-Explained/go-server/internal/router"
"github.com/Everything-Explained/go-server/internal/writers"
)

type responseWrapper struct {
http.ResponseWriter
statusCode int
}

func (w *responseWrapper) WriteHeader(statusCode int) {
w.ResponseWriter.WriteHeader(statusCode)
w.statusCode = statusCode
}

/*
LogRequests creates a log at the specified directory and returns a logByStatus(),
to filter by minimum status code. If the status is set to 400, then no status
below 400 will be logged. When you're done with the log, you can use the
returned closeLog().
*/
func LogRequests(dir string) (closeLog func(), logByStatus func(status int) router.Middleware) {
const logName = "requests"
err := writers.CreateLog(logName, dir)
if err != nil {
panic(err)
}

closeLog = func() {
writers.Log.Close(logName)
}

logByStatus = func(statusCode int) router.Middleware {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
query := ""
if req.URL.RawQuery != "" {
query = req.URL.RawQuery
}

host := req.Host
if host == "" {
host = req.RemoteAddr
}

url, err := req.URL.Parse(req.URL.RequestURI())
// TODO Log it as server error
if err != nil {
panic(err)
}

agent := strings.Join(req.Header["User-Agent"], ",")
country := strings.Join(
req.Header[http.CanonicalHeaderKey("CF-IPCountry")],
",",
)
now := time.Now().UnixMicro()

respWriterWrapper := &responseWrapper{
ResponseWriter: w,
statusCode: http.StatusOK,
}
body := router.ReadBody(req)

// Complete request ops before we log
next.ServeHTTP(respWriterWrapper, req)

if respWriterWrapper.statusCode < statusCode {
return
}

reqSpeed := fmt.Sprintf("%dµs", time.Now().UnixMicro()-now)

writers.Log.Info(
logName,
agent,
country,
req.Method,
host,
url.Path,
query,
body,
respWriterWrapper.statusCode,
reqSpeed,
)
})
}
}

return

Check warning on line 97 in internal/middleware/req_logger.go

View workflow job for this annotation

GitHub Actions / lint

bare-return: avoid using bare returns, please add return expressions (revive)
}
22 changes: 15 additions & 7 deletions internal/writers/log_writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@ import (
)

const (
logFolderPath string = "./logs"
separator string = "<|>"
newLineChar string = "\u200B"
separator string = "<|>"
newLineChar string = "\u200B"
)

type LogLevel byte
Expand All @@ -29,19 +28,19 @@ var (
)

/*
NewLogWriter initializes a new log file with the specified name.
CreateLog initializes a new log file with the specified name.
*/
func NewLogWriter(name string) error {
func CreateLog(name string, logDir string) error {
if _, exists := logs[name]; exists {
return nil
}

err := os.MkdirAll(logFolderPath, 0o755)
err := os.MkdirAll(logDir, 0o755)
if err != nil {
return err
}

logFilePath := logFolderPath + "/" + name + ".txt"
logFilePath := logDir + "/" + name + ".txt"
f, err := os.OpenFile(logFilePath, os.O_CREATE|os.O_APPEND, 0o644)
if err != nil {
return err
Expand All @@ -65,6 +64,15 @@ func (logger) Error(name string, messages ...any) {
log(name, ERROR, messages...)
}

func (logger) Close(name string) error {
f, ok := logs[name]
if !ok {
panic(fmt.Errorf("log not found: %s", name))
}
f.Close()
return nil
}

func log(name string, level LogLevel, messages ...any) {
l, exists := logs[name]
if !exists {
Expand Down

0 comments on commit 6294a07

Please sign in to comment.