kataras / iris

The fastest HTTP/2 Go Web Framework. New, modern and easy to learn. Fast development with Code you control. Unbeatable cost-performance ratio :rocket:
https://www.iris-go.com
BSD 3-Clause "New" or "Revised" License
25.29k stars 2.47k forks source link

Question about Iris Logging: How to access a logger in other parts of application #2178

Open ce-ankur opened 1 year ago

ce-ankur commented 1 year ago

Env Details:

Iris Version: 12.2.0
go version go1.19.4 darwin/arm64

I am trying to setup my new Iris application as follows:

// main.go
package main

import (
    "myapp/bootstrap"
    "github.com/kataras/iris/v12"
)

func main() {
    bootstrap.InitIrisApp()
    app := bootstrap.GetIrisApp()
    app.Listen(util.GetPortNumber(), iris.WithLowercaseRouting)
}

The bootstrap.go looks like below:

package bootstrap

import (
    "myapp/handler"
    "myapp/structs"
    "myapp/util"
    "strings"
    "time"

    prometheusMiddleware "github.com/iris-contrib/middleware/prometheus"
    "github.com/prometheus/client_golang/prometheus/promhttp"

    "github.com/kataras/golog"
    "github.com/kataras/iris/v12"
)

var irisServer *iris.Application

func getRequestLogger(ctx iris.Context) {

    // write log format as below format
    // $remote_addr $http_method $http_uri $http_user_agent
    ctx.Request().UserAgent()
    ctx.Request().Referer()
    template := "Remote Addr: %s | Path: %s %s | UA: %s "
    ctx.Application().Logger().Infof(template, ctx.RemoteAddr(), ctx.Method(), ctx.Path(), ctx.Request().UserAgent())

    ctx.Next()
}

func InitIrisApp() {

    // initialize default app with default middlewares
    irisServer = iris.Default()

    // configure logger
    initLogger()

    // configure health check
    initHealthCheck()

    // configure prometheus metrics and end points
    initPrometheusMetrics()

    // initRoutes
    initRoutes()

    // configure the env configuration

    // configure error handlers
    irisServer.OnErrorCode(iris.StatusInternalServerError, internalServerErrorHandler)

    // configure graceful shutdown

}

func initHealthCheck() {
    hcAPI := irisServer.Party(util.GetContextPath() + "/health")
    {
        hcAPI.Get("/status", func(ctx iris.Context) {
            ctx.JSON(handler.HealthHandlerIris())
        })
    }
}

func initRoutes() {
    jobsAPI := irisServer.Party(util.GetContextPath() + "/jobs")
    {
        // bind more routes
    }
}

func internalServerErrorHandler(ctx iris.Context) {

    msg := strings.Split(ctx.GetErr().Error(), "\n")

    ctx.JSON(structs.ServerErrorResponse{
        StatusCode:  500,
        Message:     "Unable to process the request. Internal Server error!",
        Description: msg[0],
        Path:        ctx.Path(),
        Timestamp:   time.Now(),
        ApiVersion:  util.GetAPIVersion(),
    })
}

func initPrometheusMetrics() {

    // adding middleware for prometheus
    m := prometheusMiddleware.New("serviceName", 0.3, 1.2, 5.0)
    irisServer.Use(m.ServeHTTP)

    // adding a route for getting prometheus metrics
    irisServer.Get("/prometrics", iris.FromStd(promhttp.Handler()))
}

func initLogger() {
    irisServer.Logger().SetLevel(util.GetRunLogLevel())
    // adding a middleware for logging requests
    irisServer.Use(getRequestLogger)
}

func GetLoggerInstance() *golog.Logger {
    return irisServer.Logger()
}

func GetIrisApp() *iris.Application {
    return irisServer
}

I want to understand once I have setup the logger I want to use it in other parts of the code, like Handlers, service layers, models etc. For this reason I exported a function GetLoggerInstance() in hope that I can use same logger instance in whole code. But I land up in cyclic dependency. Moreover, when I am to use logging methods the correct context of the log must be picked up.

[19:01:49 IST 2023/07/26] [DEFAULT] [INFO] (myapp/util/config:8) Setting project directory as.....
[INFO] 2023/07/26 19:13 Remote Addr: ::1 | Path: GET /api/health/status | UA: PostmanRuntime/7.32.0 

I understand the access logs and different from application logs, but how can I achieve the parity between both of them using iris logger. Unfortunately I was not able to understand this from Docs. Any help is much appreciated. @kataras

kataras commented 1 year ago

Hello @ce-ankur did you try?

func myHandler(ctx iris.Context) {
    logger := ctx.Application().Logger()
    // work with "logger" instance...
}
ce-ankur commented 1 year ago

HI @kataras This is the easiest approach and I am already using this in my handlers/where-ever the ctx object is available. I question was regarding how can I get logger instance where I don't have context object. I don't think passing either logger or ctx instance is a good idea.

kataras commented 1 year ago

@ce-ankur If you use the default Iris logger you can get the logger instance through golog.Default/golog.Debug/Info... so you don't have dependency cycle.