nberger / ring-logger

Log ring requests & responses using your favorite logging backend
Eclipse Public License 1.0
101 stars 21 forks source link

Ring-logger 1.0.0: Getting back to the roots #30

Closed nberger closed 6 years ago

nberger commented 6 years ago

EDIT: Looking into how different the new version is compared to the 0.7.x series, I decided to bump the new version to 1.0.0. It should help people realize that this is a major release that might (and actually does) contain breaking changes.


I've been feeling some discomfort when thinking about adding new features to ring.logger, or even when trying to use it! What the library provides is quite simple: an easy way to log some information about each request, in a way that is useful for monitoring in a production environment, but also for debugging in development.

I tried to make it customizable/adaptable by using multimethods, but in retrospect it doesn't sound like the best approach: As a user of the library, if I have to find out what multimethods to implement, and basically copy & paste the original fn to adapt it to my needs, then I will probably ditch the library and just add my own middleware. That what I (me, the maintainer of the library) have done on my latest projects. There must be a better way.

Long live ring-logger!

So here's the deal: I'll be working on a new version of the library which will have a more minimalist core, will accept a fn to change the output format (logs are not made of strings only), and will have minimal configuration options (with sensible defaults) for things like hiding sensitive values (redact-keys) or choosing which aspects of the request map to log. Might also leave that part to the output-fn.

The goal is to make it a no-brainer to use it on... let's say 80% of ring-based projects. Or well, at least on 100% of my own projects.


PS: I'd like to thank @pjlegato for creating the original ring.middleware.logger, and to all the current and past contributors, ring-logger wouldn't have gotten up to this point without your help!

nberger commented 6 years ago

By the way, any feedback about the 0.8.x approach will be much appreciated!

facundoolano commented 6 years ago

My 2 cents: a while ago I wanted to add some basic request/response logging to a small ring web app and looked into using this library. I wanted to have a single line per request with method + path + response status + elapsed time. I think there wasn't such a logger by default so I looked into writing a custom one but felt like it required too much code to pull it off.

What I ended up doing was looking at your source code and copying the bits I needed to write a single middleware function, which looked like this:

(defn- wrap-log-request
  "Middleware that logs incoming requests."
  [handler]
  (fn [{:keys [request-method uri query-string] :as req}]
    (let [start  (System/currentTimeMillis)
          method (-> request-method name str/upper-case)
          path   (if query-string (str uri "?" query-string) uri)
          res    (handler req)
          time   (- (System/currentTimeMillis) start)]
      (log/info (format "%s %s [%d] (%dms)" method path (:status res) time))
      res)))
nberger commented 6 years ago

@facundoolano thanks! I did more or less the same recently :).

In many cases it will be best to simply write your own middleware that way, but I think there's room for a library that provides logging middleware with a few more features (redacted params because you don't want sensitive information in your logs; colors because... well because colors are nice, but also because they make it easier to quickly identify some aspects of the output, especially if params were added to the output; request id to help correlate all the logs related to a request, etc.)

I recently needed to output json structured logs, to make it easier to extract metrics in the log processing pipeline. That's why I'm thinking in making the log to be just a map instead of a string, and let this output-fn convert to whatever format is preferred. Final details are to be defined, maybe the output-fn will actually be the logging middleware of which many will be provided, with a separate function/middleware/convention to take the timing metric and redact the params. The rest of the information is already in the request.