Recently in the use of log4net, before using, we must know how the file stream operation, or the blind touch ... , there is a lockingmodelbase in the FileAppender.cs file to control the lock of the stream, the default is 3 sub-classes
Exclusivelock: Default, hold a exclusive lock on the output file,open the file once for writing and hold it Open until Closefil E is called. Maintains an exclusive lock on the file during this time.
Minimallock:acquires the file lock for each write,opens the file once for each acquirelock/releaselock cycle, thus holdi Ng the lock for the minimal amount of time. This method of locking was considerably slower than Fileappender.exclusivelock but allows other processes to move/delete th E log file whilst logging continues.
Interprocesslock:provides cross-process file locking. Using mutexes to implement multiple processes
This means that minimallock is slower than exclusivelock because it opens and closes the file stream every time.
But there are 2 of classes that feel more important PatternString.cs
and PatternLayout.cs
If the log file is in a common directory, it is recommended that you log files plus the computer name, application name, process ID (such as multiple workers on the web) such as:
<file type= "log4net. Util.patternstring "value=" \\192.168.0.1\logs\%env{computername}\%appsetting{applicationname}\%processid\log\ "/ >
But the log records here by default are synchronized, but I personally tend to use asynchronous multi-threaded thinking to write log, first log information recorded in the memory Concurrentqueue inside, It then logs the contents of the Concurrentqueue into the file stream through a background thread . As for the performance of how much more I would like to say no more, write memory must be faster than writing flow
The specific implementation code is as follows:
[Assembly:log4net. Config.xmlconfigurator (Watch = true, ConfigFile = "Log4net.config")]namespace consoleapp{using Log4net; Using System; Using System.Collections.Concurrent; Using System.Threading; Using System.Threading.Tasks; public sealed class Queuelogger {//<summary>///Record Message queue///</summary> PR Ivate readonly concurrentqueue<queuelogmessage> _que; <summary>///signal///</summary> private readonly ManualResetEvent _mre; <summary>///journal///</summary> private readonly ILog _log; <summary>///Log///</summary> private static Queuelogger Flashlog = new Queuelogger (); Private Queuelogger () {//Set Log profile path//xmlconfigurator.configure (New FileInfo (Path.Combine (A PpDomain.CurrentDomain.BaseDirectory, "Log4net.config"))); _que = new ConcurreNtqueue<queuelogmessage> (); _mre = new ManualResetEvent (false); _log = Logmanager.getlogger (System.Reflection.MethodBase.GetCurrentMethod (). DeclaringType); Task.run (() = {Writelog ();}); }///<summary>//write logs from the queue to disk///</summary> private void Writelog () { while (true) {//waits for signal notification _mre. WaitOne (); Queuelogmessage msg; Determine if there is a need for content such as a disk to get content from a queue and delete the contents of a queue while (_que. Count > 0 && _que. Trydequeue (out msg)) {//Judge log level, then write log switch (MSG. Level) {case Queueloglevel.debug: _log. Debug (Msg. Message, Msg. Exception); Break Case Queueloglevel.info: _log. Info (Msg. Message, Msg. Exception); Break Case Queueloglevel.error: _log. Error (Msg. Message, Msg. Exception); Break Case Queueloglevel.warn: _log. Warn (Msg. Message, Msg. Exception); Break Case Queueloglevel.fatal: _log. Fatal (Msg. Message, Msg. Exception); Break }}//Reset signal _mre. Reset (); }}///<summary>//write Log///</summary>//<param name= "message" > Log Text </param>//<param Name= "level" > Grade </param>//<param name= "ex" >exception</par am> public void Enqueuemessage (String message, queueloglevel level, Exception ex = null) {if (level = = Queueloglevel.debug && _log. Isdebugenabled) || (level = = Queueloglevel.error && _log. iserrorenabled) | | (level = = Queueloglevel.fatal && _log. isfatalenabled) | | (level = = Queueloglevel.info && _log. isinfoenabled) | | (level = = Queueloglevel.warn && _log. iswarnenabled)) {_que. Enqueue (new Queuelogmessage {//Message = "[" + DateTime.Now.ToString ("Yyyy-mm-dd hh:mm : ss,fff ") +"]\r\n "+ message, message = message, level = level, Exception = ex}); Notifies the thread to write log _mre to disk. Set (); }} public static void Debug (String msg, Exception ex = null) {Flashlog.enqueuemessage (ms G, Queueloglevel.debug, ex); public static void Error (String msg, Exception ex = null) {flashlog.enqueuemessage (msg, Queuel Oglevel.error, ex); } public static void Fatal (String msg, Exception ex = null) {flashlog.enqueuemessage (msg, queueloglevel . Fatal, ex); } public static void Info (String msg, Exception ex = null) {flashlog.enqueuemessage (msg, Queuelo Glevel.info, ex); } public static void Warn (String msg, Exception ex = null) {flashlog.enqueuemessage (msg, Queuelo Glevel.warn, ex); }}///<summary>///log level///</summary> public enum Queueloglevel {Debug, I NFO, Error, Warn, Fatal}//<summary>//log content///</summary> public CLA SS Queuelogmessage {public string Message {get; set;} Public Queueloglevel level {get; set;} Public Exception Exception {get; set;} }}
namespace log4net{using Layout; Using System.IO; Using System.Text; Using Util; Using Core; public class Csvpatternlayout:patternlayout {public override void Activateoptions () {Addco Nverter ("Newfield", typeof (Csvnewfiledconverter)); Addconverter ("Endrow", typeof (Csvendrowconverter)); Base. Activateoptions (); public override void Format (TextWriter writer, loggingevent loggingevent) {var csvwriter = new Csvtextwriter (writer); Csvwriter.writequote (); Base. Format (Csvwriter, loggingevent); }} public class Csvtextwriter:textwriter {private readonly TextWriter TextWriter; Public Csvtextwriter (TextWriter txtwriter) {TextWriter = Txtwriter; } public override void Write (char value) {//base. Write (value); Textwriter.write (value); if (value = = ' "')//{ }} public void Writequote () {textwriter.write (' "'); } public override Encoding Encoding {get {return textwriter.encoding; }}} public class Csvnewfiledconverter:patternconverter {protected override void Co Nvert (TextWriter writer, object state) {var csvwriter = writer as csvtextwriter; Csvwriter?. Writequote (); Writer. Write (","); Csvwriter?. Writequote (); }} public class Csvendrowconverter:patternconverter {protected override void Convert (TextWriter writer , object state) {var csvwriter = writer as csvtextwriter; Csvwriter?. Writequote (); Writer. WriteLine (); } }}
A comma is required in the configuration file
<layout type= "log4net. Csvpatternlayout,consoleapp ">
Here & #13;& #10; \r\n,%newfield is a comma,%endrow is a comma + newline
See here in fact we can join the content of the CSV itself, that is, as long as there is, \ r \ n can
<layout type= "log4net. Layout.patternlayout ">
Call Code:
StringBuilder sb = new StringBuilder (); sb. Append ("Test"); sb. Append ("\", \ ""); sb. Append ("Debug"); Queuelogger.debug (sb.) ToString ());
The information written is"test", "Debug", in addition to the configuration of the Conversionpattern, "" "Debug". The entire configuration is as follows:
<?xml version= "1.0" encoding= "Utf-8"?><configuration> <configSections> <section name= "Log4net" Type= "Log4net. Config.log4netconfigurationsectionhandler, log4net "/> </configSections> <log4net xmlns:xsi="/http Www.w3.org/2001/XMLSchema-instance "> <appender name=" InfoLog "type=" log4net. Appender.rollingfileappender "> <param name=" File "value=" Log\info\info "/> <param name=" AppendToFile "Value=" true "/> <appendtofile value=" true "/> <maxsizerollbackups value="/> <maxim " Umfilesize value= "10MB"/> <staticlogfilename value= "false"/> <rollingstyle value= "Composite"/> <datepattern value= "YyyyMMdd '. csv '"/> <lockingmodel type= "log4net. Appender.fileappender+minimallock "/> <layout type=" log4net. Csvpatternlayout,consoleapp ">