19

It it possible to modify a log event after matching a filter?

I've got an web container (Jersey) that logs uncaught exceptions at the ERROR level. But, for certain exceptions (EofException) throw by the server (Jetty), I'd like to log them at a lower level (INFO).

I can drop those messages entirely using a Logback filter that matches on the exception type (EofException). But I haven't found a supported method to modify the log event, e.g., change the log level.

David B.
  • 5,700
  • 5
  • 31
  • 52
  • Would this work instead: http://stackoverflow.com/questions/6143929/how-do-i-not-log-a-particular-type-of-exception-in-logback – Darius X. Mar 15 '13 at 20:51
  • I want something like that, but to change the log level instead of outright deny the message. – David B. Mar 15 '13 at 21:00
  • Are you okay if the level "changes" at the last monent, just before the appender logs it? If so, you could write your own appender. – Darius X. Mar 15 '13 at 21:10
  • I'd rather the actual message change, so that later filtering and routing works properly. – David B. Mar 16 '13 at 16:32
  • Have you tried changing the level inside a Turbo filter? If you have full control of what Logback jar is used, you could replace LoggingEvent with your own version. – Darius X. Mar 16 '13 at 21:35
  • That would work. Looks like I'm attempting something quite non-standard; perhaps I should re-evaluate my approach to dealing with these exceptions. Thanks for the ideas. – David B. Mar 20 '13 at 23:17
  • 3
    Looks like this is [a rejected feature request](http://jira.qos.ch/browse/LOGBACK-596). – Eyal Nov 04 '13 at 18:07
  • I think a cleaner solution than the currently accepted answer would be to create a custom conversion specifier for the pattern layout that simply returns the level you like if it finds the level you want to change in the event. Even better, you can make the specifier take evaluators as arguments with braces(like the caller specifier) to print the level you like if an evaluator is matched and place. The condition can be placed in evaluators in the configuration file. – Nick Zafiridis Jan 30 '20 at 13:24

1 Answers1

23

You can simulate this behaviour using a TurboFilter by logging your own modified message with the provided logger, and denying the original.

I'm not convinced this sort of hack is a good idea, though.

package com.example.logback;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.Marker;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.turbo.TurboFilter;
import ch.qos.logback.core.spi.FilterReply;

public class LogbackTest
{
    private static class ModifyingFilter
    extends TurboFilter
    {
        @Override
        public FilterReply decide(
                Marker marker,
                ch.qos.logback.classic.Logger logger, 
                Level level,
                String format, 
                Object[] params, 
                Throwable t)
        {
            if (level == Level.ERROR &&
                logger.getName().equals("com.example.logback.LogbackTest") &&
                format.equals("Connection successful: {}"))
            {
                logger.debug(marker, format, params);
                return FilterReply.DENY;
            }

            return FilterReply.NEUTRAL;
        }
    }

    public static void main(String[] args)
    {
        LoggerContext lc = (LoggerContext)LoggerFactory.getILoggerFactory();
        lc.addTurboFilter(new ModifyingFilter());

        Logger logger = LoggerFactory.getLogger(LogbackTest.class);
        logger.error("Connection successful: {}", "no problem", new RuntimeException("Hi"));
    }
}
  • Thanks god, you a genies – Tommy.Tang Mar 01 '19 at 08:57
  • Since this is denying the original and logging it again, the origin method name(%M or %method) changes to "decide" as it is essentially logged in this method. How do you avoid this? – user1144004 Feb 24 '21 at 05:29
  • 1
    Fixing reference to line and class (and probably method name) you have to add: `lc.getFrameworkPackages().addAll(List.of("ch.qos.logback.core", "ch.qos.logback.classic", "package.for.your.modifying.filter"));` – Kim Rydhof Thor Hansen May 15 '23 at 22:47