最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

go - How to abstract logging of data from context using zerolog? - Stack Overflow

programmeradmin2浏览0评论

I want to add logging of an Request ID on every log message in every service. That way I can know which logs were coming from which request easier.

For my project I am using zerolog as the package of choice for logging.

Middleware function

func RequestIDMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        reqID := r.Header.Get("X-Request-ID")
        if reqID == "" {
            reqID = uuid.New().String()
        }

        ctx := context.WithValue(r.Context(), service.RequestIDKey, reqID)

        next.ServeHTTP(w, r.WithContext(ctx))
    })
}

handler.go

func (h *Handler) Message(w http.ResponseWriter, r *http.Request) {
    responseMsg, err := h.Service.GetMessage(r.Context())

    reqId, ok := r.Context().Value(service.RequestIDKey).(string)
    if !ok {
        log.Info().Msg("Some log message from handler")
    } else {
        log.Info().Str("request_id", reqId).Msg("Some log message from handler")
    }

    if err != nil {
        reqId, ok = r.Context().Value(service.RequestIDKey).(string)
        if !ok {
            log.Info().Msg("Some log message from handler")
        } else {
            log.Info().Str("request_id", reqId).Msg("Some log message from handler")
        }

        http.Error(w, "Internal Server Error", http.StatusInternalServerError)
    }

    w.Header().Set("Content-Type", "text/plain; charset=utf-8")
    w.WriteHeader(http.StatusOK)
    if _, err = w.Write([]byte(responseMsg)); err != nil {
        http.Error(w, "Failed to encode response", http.StatusInternalServerError)
    }
    return
}

Service object

func (service *Service) GetMessage(ctx context.Context) (string, error) {
    reqId, ok := ctx.Value(RequestIDKey).(string)

    if !ok {
        log.Info().Msg("Some log message from service")
    } else {
        log.Info().Str("request_id", reqId).Msg("Some log message from service")
    }

    return "Message from service", nil
}

Initiation function for the logger

package logger

func NewLogger() zerolog.Logger {
    once.Do(func() {

        consoleWriter := zerolog.ConsoleWriter{
            Out:        os.Stderr,
            TimeFormat: time.RFC3339,
        }

        zerolog.ErrorStackMarshaler = pkgerrors.MarshalStack

        var writers zerolog.LevelWriter

        writers = zerolog.MultiLevelWriter(consoleWriter)

        zerolog.CallerMarshalFunc = func(pc uintptr, file string, line int) string {
            parts := strings.Split(file, "/")
            if len(parts) > 3 {
                file = strings.Join(parts[len(parts)-3:], "/")
            }

            return file + ":" + strconv.Itoa(line)
        }

        logger = zerolog.New(writers).With().Timestamp().Caller().Logger()

    })

    return logger
}

main.go

func main() {
    // Set the global zerolog logger
    log.Logger = logger.NewLogger()

    s := service.NewService()
    h := handler.NewHandler(s)

    router := mux.NewRouter()
    router.Use(RequestIDMiddleware)

    router.HandleFunc("/message", h.Message).Methods("GET")

    if err := http.ListenAndServe(":8080", router); err != nil {
        log.Fatal().Err(err).Msg("Server failed")
    }

    log.Info().Msg("Server started")
}

I want to somehow abstract this repetitive code, that checks for requstId in the context and then adding it to the logger.

reqId, ok := r.Context().Value(service.RequestIDKey).(string)
    if !ok {
        log.Info().Msg("Some log message from handler")
    } else {
        log.Info().Str("request_id", reqId).Msg("Some log message from handler")
    }

Ideally I would best like to have something like:

log.Info().RequestId(ctx).Msg("Some log message")

From what I've read online, I can add new logger into the request context, with populated RequestID, but I don't know how good of an idea is to do that.

That way I will have a line of code, that extract a logger from the context, in every method of every handler and service.

发布评论

评论列表(0)

  1. 暂无评论