[Architecture Pattern] inversion of Logging

Source: Internet
Author: User
Tags log4net

Motivation

Log is an indispensable function for the development of a software system. Whether it is problem tracing or status analysis, with log assistance, developers can trace the problem. For the implementation modules of these log functions, developers can choose the EventLog built in. net, or the third-party log4net .... And so on. There are so many implementation modules that can be used to simplify the workload of developers, but it also brings another problem: "The system adds dependencies between log implementation modules 」.

 

Suppose we are developing a user module, which uses EventLog to complete the log function. After a long period of verification, it is confirmed that the user module is stable and powerful. Another project now needs to use functions related to the user module, and this project uses log4net to complete the log function. At this time, it will be embarrassing to find that the new project and user module adopt two sets of implementation modules with different log functions.

 

Of course, during program development, developers can ignore this issue, and compilation will always pass the function normally. However, as a result, the deployment personnel who subsequently take over must understand the setting methods of two different implementation modules. Of course, this can also be handled by means of non-program development. However, when the system grows larger and the number of log modules increases, some part of the team will attack developers one day. In addition, for developers themselves, these additional Module Settings will increase the workload of developers more or less during unit testing of the development system.

 

This article introduces an inversion of logging implementation that applies the IOC mode. This implementation defines the responsibilities and interactions between objects and is used to reverse the system's dependency on log modules and solve the above problems. Make a record for yourself and hope to help developers who need it.

 

Implementation

Model column download

For more information, see the sample program content: inversion of logging.
(* The execution example can be executed normally only after the system administrator privilege is granted .)

 

Ilogger

To switch the Log Module, you must first create an abstract ilogger interface. So that the system can use the log function only by relying on this abstraction module. The Log Module for system replacement needs to implement this ilogger interface to provide the log function.

 

namespace CLK.Logging{    public enum Level    {        Error,        Warning,        Information,        SuccessAudit,        FailureAudit,    }}

 

namespace CLK.Logging{    public interface ILogger    {        // Methods        void Log(Level level, string message);        void Log(Level level, string message, System.Exception exception);    }}

 

Logmanager

Then proceed to process the logmanager object that generates the ilogger object. This logmanager object applies the singleton mode, so that only a unique logmanager object exists in the system, and only a unique logmanager object exists between different modules in the system. In this way, the ilogger object between different modules can be controlled by a unique logmanager object.

 

Logmanager is an abstract class that provides the function for generating ilogger objects and releasing their own objects. To implement the logmanager class, you need to implement these two interfaces to provide the function of managing the ilogger object lifecycle. In addition, different log settings may be required between different modules. Therefore, a string parameter is added to the function of generating the ilogger object to let the logmanager category identify different modules to generate different set ilogger objects. As for the function of releasing objects, only the entry for uniformly releasing resources is reserved for objects in the logmanager category.

 

namespace CLK.Logging{    public abstract class LogManager : IDisposable    {        // Singleton        private static LogManager _current;        public static LogManager Current        {            get            {                // Require                if (_current == null) throw new InvalidOperationException();                // Return                return _current;            }            set            {                // Require                if (_current != null) throw new InvalidOperationException();                // Return                _current = value;            }        }                // Methods        public abstract ILogger CreateLogger(string name);        public abstract void Dispose();    }    }

 

Eventlogmanager

In the sample program, the Log Module implements EventLog and writes log information to Windows event records. The related program code is as follows. Interested developers can spend some time learning. When they need to expand the Log Module (for example, log4net), they can add relevant implementations on their own.

 

namespace CLK.Logging.Implementation{    public static class EventLogLevelConvert    {        public static EventLogEntryType ToEventLogEntryType(Level level)        {            switch (level)            {                case Level.Error: return EventLogEntryType.Error;                case Level.Warning: return EventLogEntryType.Warning;                case Level.Information: return EventLogEntryType.Information;                case Level.SuccessAudit: return EventLogEntryType.SuccessAudit;                case Level.FailureAudit: return EventLogEntryType.FailureAudit;                default: return EventLogEntryType.Error;            }        }    }}

 

namespace CLK.Logging.Implementation{    public class EventLogLogger : ILogger    {        // Fields        private readonly string _sourceName = null;        // Constructors        public EventLogLogger(string sourceName)        {            #region Contracts            if (string.IsNullOrEmpty(sourceName) == true) throw new ArgumentException();            #endregion            _sourceName = sourceName;        }        // Methods        public void Log(Level level, string message)        {            this.Log(level, message, null);        }        public void Log(Level level, string message, Exception exception)        {            #region Contracts            if (string.IsNullOrEmpty(message) == true) throw new ArgumentException();            #endregion            if (EventLog.SourceExists(_sourceName)==false)            {                EventLog.CreateEventSource(_sourceName, null);            }            EventLog eventLog = new EventLog();            eventLog.Source = _sourceName;            eventLog.WriteEntry(string.Format("Message={0}, Exception={1}", message, exception == null ? string.Empty : exception.Message), EventLogLevelConvert.ToEventLogEntryType(level));        }    }    }

 

namespace CLK.Logging.Implementation{    public class EventLogManager : LogManager    {        // Methods        public override ILogger CreateLogger(string name)        {            return new EventLogLogger(name);        }        public override void Dispose()        {        }    }}

 

Use

Usermodule. Logging. Logger

Next, write a virtual usermodule to demonstrate how to apply inversion of logging. First, add the namespace logging to the usermodule. You need to reference this namespace if you need to use the log function in the usermodule. In addition, create a logger object in the logging naming room, copy and paste the following program code into the logger object, and then write the logger object.

 

This logger object uses the component name as the identification and generates an ilogger object for log implementation by calling a unique logmanager object. In addition, the ilogger object function is encapsulated to become a static function that makes the system more convenient to use.

 

namespace UserModule.Logging{    internal static class Logger    {        // Singleton         private static ILogger _currentLogger;        private static ILogger CurrentLogger        {            get            {                if (_currentLogger == null)                {                    _currentLogger = LogManager.Current.CreateLogger(typeof(Logger).Assembly.GetName().Name);                }                return _currentLogger;            }        }        // static Methods        public static void Log(Level level, string message)        {            CurrentLogger.Log(level, message);        }        public static void Log(Level level, string message, System.Exception exception)        {            CurrentLogger.Log(level, message);        }    }}

 

Usermodule. User

After writing these programs, you only need to use the abstract ilogger implementation to use the log function in the usermodule, instead of relying on the currently used log module.

 

namespace UserModule{    public class User    {        public void Test(string message)        {            // Do            // Log            Logger.Log(CLK.Logging.Level.Information, "OK");        }    }}

 

Run

Finally, the usermodule system inversionofloggingsample is created, and logmanager is injected into the inversionofloggingsample. current is used to determine which Log Module the system uses. As long as the log information is in the same system, the log module is used to complete the log function.

 

Developers can use the di framework to generate a logmanager and inject it into logmanager. Current to complete the function of the log module. In unit test scenarios, emptylogger provided in the sample file can be injected to simplify the log settings during unit test.

 

namespace InversionOfLoggingSample{    class Program    {        static void Main(string[] args)        {            // Init            LogManager.Current = new EventLogManager();            // Test            User user = new User();            user.Test("Clark=_=y-~");        }    }}

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.