Logging is very important for applications. Thanks to the logs, we can access the data states of the application. For example, Crash logs are very important for us to learn why the application crashed. In the same way, we can even monitor the performance. In short, logging has a lot of importance, especially after the application is released, it is useful in monitoring anomalies in the online version.

Log Storage Classification

In a normal development process, we debug our application in Debug Mode. Thanks to break points, we can monitor the changes in the data. In addition to Debug we can also use console outputs, such as “system.out.println()” in Java, “Console.WriteLine()” in .NET, “print()” in Swift. In Unity, unity allows us to keep a “Debug.Log()” log.
However, in our online versions, we cannot keep the data of our applications as above.

If we look from the perspective of Log Storege Classification; it can be divided into four categories: console, file system, database and third-party platform.

  • Console: It is used to monitor data working methods during the development process in Local.
  • File System: It is used for logging of user behavior, for monitoring time and performance. If the user accepts, the records are sent to the server.
  • Database: If the user has accepted it, it is used to be sent to the server for tracking abnormal behavior that occurs as a result of the application crashing. Third-Party: eg Umeng etc., if the application crashes, necessary records are saved in Umeng and monitored by DashBord.

Designing Log Component

We can use our own or Third-Party, but here we will mix and use. The component representation we will make is shown below:

Log Component UML

Log Component Implementation

LogFactory is for encapsulating the code needed to build the LogStrategy component.

public class LogFactory
{
    public static LogFactory Instance=new LogFactory();
    private LogFactory(){}
    private readonly Dictionary<string,LogStrategy> _strategies=new Dictionary<string, LogStrategy>()
    {
        {typeof(ConsoleLogStrategy).Name,new ConsoleLogStrategy() },
        {typeof(FileLogStrategy).Name,new FileLogStrategy() },
        {typeof(DatabaseLogStrategy).Name,new DatabaseLogStrategy() }
    }; 
    public LogStrategy Resolve<T>() where T:LogStrategy
    {
        return _strategies[typeof(T).Name];
    }
}

LogFactory is a Dictionary and holds strategy name as Key and Strategy class as Value.
LogStrategy is an abstract class, it represents the Template in the figure.

public abstract class LogStrategy
{
    private readonly StringBuilder _messageBuilder=new StringBuilder();
    protected IContentWriter Writer { get; set; }

    /// <summary>
    ///     Template method
    /// </summary>
    protected abstract void RecordMessage(string message);

    protected abstract void SetContentWriter();

    /// <summary>
    ///     Public API
    /// </summary>
    public void Log(string message,bool verbose=false)
    {
        if (verbose)
        {
            //Public Method
            RecordDateTime();
            RecordDeviceModel();
            RecordDeviceName();
            RecordOperatingSystem();
        }
        //Abstract methods, handed over to subclasses to implement
        RecordMessage(_messageBuilder.AppendLine(string.Format("Message:{0}", message)).ToString());
    }

    private void RecordDateTime()
    {
        _messageBuilder.AppendLine(string.Format("DateTime:{0}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")));
    }

    private void RecordDeviceModel()
    {
        _messageBuilder.AppendLine(string.Format("Device Model:{0}",SystemInfo.deviceModel));
    }

    private void RecordDeviceName()
    {
        _messageBuilder.AppendLine(string.Format("Device Name:{0}", SystemInfo.deviceName));
    }

    private void RecordOperatingSystem()
    {
        _messageBuilder
            .AppendLine(string.Format("Operating System:{0}", SystemInfo.operatingSystem))
            .AppendLine();
    }
}

Template Method Pattern is used, explain that too.
When we debug in the console, we do not need some information, for example device name, etc. Therefore, Log provides a transition to verbose to detail the information needed. Initially it is false, that is, in the off state.
Inheriting LogStrategy and creating my own log strategy. For example, to do FileLogStrategy.

public class FileLogStrategy : LogStrategy
{
    public FileLogStrategy()
    {
        SetContentWriter();
    }
    protected sealed override void SetContentWriter()
    {
        Writer = new FileContentWriter(); 
    }
    protected override void RecordMessage(string message)
    {
        Writer.Write(message);
    }
}