Logging Framework - Low Level Design
Anonymous User
544

Logging Framework

This I have written as part of my LLD Practice. Please let me know further imporvements that can be done.

Also current design is Strong/Average/Lean Hire

Other Design Problems

/*
Requirements -

1. Support multiple log levels – e.g., Debug, Info, Warn, Error, with priority control.

2. Flexible output destinations – logs can be sent to console, files, databases, or other custom targets.

3. Pluggable formatters – support different formats such as plain text, JSON, XML, etc.

4. Configurable routing – control which log levels go to which appenders.

5. Priority-based filtering with default fallback – ignore messages below the configured level and ensure a default appender always handles logs.
*/
import sun.rmi.runtime.Log;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

enum LogLevel{
    Debug(1), Info(2), Warn(3), Error(4);
    int value;

    LogLevel(int val){
        this.value=val;
    }
}

class LogMessage{
    LogLevel logLevel;
    String message;
    String source;
    LocalDateTime timeStamp;
}

interface LogFormatter{
    String format(LogMessage logMessage);
}

class TextFormatter implements LogFormatter{

    @Override
    public String format(LogMessage logMessage){

    }
}

interface LogAppender{
    void append(LogMessage logMessage);
}

class ConsoleAppender implements LogAppender{
    LogFormatter logFormatter;

    ConsoleAppender(LogFormatter formatter){
        this.logFormatter=formatter;
    }

    @Override
    public void append(LogMessage logMessage){
        System.out.println(logFormatter.format(logMessage));
    }
}

class FileAppender implements LogAppender{
    LogFormatter logFormatter;
    String path;

    FileAppender(LogFormatter formatter, String path){
        this.logFormatter=formatter;
        this.path=path;
    }

    @Override
    public void append(LogMessage logMessage){
        System.out.println(logFormatter.format(logMessage));
    }
}

class LoggerConfig{
    LogLevel logLevel;
    Map<LogLevel,List<LogAppender>> appenderMap=new HashMap<>();
    LogAppender defaultAppender;

    LoggerConfig(LogLevel minLevel, LogAppender defaultAppender){
        this.logLevel=minLevel;
        this.defaultAppender=defaultAppender;
    }

    void setLogLevel(LogLevel minLevel){
        this.logLevel=minLevel;
    }

    void addLogAppender(LogLevel level, LogAppender logAppender){
        appenderMap.get(level).add(logAppender);
    }

    List<LogAppender> getLogAppender(LogLevel level){
        return appenderMap.getOrDefault(level, Arrays.asList(defaultAppender));
    }
}

class Logger{
    LoggerConfig config;

    Logger(LoggerConfig config){
        this.config=config;
    }

    void log(LogLevel logLevel, String message){
        if(logLevel.value<config.logLevel.value) return;

        LogMessage logMessage=new LogMessage();

        for(LogAppender app:config.getLogAppender(logLevel)){
            app.append(logMessage);
        }
    }

    void debug(String message){
        log(LogLevel.Debug,message);
    }

    void info(String message){
        log(LogLevel.Info,message);
    }

    void warn(String message){
        log(LogLevel.Warn,message);
    }

    void error(String message){
        log(LogLevel.Error,message);
    }
}

public class LoggingFramework {
    public static void main(String[] args) {

        LoggerConfig config=new LoggerConfig(LogLevel.Info,new ConsoleAppender(new TextFormatter()));
        config.addLogAppender(LogLevel.Info, new ConsoleAppender(new TextFormatter()));
        config.addLogAppender(LogLevel.Error, new ConsoleAppender(new TextFormatter()));
        config.addLogAppender(LogLevel.Error, new FileAppender(new TextFormatter(),"error.txt"));

        Logger logger=new Logger(config);
        logger.debug("Debugg"); //ignored
        logger.info("Info"); // console
        logger.warn("Warning");  // default -> console
        logger.error("Error"); // console+file

    }
}
Comments (0)