mirror of
https://github.com/labstack/echo.git
synced 2024-12-22 20:06:21 +02:00
6ef5f77bf2
WIP: make default logger implemented custom writer for jsonlike logs WIP: improve examples WIP: defaultErrorHandler use errors.As to unwrap errors. Update readme WIP: default logger logs json, restore e.Start method WIP: clean router.Match a bit WIP: func types/fields have echo.Context has first element WIP: remove yaml tags as functions etc can not be serialized anyway WIP: change BindPathParams,BindQueryParams,BindHeaders from methods to functions and reverse arguments to be like DefaultBinder.Bind is WIP: improved comments, logger now extracts status from error WIP: go mod tidy WIP: rebase with 4.5.0 WIP: * removed todos. * removed StartAutoTLS and StartH2CServer methods from `StartConfig` * KeyAuth middleware errorhandler can swallow the error and resume next middleware WIP: add RouterConfig.UseEscapedPathForMatching to use escaped path for matching request against routes WIP: FIXMEs WIP: upgrade golang-jwt/jwt to `v4` WIP: refactor http methods to return RouteInfo WIP: refactor static not creating multiple routes WIP: refactor route and middleware adding functions not to return error directly WIP: Use 401 for problematic/missing headers for key auth and JWT middleware (#1552, #1402). > In summary, a 401 Unauthorized response should be used for missing or bad authentication WIP: replace `HTTPError.SetInternal` with `HTTPError.WithInternal` so we could not mutate global error variables WIP: add RouteInfo and RouteMatchType into Context what we could know from in middleware what route was matched and/or type of that match (200/404/405) WIP: make notFoundHandler and methodNotAllowedHandler private. encourage that all errors be handled in Echo.HTTPErrorHandler WIP: server cleanup ideas WIP: routable.ForGroup WIP: note about logger middleware WIP: bind should not default values on second try. use crypto rand for better randomness WIP: router add route as interface and returns info as interface WIP: improve flaky test (remains still flaky) WIP: add notes about bind default values WIP: every route can have their own path params names WIP: routerCreator and different tests WIP: different things WIP: remove route implementation WIP: support custom method types WIP: extractor tests WIP: v5.0.x proposal over v4.4.0
142 lines
4.6 KiB
Go
142 lines
4.6 KiB
Go
package echo
|
|
|
|
import (
|
|
"bytes"
|
|
"io"
|
|
"strconv"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Example for Zap (https://github.com/uber-go/zap)
|
|
//func main() {
|
|
// e := echo.New()
|
|
// logger, _ := zap.NewProduction()
|
|
// e.Logger = &ZapLogger{logger: logger}
|
|
//}
|
|
//type ZapLogger struct {
|
|
// logger *zap.Logger
|
|
//}
|
|
//
|
|
//func (l *ZapLogger) Write(p []byte) (n int, err error) {
|
|
// // Note: if `logger` middleware is used it will send json bytes here, and it will not look beautiful at all.
|
|
// l.logger.Info(string(p), zap.String("subsystem", "echo")) // naively log everything as string message.
|
|
// return len(p), nil
|
|
//}
|
|
//
|
|
//func (l *ZapLogger) Error(err error) {
|
|
// l.logger.Error(err.Error(), zap.Error(err), zap.String("subsystem", "echo"))
|
|
//}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Example for Zerolog (https://github.com/rs/zerolog)
|
|
//func main() {
|
|
// e := echo.New()
|
|
// logger := zerolog.New(os.Stdout)
|
|
// e.Logger = &ZeroLogger{logger: &logger}
|
|
//}
|
|
//
|
|
//type ZeroLogger struct {
|
|
// logger *zerolog.Logger
|
|
//}
|
|
//
|
|
//func (l *ZeroLogger) Write(p []byte) (n int, err error) {
|
|
// // Note: if `logger` middleware is used it will send json bytes here, and it will not look beautiful at all.
|
|
// l.logger.Info().Str("subsystem", "echo").Msg(string(p)) // naively log everything as string message.
|
|
// return len(p), nil
|
|
//}
|
|
//
|
|
//func (l *ZeroLogger) Error(err error) {
|
|
// l.logger.Error().Str("subsystem", "echo").Err(err).Msg(err.Error())
|
|
//}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Example for Logrus (https://github.com/sirupsen/logrus)
|
|
//func main() {
|
|
// e := echo.New()
|
|
// e.Logger = &LogrusLogger{logger: logrus.New()}
|
|
//}
|
|
//
|
|
//type LogrusLogger struct {
|
|
// logger *logrus.Logger
|
|
//}
|
|
//
|
|
//func (l *LogrusLogger) Write(p []byte) (n int, err error) {
|
|
// // Note: if `logger` middleware is used it will send json bytes here, and it will not look beautiful at all.
|
|
// l.logger.WithFields(logrus.Fields{"subsystem": "echo"}).Info(string(p)) // naively log everything as string message.
|
|
// return len(p), nil
|
|
//}
|
|
//
|
|
//func (l *LogrusLogger) Error(err error) {
|
|
// l.logger.WithFields(logrus.Fields{"subsystem": "echo"}).Error(err)
|
|
//}
|
|
|
|
// Logger defines the logging interface that Echo uses internally in few places.
|
|
// For logging in handlers use your own logger instance (dependency injected or package/public variable) from logging framework of your choice.
|
|
type Logger interface {
|
|
// Write provides writer interface for http.Server `ErrorLog` and for logging startup messages.
|
|
// `http.Server.ErrorLog` logs errors from accepting connections, unexpected behavior from handlers,
|
|
// and underlying FileSystem errors.
|
|
// `logger` middleware will use this method to write its JSON payload.
|
|
Write(p []byte) (n int, err error)
|
|
// Error logs the error
|
|
Error(err error)
|
|
}
|
|
|
|
// jsonLogger is similar logger formatting implementation as `v4` had. It is not particularly fast or efficient. Only
|
|
// goal it to exist is to have somewhat backwards compatibility with `v4` for Echo internals logging formatting.
|
|
// It is not meant for logging in handlers/middlewares. Use some real logging library for those cases.
|
|
type jsonLogger struct {
|
|
writer io.Writer
|
|
bufferPool sync.Pool
|
|
|
|
timeNow func() time.Time
|
|
}
|
|
|
|
func newJSONLogger(writer io.Writer) *jsonLogger {
|
|
return &jsonLogger{
|
|
writer: writer,
|
|
bufferPool: sync.Pool{
|
|
New: func() interface{} {
|
|
return bytes.NewBuffer(make([]byte, 256))
|
|
},
|
|
},
|
|
timeNow: time.Now,
|
|
}
|
|
}
|
|
|
|
func (l *jsonLogger) Write(p []byte) (n int, err error) {
|
|
pLen := len(p)
|
|
if pLen >= 2 && // naively try to avoid JSON values to be wrapped into message
|
|
(p[0] == '{' && p[pLen-2] == '}' && p[pLen-1] == '\n') ||
|
|
(p[0] == '{' && p[pLen-1] == '}') {
|
|
return l.writer.Write(p)
|
|
}
|
|
// we log with WARN level as we have no idea what that message level should be. From Echo perspective this method is
|
|
// called when we pass Echo logger to http.Server.ErrorLog and there are problems inside http.Server - which probably
|
|
// deserves at least WARN level.
|
|
return l.printf("WARN", string(p))
|
|
}
|
|
|
|
func (l *jsonLogger) Error(err error) {
|
|
_, _ = l.printf("ERROR", err.Error())
|
|
}
|
|
|
|
func (l *jsonLogger) printf(level string, message string) (n int, err error) {
|
|
buf := l.bufferPool.Get().(*bytes.Buffer)
|
|
buf.Reset()
|
|
defer l.bufferPool.Put(buf)
|
|
|
|
buf.WriteString(`{"time":"`)
|
|
buf.WriteString(l.timeNow().Format(time.RFC3339Nano))
|
|
buf.WriteString(`","level":"`)
|
|
buf.WriteString(level)
|
|
buf.WriteString(`","prefix":"echo","message":`)
|
|
|
|
buf.WriteString(strconv.Quote(message))
|
|
buf.WriteString("}\n")
|
|
|
|
return l.writer.Write(buf.Bytes())
|
|
}
|