{"id":21239396,"url":"https://github.com/kabragaurav/logginglibrary","last_synced_at":"2025-10-17T09:33:28.479Z","repository":{"id":244991624,"uuid":"816850698","full_name":"kabragaurav/LoggingLibrary","owner":"kabragaurav","description":"Simple Logging Library","archived":false,"fork":false,"pushed_at":"2024-06-19T07:41:19.000Z","size":453,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-21T19:24:33.966Z","etag":null,"topics":["chain-of-responsibility-pattern","facade-pattern","factory-pattern","logging-library"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kabragaurav.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-06-18T14:15:48.000Z","updated_at":"2024-11-28T12:54:37.000Z","dependencies_parsed_at":"2025-01-21T19:24:11.319Z","dependency_job_id":"f9e40caa-52d5-42d4-a2c9-ed543ee420ec","html_url":"https://github.com/kabragaurav/LoggingLibrary","commit_stats":null,"previous_names":["kabragaurav/logginglibrary"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kabragaurav%2FLoggingLibrary","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kabragaurav%2FLoggingLibrary/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kabragaurav%2FLoggingLibrary/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kabragaurav%2FLoggingLibrary/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kabragaurav","download_url":"https://codeload.github.com/kabragaurav/LoggingLibrary/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243680974,"owners_count":20330154,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["chain-of-responsibility-pattern","facade-pattern","factory-pattern","logging-library"],"created_at":"2024-11-21T00:43:22.352Z","updated_at":"2025-10-17T09:33:23.453Z","avatar_url":"https://github.com/kabragaurav.png","language":"Java","readme":"# Logging Library \nby Gaurav Kabra\n\n## Problem Statement\n![](./assets/images/logger_lib.png)\n\n## Setup\nWill require `JUnit5.8.1` to run tests.\n\n## Design\n[Inspired from `log4j` and `slf4j`]\n\n![UML](./assets/images/LoggingLib.svg)\n\n1. `Sink` is not concrete. `ConsoleSink` and `TextFileSink` are.\n2. `Logger` is using **singleton design pattern** so that multiple loggers do not overwrite.\n3. We can use **factory design pattern** to create different loggers\n - In that case remove `sink` from `Logger.java` and make it asbtract\n - Then create two sub classes: `ConsoleLogger` and `TextFileLogger`\n4. It is requirement that for any level, all higher level logs must also be logged\n - We have used enum's ability to get higher levels using `getHigherOrEqualLevels()` method\n - In general, we can use **chain of responsibility (cor) design pattern** where we create different levels logger and set next logger. Once one logger is done, it delegates to next logger.\n - But in our impl, cor will lead to complexity - extensibility wise if new level is introduced, we need to create new loggers and set next logger, and if level is between two existing loggers, existing classes will need changes to accommodate new logger as next logger\n5. If some external logger comes into picture (like slf4j), we need to use **facade design pattern**\n\n\n### Quick Examples\n### Singleton Pattern\n\nEnsure that only one instance of the `Logger` class exists.\n\n```java\npublic class Logger {\n    private static Logger instance;\n\n    private Logger() {\n        // Private constructor to prevent instantiation\n    }\n\n    public static Logger getInstance() {\n        if (instance == null) {\n            instance = new Logger();\n        }\n        return instance;\n    }\n\n    public void log(String message) {\n        // Log message to console\n        System.out.println(message);\n    }\n}\n```\n\n### Factory Pattern\n\nCreate different types of loggers using a factory method.\n\n```java\ninterface ILogger {\n    void log(String message);\n}\n\nclass ConsoleLogger implements ILogger {\n    public void log(String message) {\n        System.out.println(\"ConsoleLogger: \" + message);\n    }\n}\n\nclass FileLogger implements ILogger {\n    public void log(String message) {\n        // Log message to a file (simplified)\n        System.out.println(\"FileLogger: \" + message);\n    }\n}\n\nclass LoggerFactory {\n    public static ILogger getLogger(String type) {\n        if (type.equalsIgnoreCase(\"console\")) {\n            return new ConsoleLogger();\n        } else if (type.equalsIgnoreCase(\"file\")) {\n            return new FileLogger();\n        }\n        throw new IllegalArgumentException(\"Unknown logger type\");\n    }\n}\n```\n\n### Chain of Responsibility Pattern\n\nHandle different logging levels.\n\n```java\nabstract class Logger {\n    public static int INFO = 1;\n    public static int DEBUG = 2;\n    public static int ERROR = 3;\n\n    protected int level;\n\n    protected Logger nextLogger;\n\n    public void setNextLogger(Logger nextLogger) {\n        this.nextLogger = nextLogger;\n    }\n\n    public void logMessage(int level, String message) {\n        if (this.level \u003c= level) {\n            write(message);\n        }\n        if (nextLogger != null) {\n            nextLogger.logMessage(level, message);\n        }\n    }\n\n    protected abstract void write(String message);\n}\n\nclass ConsoleLogger extends Logger {\n    public ConsoleLogger(int level) {\n        this.level = level;\n    }\n\n    @Override\n    protected void write(String message) {\n        System.out.println(\"ConsoleLogger: \" + message);\n    }\n}\n\nclass ErrorLogger extends Logger {\n    public ErrorLogger(int level) {\n        this.level = level;\n    }\n\n    @Override\n    protected void write(String message) {\n        System.err.println(\"ErrorLogger: \" + message);\n    }\n}\n\n// Usage\npublic class ChainPatternDemo {\n    private static Logger getChainOfLoggers() {\n        Logger errorLogger = new ErrorLogger(Logger.ERROR);\n        Logger consoleLogger = new ConsoleLogger(Logger.INFO);\n\n        errorLogger.setNextLogger(consoleLogger);\n\n        return errorLogger;\n    }\n\n    public static void main(String[] args) {\n        Logger loggerChain = getChainOfLoggers();\n\n        loggerChain.logMessage(Logger.INFO, \"This is an informational message.\");\n        loggerChain.logMessage(Logger.ERROR, \"This is an error message.\");\n    }\n}\n```\n\n### Facade Pattern\n\n```java\ninterface ILogger {\n    void log(String message);\n}\n\nclass ConsoleLogger implements ILogger {\n    public void log(String message) {\n        System.out.println(\"ConsoleLogger: \" + message);\n    }\n}\n\nclass FileLogger implements ILogger {\n    public void log(String message) {\n        // Log message to a file (simplified)\n        System.out.println(\"FileLogger: \" + message);\n    }\n}\n\nclass SLF4JLogger implements ILogger {\n    private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(SLF4JLogger.class);\n\n    public void log(String message) {\n        logger.info(message);\n    }\n}\n\nclass LoggerFactory {\n    public static ILogger getLogger(String type) {\n        switch (type.toLowerCase()) {\n            case \"console\":\n                return new ConsoleLogger();\n            case \"file\":\n                return new FileLogger();\n            case \"slf4j\":\n                return new SLF4JLogger();\n            default:\n                throw new IllegalArgumentException(\"Unknown logger type\");\n        }\n    }\n}\n\nclass LoggerFacade {\n    private ILogger logger;\n\n    public LoggerFacade(String type) {\n        this.logger = LoggerFactory.getLogger(type);\n    }\n\n    public void log(String message) {\n        logger.log(message);\n    }\n}\n\n// Usage\npublic class FacadePatternDemo {\n    public static void main(String[] args) {\n        LoggerFacade consoleLogger = new LoggerFacade(\"console\");\n        consoleLogger.log(\"Logging to console\");\n\n        LoggerFacade fileLogger = new LoggerFacade(\"file\");\n        fileLogger.log(\"Logging to file\");\n\n        LoggerFacade slf4jLogger = new LoggerFacade(\"slf4j\");\n        slf4jLogger.log(\"Logging using SLF4J\");\n    }\n}\n```\nThis approach enhances flexibility and encapsulates the complexity of logger instantiation and usage, making it easier to switch or add new logging mechanisms.\n\nThese examples demonstrate the application of design patterns to create a flexible and extensible logging library in Java.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkabragaurav%2Flogginglibrary","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkabragaurav%2Flogginglibrary","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkabragaurav%2Flogginglibrary/lists"}