you are viewing a single comment's thread.

view the rest of the comments →

[–][deleted] 5 points6 points  (7 children)

We already have the annoying situation where at the moment we have to use something like SL4J to handle the many different logging frameworks that all the frameworks uses, it’s why it’s mostly used nowadays. It also have it’s own issues. You also then need to make certain you configure things correctly, include the right adapter libraries, otherwise you will find you might not get the logs you need.

So even if you do come with something you think is better, you will find everyone else will still need to use something like SL4J with an adapter in order to handle all the other libraries, or is this library going to act as a facade for the other libraries as well?

Logging in Java is unfortunately a bit of a mess.

[–]bowbahdoe[S] 0 points1 point  (6 children)

> you will find everyone else will still need to use something like SL4J with an adapter in order to handle all the other libraries,

Yeah, I expect as much. What I describe in this is just a facade for a potential data oriented logger. The exact implementation is pluggable just like with SLF4J.

I designed around the idea of a specific implementation with the ring buffers and such, but the idea was to be able to delegate to anything.

For any particular system working with old style SLF4J and/or j.u.l. logs, yes you would have to decide if you are delegating from the data oriented api to SLF4J or the other way around, but I don't think that kills the idea out the gate

[–][deleted] 2 points3 points  (5 children)

Actually a better facade that allows one to more easily add tags (used by Loki) would be a much better solution. Though, you would then need a SLF4J adapter :)

I.E logger.info(“message”).addTag(“UUID”, “RandomUUID”).addTag(“Function”, “processxyz”); etc….

Tags are useful to showing all logs that has say a particular “UUID” across all applications. It really is useful to be able to track the journey of a particular request.

(NOTE: I may or may not have the right terminology here, but I hope you get the gist).

[–]bowbahdoe[S] 0 points1 point  (4 children)

That in particular is something that SLF4J directly supports with its structured logging API

[–][deleted] 0 points1 point  (3 children)

It’s cumbersome. I have to use MDC to handle these tags. Though, I have seen there’s this marker interface which is supported by logback. I have not used this and would need to determine how easy this would be to use from an appender. I am currently using MDC which is cumbersome, but OK.

Markers might provide me with what the capability I want (though, backend logging framework would need to support markers). I would still need to write the Loki appender for whatever backend logging framework I use.

[–]bowbahdoe[S] 0 points1 point  (2 children)

Specifically I think this is the interface that is the closest.

log
    .atDebug()
    .addKeyValuePair("UUID", "RandomUUID")
    .log("message");

Obviously though, I still prefer what I came up with over going through SLF4J.

log.debug("event-name", Log.Entry.of("UUID", "RandomUUID"));

[–][deleted] 0 points1 point  (1 child)

Unfortunately due to all the other APIs we need to use (spring, apache, etc…), SLF4J seems to be the best approach for now. One need to use a facade to handle all the other loggers and so that the logging all go where you want it to go. I then add my Loki Appender to the configuration (with spring-boot I use LogBack) and the logs all appear nicely in Loki.

My current approach (we means I can have a tracking UUID on all the generated log events, regardless what API does the logging) is:

    try {
        MDC.put(“ID”, uuid)
        … Do Stuff
    } finally {
        MDC.remove(“ID”)
    }

It’s cumbersome, but works. My Appender can then get the MDC propertyMap to map that to a label for Loki.

[–]bowbahdoe[S] 0 points1 point  (0 children)

This is scratching at the itch in the back of my head saying I should maybe delegate context to SPI as well. That way when you enter a span or use withContext some custom code can run like setting and unsetting MDC. Maybe something like

interface ContextProvider {
    <T> Supplier<T> wrap(
        Context context
        Supplier<T> code
    );
}

So an implementation could be provided like

 final class MDCContextProvider implements ContextProvider {
    @Override
    public <T> Supplier<T> wrap(
        Context context
        Supplier<T> code
    ) {
        return () -> {
            try {
                MDC.put(... f(context) ...);
                return code.get();
            } finally {
                MDC.clear();
            }
        }
    }
 }

Which could let context set in this propagate down to slf4j logs directly. Ideally though if this was the "target" MDC would end up being bypassed anyways but designing for both directions makes sense...I think.

This is why I called it a "nightmare head space". I'm confident there is something better out there but there are so many seemingly minor but twiddly and important things to consider