1

I'm using Logback for logging, and in several places of my code, I have things like:

  if(message.contains("kitten")) {
    logger.info(message);
  } else if (message.contains("wolf")) {
    logger.error(message);
  }  else if(message.contains("chuck norris")) {
    logger.fatal(message);
  } else  {
    logger.warn(message);
  }

(most of the time the message comes from an external system)

Is there a less ugly way to do?

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
Fabien G.
  • 21
  • 4

3 Answers3

0

As you are using logback as the backend, and you don't specify the logging API you are using, I assume you are using slf4j (logback's native API). Unfortunately, this API is not as flexible as one might like it to be. For example, log4j 2 has Logger.log which takes a Level, and you can then use it like this:

logger.log(levelFor(message), message);
...
private Level levelFor(String message) {
    if (message.contains("kitten"))
        return Level.INFO;
    else if...
        return...
}

Unfortunately, slf4j doesn't have a Logger.log method. You can use log4j2 as your API and bridge it to your logback backend using the appropriate jar dependency.

k314159
  • 5,051
  • 10
  • 32
0

This is an interesting question which also introduces new questions. You could have a list of words which could either escalate or de-escalate the log level for that message.

One approach to this, would be to make your own logger class, which encapsulates your general logging framework, mirroring each of the log methods. The first version for establishment would be simply calling the logging framework behind ie.

public class MyLogger {
    public void info(String message) { Logger.info(message); }
    public void debug(String message) { Logger.debug(message); }
    // And so on
}

Say you have a wordlist you could introduce some words to trigger another level, if contained in message.

public class MyLogger {
    private final List<String> warnTriggerMessages;
    public MyLogger(List<String> warnTrigerMessages) { 
         this.warnTriggerMessages = warnTrigerMessages;
    }
    public void info(String message) {
        if (warnTriggerMessages.stream().anyMatch(trigger => message.contains(trigger))) { 
            Logger.warn(message);
        } else {
             Logger.info(message); 
        }
    }
    // And so on
}

This was just a very simple example, but could be expanded with a more generic approach or intertwined with a strategyPattern, which would resolve the logging method based on a "proposed" log level and the message, where the message could cause the strategy to choos another log level than the proposed loglevel.

Wisienkas
  • 1,602
  • 2
  • 17
  • 22
-1

I don't think there is a way to instruct logback to change the level based on the content and probably you don't want to do so because logging belongs to your business logic.

If you are using jdk 16 and the code is as simple as you shown maybe an switch statement is nicer

switch (message){
  case "kitten"       -> logger.info(message);
  case "wolf"         -> logger.error(message);
  case "chuck norris" -> logger.fatal(message);
  default             -> logger.warn(message);
}
RoberMP
  • 1,306
  • 11
  • 22