C# Logging design: Extension method, alternatives?

2019-05-21 05:13发布

I'd like to write a logger that can be easily appended to any class in my current project. For development, it will be convenient to log messages to the console, whereas in the final release I'd like to log to a file or something. One should be able to change the behavior by editing just a few lines of code, or ideally a settings file.

What I have so far is this class structure:

public interface ILogger {
    void LogMessage(String message);
    // ... other logging functions (exceptions, time etc.) don't matter here
};

public interface ILoggable { };

public static class LoggingProvider {
    private static ILogger logger = ConsoleLogger.handle;
        public static void LogMessage(this ILoggable obj, String message) {
        logger.LogMessage(message);
    }
}


public sealed class NullLogger : ILogger {
        // A logger that does nothing..
};

public sealed class FileLogger : ILogger {
    // A logger that writes to a file..
};

public sealed class ConsoleLogger : ILogger {
    #region Console Allocation
    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool AllocConsole();
    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool FreeConsole();
    #endregion

    #region Singleton implementation
    private static Object cs = new Object();
    private static ILogger instance = null;
    private ConsoleLogger() {
        AllocConsole();
    }
    ~ConsoleLogger() {
        FreeConsole();
    }
    public static ILogger handle {
        get {
            lock ( cs ) { if ( instance == null ) instance = new ConsoleLogger(); }
            return instance;
        }
    }
    #endregion

    #region ILogger Member
    public void LogMessage(string message) {
        lock ( cs ) {
            String logString = getTimeString();
            logString += ( " -> \t " + message );
            Console.WriteLine(logString);
        }
    }
    #endregion

    #region Helper functions
    // ...
    #endregion
};

Now, I can have any class I'd like to implement ILoggable, and via the Extension Method LogingProvider.LogMessage I can call this.LogMessage("...") within these classes. If it was C++, I'd just use private inheritance instead.

Is this now good or bad design? Anything I can improve? Is there a way to provide classes with logging functionality without the extension method, but with similarly few changes?

1条回答
疯言疯语
2楼-- · 2019-05-21 05:29

Your design seems a bit over-engineered at first sight. In this method:

public static void LogMessage(this ILoggable obj, String message) {
    logger.LogMessage(message);
}

the ILoggable obj is not used at all. Why do you need it then? Why not just have:

public static void LogMessage(String message) {
    logger.LogMessage(message);
}

and call it LoggingProvider.LogMessage(...)?

On a side note, take a look at Log4Net, this is the industry standard implementation of logging functionality.

查看更多
登录 后发表回答