1
0
mirror of https://github.com/kataras/iris.git synced 2025-12-23 12:57:05 +00:00

add accesslog middleware (rel: #1601)

This commit is contained in:
Gerasimos (Makis) Maropoulos
2020-09-06 10:38:48 +03:00
parent bf9f7617e2
commit 0be856e54c
16 changed files with 339 additions and 347 deletions

View File

@@ -0,0 +1,47 @@
package main // See https://github.com/kataras/iris/issues/1601
import (
"github.com/kataras/iris/v12"
"github.com/kataras/iris/v12/middleware/accesslog"
)
func main() {
app := iris.New()
ac := accesslog.File("./access.log")
defer ac.Close()
iris.RegisterOnInterrupt(func() {
ac.Close()
})
// Register the middleware (UseRouter to catch http errors too).
app.UseRouter(ac.Handler)
//
// Register some routes...
app.HandleDir("/", iris.Dir("./public"))
app.Get("/user/{username}", userHandler)
app.Post("/read_body", readBodyHandler)
app.Get("/html_response", htmlResponse)
//
app.Listen(":8080")
}
func readBodyHandler(ctx iris.Context) {
var request interface{}
if err := ctx.ReadBody(&request); err != nil {
ctx.StopWithPlainError(iris.StatusBadRequest, err)
return
}
ctx.JSON(iris.Map{"message": "OK", "data": request})
}
func userHandler(ctx iris.Context) {
ctx.Writef("Hello, %s!", ctx.Params().Get("username"))
}
func htmlResponse(ctx iris.Context) {
ctx.HTML("<h1>HTML Response</h1>")
}

View File

@@ -21,7 +21,6 @@ func main() {
Query: true,
// Shows information about the executed route.
TraceRoute: true,
// Columns: true,
// if !empty then its contents derives from `ctx.Values().Get("logger_message")
// will be added to the logs.

View File

@@ -1,174 +0,0 @@
package main // See https://github.com/kataras/iris/issues/1601
import (
"bytes"
"encoding/json"
"fmt"
"io"
"os"
"strings"
"time"
"github.com/kataras/iris/v12"
"github.com/kataras/iris/v12/middleware/logger"
)
func main() {
// Create or use the ./access.log file.
f, err := os.OpenFile("access.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
panic(err)
}
defer f.Close()
iris.RegisterOnInterrupt(func() { f.Close() })
//
app := iris.New()
// Init the request logger with
// the LogFuncCtx field alone.
reqLogger := logger.New(logger.Config{
LogFuncCtx: requestLogFunc(f),
})
//
// Wrap the request logger middleware
// with a response recorder because
// we want to record the response body
// sent to the client.
reqLoggerWithRecord := func(ctx iris.Context) {
// Store the requested path just in case.
ctx.Values().Set("path", ctx.Path())
ctx.Record()
reqLogger(ctx)
}
//
// Register the middleware (UseRouter to catch http errors too).
app.UseRouter(reqLoggerWithRecord)
//
// Register some routes...
app.HandleDir("/", iris.Dir("./public"))
app.Get("/user/{username}", userHandler)
app.Post("/read_body", readBodyHandler)
//
// Start the server with `WithoutBodyConsumptionOnUnmarshal`
// option so the request body can be readen twice:
// one for our handlers and one from inside our request logger middleware.
app.Listen(":8080", iris.WithoutBodyConsumptionOnUnmarshal)
}
func readBodyHandler(ctx iris.Context) {
var request interface{}
if err := ctx.ReadBody(&request); err != nil {
ctx.StopWithPlainError(iris.StatusBadRequest, err)
return
}
ctx.JSON(iris.Map{"message": "OK"})
}
func userHandler(ctx iris.Context) {
ctx.Writef("Hello, %s!", ctx.Params().Get("username"))
}
func jsonToString(src []byte) string {
buf := new(bytes.Buffer)
if err := json.Compact(buf, src); err != nil {
return err.Error()
}
return buf.String()
}
func requestLogFunc(w io.Writer) func(ctx iris.Context, lat time.Duration) {
return func(ctx iris.Context, lat time.Duration) {
var (
method = ctx.Method() // request method.
// Use a stored value instead of ctx.Path()
// because some handlers may change the relative path
// to perform some action.
path = ctx.Values().GetString("path")
code = ctx.GetStatusCode() // response status code
// request and response data or error reading them.
requestBody string
responseBody string
// url parameters and path parameters separated by space,
// key=value key2=value2.
requestValues string
)
// any error handler stored ( ctx.SetErr or StopWith(Plain)Error )
errHandler := ctx.GetErr()
// check if not error and client sent a response with a content-type set-ed.
if errHandler == nil {
if ctx.GetContentTypeRequested() == "application/json" {
// Read and log request body the client sent to the server:
//
// You can use ctx.ReadBody(&body)
// which will decode any body (json, xml, msgpack, protobuf...)
// and use %v inside the fmt.Fprintf to print something like:
// map[age:22 id:10 name:Tim]
//
// But if you want specific to json string,
// then do that:
var tmp json.RawMessage
if err := ctx.ReadJSON(&tmp); err != nil {
requestBody = err.Error()
} else {
requestBody = jsonToString(tmp)
}
//
} else {
// left for exercise.
}
} else {
requestBody = fmt.Sprintf("error(%s)", errHandler.Error())
}
responseData := ctx.Recorder().Body()
// check if the server sent any response with content type,
// note that this will return the ;charset too
// so we check for its prefix instead.
if strings.HasPrefix(ctx.GetContentType(), "application/json") {
responseBody = jsonToString(responseData)
} else {
responseBody = string(responseData)
}
var buf strings.Builder
ctx.Params().Visit(func(key, value string) {
buf.WriteString(key)
buf.WriteByte('=')
buf.WriteString(value)
buf.WriteByte(' ')
})
for _, entry := range ctx.URLParamsSorted() {
buf.WriteString(entry.Key)
buf.WriteByte('=')
buf.WriteString(entry.Value)
buf.WriteByte(' ')
}
if n := buf.Len(); n > 1 {
requestValues = buf.String()[0 : n-1] // remove last space.
}
fmt.Fprintf(w, "%s|%s|%s|%s|%s|%d|%s|%s|\n",
time.Now().Format("2006-01-02 15:04:05"),
lat,
method,
path,
requestValues,
code,
requestBody,
responseBody,
)
}
}

View File

@@ -1,107 +0,0 @@
package main
import (
"os"
"strings"
"time"
"github.com/kataras/iris/v12"
"github.com/kataras/iris/v12/middleware/logger"
)
const deleteFileOnExit = false
func main() {
app := iris.New()
r, close := newRequestLogger()
defer close()
app.Use(r)
app.OnAnyErrorCode(r, func(ctx iris.Context) {
ctx.HTML("<h1> Error: Please try <a href ='/'> this </a> instead.</h1>")
})
h := func(ctx iris.Context) {
ctx.Writef("Hello from %s", ctx.Path())
}
app.Get("/", h)
app.Get("/1", h)
app.Get("/2", h)
// http://localhost:8080
// http://localhost:8080/1
// http://localhost:8080/2
// http://lcoalhost:8080/notfoundhere
app.Listen(":8080")
}
// get a filename based on the date, file logs works that way the most times
// but these are just a sugar.
func todayFilename() string {
today := time.Now().Format("Jan 02 2006")
return today + ".txt"
}
func newLogFile() *os.File {
filename := todayFilename()
// open an output file, this will append to the today's file if server restarted.
f, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
panic(err)
}
return f
}
var excludeExtensions = [...]string{
".js",
".css",
".jpg",
".png",
".ico",
".svg",
}
func newRequestLogger() (h iris.Handler, close func() error) {
close = func() error { return nil }
c := logger.Config{
Status: true,
IP: true,
Method: true,
Path: true,
Columns: true,
}
logFile := newLogFile()
close = func() error {
err := logFile.Close()
if deleteFileOnExit {
err = os.Remove(logFile.Name())
}
return err
}
c.LogFunc = func(endTime time.Time, latency time.Duration, status, ip, method, path string, message interface{}, headerMessage interface{}) {
output := logger.Columnize(endTime.Format("2006/01/02 - 15:04:05"), latency, status, ip, method, path, message, headerMessage)
logFile.Write([]byte(output))
} // or make use of the `LogFuncCtx`, see the '../request-logger-file-json' example for more.
// when we don't want to use to log requests to assets and etc.
c.AddSkipper(func(ctx iris.Context) bool {
path := ctx.Path()
for _, ext := range excludeExtensions {
if strings.HasSuffix(path, ext) {
return true
}
}
return false
})
h = logger.New(c)
return
}