Improved logging and improved logging
Compared with the log records sent earlier, this type separates program record processing from disk write operations. The user code part puts the logs in the queue and notifies the thread to write the logs to the file:
1. Public class:
Using System;
Using System. IO;
Using System. Collections. Generic;
Using static System. Console;
Using System. Text;
Using System. Diagnostics;
Namespace LogWriter
{
/// <Summary>
/// Log Type
/// </Summary>
Public enum LogType
{
Error,
Info,
Waring,
Success,
Failure
}
/// <Summary>
/// Log parameter information
/// </Summary>
Internal struct LogInfo
{
Internal string FileName {get; set ;}
Internal string MethodName {get; set ;}
Internal int Line {get; set ;}
Internal int Column {get; set ;}
Internal string LogType {get; set ;}
}
/// <Summary>
/// Public day
/// </Summary>
Internal class LogCommon
{
Static System. Threading. ReaderWriterLockSlim Slim = new System. Threading. ReaderWriterLockSlim (System. Threading. LockRecursionPolicy. SupportsRecursion );
/// <Summary>
/// Obtain log parameter information
/// </Summary>
/// <Param name = "type"> type </param>
/// <Returns> </returns>
Internal static LogInfo GetLog (LogType type)
{
StackTrace st = new StackTrace (2, true );
StackFrame sf = st. GetFrame (0 );
LogInfo li = new LogInfo ()
{
FileName = sf. GetFileName (),
MethodName = sf. GetMethod (). Name,
Line = sf. GetFileLineNumber (),
Column = sf. GetFileColumnNumber (),
};
String logType = "-Error ";
Switch (type)
{
Case LogType. Error:
LogType = "-Error ";
Break;
Case LogType. Info:
LogType = "-Info ";
Break;
Case LogType. Waring:
LogType = "-Waring ";
Break;
Case LogType. Success:
LogType = "-Success ";
Break;
Case LogType. Failure:
LogType = "-Failure ";
Break;
Default:
LogType = "-Error ";
Break;
}
Li. LogType = logType;
Return li;
}
/// <Summary>
/// Write log files separated by hours
/// </Summary>
/// <Param name = "Msg"> message to be logged </param>
/// <Param name = "li"> log information class </param>
/// <Param name = "LogPath"> log folder </param>
/// <Returns> </returns>
Internal static string WriteLineToTimeFile (string Msg, LogInfo li, string LogPath)
{
If (string. IsNullOrEmpty (Msg ))
{
Return "the input parameter Msg is null or the value is null does not meet the record requirements! ";
}
StreamWriter sw = null;
Try
{
Slim. EnterWriteLock ();
// String Dir = System. Windows. Forms. Application. StartupPath + @ "\ GLogs \" + DateTime. Now. ToString ("MM dd, yyyy ");
CheckLog (LogPath );
String file = DateTime. Now. ToString ("MM dd, yyyy") + ". log ";
Checkfile (LogPath, file );
String fileName = LogPath + "\" + file;
Sw = File. AppendText (fileName );
Sw. writeLine ("log time:" + DateTime. now. toString () + ", file name:" + li. fileName + ", method name:" + li. methodName + "row number:" + li. line + ", column:" + li. column + ", Log Type:" + li. logType );
Sw. WriteLine ("log Content:" + Msg );
Return nameof (WriteLineToTimeFile) + "logging operation successful! ";
}
Catch (Exception ex)
{
Return nameof (WriteLineToTimeFile) + "log record error:" + ex. Message;
}
Finally
{
Sw. Close ();
Slim. ExitWriteLock ();
}
}
/// <Summary>
/// Check whether the log directory exists. If it does not exist, create
/// </Summary>
/// <Param name = "Path"> folder </param>
Internal static void checkLog (string Path)
{
If (! Directory. Exists (Path ))
{
Directory. CreateDirectory (Path );
}
}
/// <Summary>
/// Input the path name and file name to create a log file
/// </Summary>
/// <Param name = "DirName"> folder </param>
/// <Param name = "FileName"> file name </param>
Internal static void checkfile (string DirName, string FileName)
{
If (! File. Exists (DirName + @ "\" + FileName ))
{
File. Create (DirName + @ "\" + FileName). Close ();
}
}
}
}
2. gLog class:
Using System;
Using System. IO;
Using System. Collections. Generic;
Using static System. Console;
Using System. Text;
Using System. Threading;
Using System. Threading. Tasks;
Namespace LogWriter
{
/// <Summary>
/// Improve the log record speed through the queue Cache
/// </Summary>
Public class GLog
{
Readonly object lockobj = new object ();
TimerCallback tc;
Timer timer;
Queue <LogQueueStruct> LogList = new Queue <LogQueueStruct> ();
Public string LogPath {get; set;} = System. windows. forms. application. startupPath + @ "\ Logs \" + DateTime. now. toString ("MM dd, yyyy ");
Public void RecordLog (LogType type, string msg)
{
LogQueueStruct log = new LogQueueStruct ()
{
Info = LogCommon. GetLog (type ),
Msg = msg
};
Lock (lockobj)
{
LogList. Enqueue (log );
}
Timer. Change (0, Timeout. Infinite );
}
Public void RegiestLog ()
{
// Enable a thread to record logs in the queue to a file
Tc = new TimerCallback (o) =>
{
Timer. Change (Timeout. Infinite, Timeout. Infinite );
Lock (lockobj)
{
If (LogList. Count> 0)
{
LogQueueStruct log = LogList. Dequeue ();
LogCommon. WriteLineToTimeFile (log. Msg, log.info, LogPath );
}
}
});
Timer = new Timer (tc, null, Timeout. Infinite, Timeout. Infinite );
}
Public int LogListCount => LogList. Count;
}
Internal class LogQueueStruct
{
Internal LogInfo info {get; set ;}
Internal string Msg {get; set ;}
}
}
3. call:
GLog log = new GLog ();
Log. RegiestLog (); // initialization record thread (timer)
System. Diagnostics. Stopwatch stopwatch = new System. Diagnostics. Stopwatch ();
Stopwatch. Start ();
For (int I = 0; I ++ <1000 ;)
{
Log. RecordLog (LogType. Info, $ "log Record Test Data {I }");
}
Stopwatch. Stop ();
Console. WriteLine (stopwatch. Elapsed. TotalSeconds );
Console. WriteLine ("some program operations are completed! ");
Console. ReadLine ();
Compared with TxtLog:
TxtLog log = TxtLog. Instance;
// Initialize record thread (timer)
System. Diagnostics. Stopwatch stopwatch = new System. Diagnostics. Stopwatch ();
Stopwatch. Start ();
For (int I = 0; I ++ <1000 ;)
{
Log. WriteLineToFile ($ "log Record Test Data {I}", LogType. Info );
}
Stopwatch. Stop ();
Console. WriteLine ($ "call {nameof (TxtLog)} Time consumed: {stopwatch. Elapsed. TotalSeconds }");
Console. WriteLine ("some program operations are completed! ");
Console. ReadLine ();
The program operation time is several times different! This shows the benefits of separating the user's calling part and writing disk files in the background!