New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Logger backends #56
Logger backends #56
Conversation
|
||
// Metrics return a middleware which will use the given MetricsHandler in | ||
// order to publish new statistics. | ||
func Metrics(handler MetricsHandler) func(next http.Handler) http.Handler { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you call it Metrics? This is just a Logger, isn't it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hello,
It's a terminology choice in order to separate what the data is (a metric) with how it's handled (with a logger).
For example, depending of your use case, you may use this middleware to expose these metrics on one of these "backends":
- NSQ Producer
- RabbitMQ Queue
- Telegraf (InfluxDB) Plugin
- Prometheus Exporter
With these examples, is Logger still make sense ? I was trying to "use" a more generic terms (Metrics) for this purpose. (However, a Logger use these metrics)
Nevertheless, If the contributors team isn't conviced by this opinionated design, I can update this Pull Request with the terminology that you prefer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like Metrics is more specific word for the application data/metrics (where data would contain session, user_id, ip, referer, user_agent, context etc.), not just the Request/Response data.
@pkieltyka thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
btw: We need to keep the old Logger interface the same. For stable API.
func Logger(next http.Handler) http.Handler
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yea, I agree with @VojtechVitek that the name Metrics is more about instrumentation metrics and less about application logs going to different backends.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, so for the terminology, do we agree to rename Metric
as LogEntry
and Metrics
as NewLogger
?
Also, for the MetricsHandler
interface, what do you prefer between:
LogAppender
with aAppend
method.LogHandler
with aWrite
method.
Thank you.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice, I like these suggestions, LogEntry, NewLogger and I prefer LogAppender/Append -- @VojtechVitek ?
thanks for the PR @november-eleven, there is definitely some good stuff in here and I feel we're close. I'd like to find a different name than Metric, more like LogBackend etc., or LogPipe .. something like that. But first, can you give a quick example how this could be used with different backends? ie. is it like .. // something that comes to mind
func router() http.Handler {
logger := middleware.NewLogger(
middleware.DefaultLoggerBackend,
myCustomPrometheusLoggerBackend{},
)
r := chi.NewRouter()
r.Use(logger)
r.Get("/", ...)
} |
Oh, I haven't thought about the "multiple backends" use-case. If we assume that the declaration of each routes are defined in the same thread in order to avoid race condition, then (with a little modification) you could use the func router() http.Handler {
logger := middleware.NewLogger(
middleware.DefaultLoggerBackend,
myCustomPrometheusLoggerBackend{},
)
r := chi.NewRouter()
r.Use(logger)
r.Get("/", ...)
} or func router() http.Handler {
r := chi.NewRouter()
r.Use(middleware.NewLogger(middleware.DefaultLoggerBackend))
r.Use(middleware.NewLogger(myCustomPrometheusLoggerBackend{}))
r.Get("/", ...)
} However, if a third Logger is required for a sub group: r.Group("articles", func(r chi.Router) {
r.Use(middleware.NewLogger(AnotherLoggerForArticles{}))
r.Get("/", paginate, listArticles)
r.Post("/", createArticle)
r.Group("/:articleID", func(r chi.Router) {
r.Use(ArticleCtx)
r.Get("/", getArticle)
r.Put("/", updateArticle)
r.Delete("/", deleteArticle)
})
}) The implementation I have in mind wouldn't work, and wrapping another For these reasons, I would be inclined to think that this middleware should define only once, one or multiple backend. (So, it would be your example). |
@november-eleven yea, I was also thinking about the performance implications. For some, the trade-off may be negligible, but we should still consider the API design in regards to performance. It's pretty easy to support multiple backends in a single call..
|
if someone felt so inclined, they could split the logger middlewares like in your example, which I think looks a bit cleaner, but has some performance penalties that aren't worth it. |
Hello, I've played a little with If you prefer, I can submit a new pull request with a more appropriate branch name and a squashed commit. However, it will lose this discussion history... Cheers, |
Sure, submit another PR and we can always reference the discussion here as needed. Also, boom tests are good, but it's also important to write go bench tests to determine number of allocs and ops to figure out memory and cpu pressure of the code |
Yeah, you're right. I've added some primary benchmark for this purpose, so if you have any feedback: don't hesitate. Also, don't merge it yet, I would like to add some testing too :)
To finish on a good note, I've run some benchmark on several router (Echo, Gin and LARS for instance) with and without logger (note: output on
Cheers, |
Hello, I think this will be my final commit for this Pull Request because I won't be available for the time being... Cheers, |
@november-eleven this is awesome, thank you. I'm going to dive in deeper on this as I get to the final details and step of v2 |
@november-eleven thanks so much for your work on this! What's great about the new context support in net/http, this logger is framework-agnostic and will technically work as any stdlib net/lib http middleware. After giving it some thought, I think the first version of chi v2, I'd like to keep super minimal and it would be better if you move this PR into its own middleware package. For example, github.com/november-eleven/logpiper or in the github.com/goware org which we put a lot of other middleware's if you'd like. Let me know if you do it, and I'll link to it from our README. |
Hello, Ok I understand. I would prefer to have access to the goware organizations so others (including you) could contribute more easily to this middleware. Cheers, |
done! |
@november-eleven I reviewed this PR too. There is some really good code! However, after some considerations, I also feel like we should keep the default logger middleware as simple as possible and it should just write to STDOUT in respect to Docker, syslog etc. Even though multiple backend is certainly good idea, I don't think that goware Org would be a perfect place for this :) Anyway, thank you again for your PR, we really appreciate it! |
Hello,
This Pull Request add a new
Metrics
middleware in order to close the #55.It require a
MetricsHandler
which will be used as an events/metrics receiver.If the user want to use another logging backend, it just have to implement the previous interface.
Example:
However, while trying to keep compatibility with the v1 version, I think some refactoring for
middleware/recoverer.go
are required.Cheers,