iris/_examples/logging/request-logger/accesslog/main.go
2022-06-17 10:23:51 +03:00

192 lines
5.0 KiB
Go

package main // See https://github.com/kataras/iris/issues/1601
import (
"bufio"
"time"
"github.com/kataras/iris/v12"
"github.com/kataras/iris/v12/middleware/accesslog"
"github.com/kataras/iris/v12/middleware/basicauth"
"github.com/kataras/iris/v12/middleware/requestid"
"github.com/kataras/iris/v12/sessions"
rotatelogs "github.com/iproj/file-rotatelogs"
)
// Default line format:
// Time|Latency|Code|Method|Path|IP|Path Params Query Fields|Bytes Received|Bytes Sent|Request|Response|
//
// Read the example and its comments carefully.
func makeAccessLog() *accesslog.AccessLog {
// Optionally, let's Go with log rotation.
pathToAccessLog := "./access_log.%Y%m%d%H%M"
w, err := rotatelogs.New(
pathToAccessLog,
rotatelogs.WithMaxAge(24*time.Hour),
rotatelogs.WithRotationTime(time.Hour))
if err != nil {
panic(err)
}
// Initialize a new access log middleware.
// Accepts an `io.Writer`.
ac := accesslog.New(bufio.NewWriter(w))
ac.Delim = ' ' // change the separator from '|' to space.
// ac.TimeFormat = "2006-01-02 15:04:05" // default
// Example of adding more than one field to the logger.
// Here we logging all the session values this request has.
//
// You can also add fields per request handler,
// look below to the `fieldsHandler` function.
// Note that this method can override a key stored by a handler's fields.
ac.AddFields(func(ctx iris.Context, fields *accesslog.Fields) {
if sess := sessions.Get(ctx); sess != nil {
fields.Set("session_id", sess.ID())
sess.Visit(func(k string, v interface{}) {
fields.Set(k, v)
})
}
})
// Add a custom field of "auth" when basic auth is available.
ac.AddFields(func(ctx iris.Context, fields *accesslog.Fields) {
if username, password, ok := ctx.Request().BasicAuth(); ok {
fields.Set("auth", username+":"+password)
}
})
return ac
/*
Use a file directly:
ac := accesslog.File("./access.log")
Log after the response was sent (defaults to false):
ac.Async = true
Force-protect writer with locks.
On this example this is not required:
ac.LockWriter = true"
// To disable request and response calculations
// (enabled by default but slows down the whole operation if Async is false):
ac.RequestBody = false
ac.ResponseBody = false
ac.BytesReceived = false
ac.BytesSent = false
ac.BytesReceivedBody = false
ac.BytesSentBody = false
Add second output:
ac.AddOutput(app.Logger().Printer)
OR:
accesslog.New(io.MultiWriter(w, os.Stdout))
Change format (after output was set):
ac.SetFormatter(&accesslog.JSON{Indent: " "})
Modify the output format and customize the order
with the Template formatter:
ac.SetFormatter(&accesslog.Template{
Text: "{{.Now.Format .TimeFormat}}|{{.Latency}}|{{.Code}}|{{.Method}}|{{.Path}}|{{.IP}}|{{.RequestValuesLine}}|{{.BytesReceivedLine}}|{{.BytesSentLine}}|{{.Request}}|{{.Response}}|\n",
// Default ^
})
*/
}
func main() {
ac := makeAccessLog()
defer ac.Close()
app := iris.New()
// Register the middleware (UseRouter to catch http errors too).
app.UseRouter(ac.Handler)
//
// Register other middlewares...
app.UseRouter(requestid.New())
// Register some routes...
app.HandleDir("/", iris.Dir("./public"))
app.Get("/user/{username}", userHandler)
app.Post("/read_body", readBodyHandler)
app.Get("/html_response", htmlResponse)
basicAuth := basicauth.Default(map[string]string{
"admin": "admin",
})
app.Get("/admin", basicAuth, adminHandler)
sess := sessions.New(sessions.Config{Cookie: "my_session_id", AllowReclaim: true})
app.Get("/session", sess.Handler(), sessionHandler)
app.Get("/fields", fieldsHandler)
//
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>")
}
func adminHandler(ctx iris.Context) {
username, password, _ := ctx.Request().BasicAuth()
// of course you don't want that in production:
ctx.HTML("<h2>Username: %s</h2><h3>Password: %s</h3>", username, password)
}
func sessionHandler(ctx iris.Context) {
sess := sessions.Get(ctx)
sess.Set("session_test_key", "session_test_value")
ctx.WriteString("OK")
}
type user struct {
ID string
Username string
}
// Log custom structs, they can implement the fmt.Stringer interface too.
func (u user) String() string {
return u.ID + ":" + u.Username
}
func fieldsHandler(ctx iris.Context) {
start := time.Now()
// simulate a heavy job...
time.Sleep(2 * time.Second)
end := time.Since(start)
// Get the current fields instance
// and use it to set custom log values.
logFields := accesslog.GetFields(ctx)
logFields.Set("job_latency", end.Round(time.Second))
// Simulate a database fetch or anything
// to get a "user" and log it:
u := user{
ID: "user-id",
Username: "user-name",
}
logFields.Set("user", u)
ctx.WriteString("OK")
}