C#日志记录工具 MicroLog

Posted Thomas会写字

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C#日志记录工具 MicroLog相关的知识,希望对你有一定的参考价值。

一个简单的日志记录工具,性能高效,常用功能都有,结构简单。 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Threading;
using System.IO;

namespace SystemTools

    public class MLog
    
        public MFilter filter = new MFilter();
        public MConvert convert = new MConvert();
        public MThr thr = new MThr();
        public List<MLog> transTo = new List<MLog>();
        public delegate void WriteDelegate(LogItem log);
        public event WriteDelegate OnWrite;
        public void Write(String msg, MType type = MType.mType1, Exception e = null)
        
            LogItem log = new LogItem(type, msg, e);
            if (transTo != null)
                for (int i = 0; i < transTo.Count; i++)
                    transTo[i].Write(msg, type, e);

            // Thr
            log.thrName = thr.Name;

            // filter
            if (filter.Filt(log) == false) return;

            // convert
            convert.FormatLog(log);

            // write
            OnWrite(log);
        
    
    public class LogItem
    
        public DateTime time;
        public Exception e;
        public String thrName;
        public String mark;
        public byte[] logHead;
        public String msg;
        public MType type;

        public String fileName;
        public String filePath;
        public String fileExten;

        public int thrID = -1;
        public int logSize = 0;

        public byte[] logBuf;

        public bool IsStableName = false;

        public LogItem(MType type, String msg, Exception e = null)
        
            time = DateTime.Now;
            this.type = type;
            this.msg = msg;
            this.e = e;
        
    
    public class MConvert
    
        public bool IsEnableLogHead = false;
        public bool IsStableName = false;

        byte[] logHead = null;
        String logName = "";
        String logNameExt = "";
        String logMark = "";
        String logLayout = "";
        String pathLayout = "";
        List<String> listLogLayout = null;
        List<String> listPathLayout = null;
        Dictionary<String, int> dictLog;
        Dictionary<int, String> dictPath;

        public MConvert()
        
            LogName = "mlog.log";
            LogLayout = "time msg";
            PathLayout = ".\\\\Mlog";
        
        public String LogHead
        
            get
            
                if (logHead == null || logHead.Length == 0) return "";
                return Encoding.UTF8.GetString(logHead, 0, logHead.Length - 1);
            
            set
            
                logHead = Encoding.UTF8.GetBytes(value + "\\n");
            
        
        public String LogName
        
            get
            
                return logName + "." + logNameExt;
            
            set
            
                int n = value.LastIndexOf('.');
                if (n > 0)
                
                    logName = value.Substring(0, n);
                    logNameExt = value.Substring(n + 1, value.Length - n - 1);
                
                else
                
                    logName = value;
                    logNameExt = "log";
                
            
        
        public String LogMark
        
            get
            
                return logMark;
            
            set
            
                logMark = value;
            
        
        public String LogLayout
        
            get  return logLayout; 
            set
            
                logLayout = value;
                String format = value;
                int n1 = format.IndexOf("");
                int n2 = format.IndexOf("");
                dictLog = new Dictionary<String, int>();
                listLogLayout = new List<String>();
                while (n1 >= 0 && n2 >= 0)
                
                    if (n1 > 0)
                        listLogLayout.Add(format.Substring(0, n1));
                    String sKey = format.Substring(n1 + 1, n2 - n1 - 1);
                    dictLog.Add(sKey, listLogLayout.Count);
                    listLogLayout.Add("");

                    format = format.Substring(n2 + 1, format.Length - n2 - 1);
                    n1 = format.IndexOf("");
                    n2 = format.IndexOf("");
                
                if (format.Length > 0)
                    listLogLayout.Add(format);
                listLogLayout.Add("\\n");
            
        
        public String PathLayout
        
            get
            
                return pathLayout;
            
            set
            
                pathLayout = value;
                String format = value;
                int n1 = format.IndexOf("");
                int n2 = format.IndexOf("");
                dictPath = new Dictionary<int, String>();
                listPathLayout = new List<String>();
                while (n1 >= 0 && n2 >= 0)
                
                    if (n1 > 0)
                        listPathLayout.Add(format.Substring(0, n1));
                    String sKey = format.Substring(n1 + 1, n2 - n1 - 1);
                    dictPath.Add(listPathLayout.Count, sKey);
                    listPathLayout.Add("");

                    format = format.Substring(n2 + 1, format.Length - n2 - 1);
                    n1 = format.IndexOf("");
                    n2 = format.IndexOf("");
                
                if (format.Length > 0)
                    listPathLayout.Add(format);
                if (listPathLayout.Count == 0 || listPathLayout[listPathLayout.Count - 1] != "\\\\")
                    listPathLayout.Add("\\\\");
            
        

        public void FormatLog(LogItem log)
        
            if (IsEnableLogHead)
                log.logHead = logHead;
            log.fileName = logName;
            log.fileExten = logNameExt;
            log.mark = LogMark;
            log.IsStableName = IsStableName;

            foreach (String sK in dictLog.Keys)
            
                int nIdx = 0;
                if (dictLog.TryGetValue(sK, out nIdx))
                
                    if (sK.ToLower() == "time")
                        listLogLayout[nIdx] = log.time.ToString("HH:mm:ss,fff");
                    else if (sK.ToLower() == "exp" && log.e != null)
                        listLogLayout[nIdx] = log.e.StackTrace;
                    else if (sK.ToLower() == "thrname")
                        listLogLayout[nIdx] = log.thrName;
                    else if (sK.ToLower() == "thrid")
                        listLogLayout[nIdx] = log.thrID.ToString("D3");
                    else if (sK.ToLower() == "type")
                        listLogLayout[nIdx] = Enum.GetName(log.type.GetType(), log.type);
                    else if (sK.ToLower() == "msg")
                        listLogLayout[nIdx] = log.msg;
                    else if (sK.ToLower() == "mark")
                        listLogLayout[nIdx] = log.mark;
                
            
            int nS = 0;
            for (int i = 0; i < listLogLayout.Count; i++)
                nS += listLogLayout[i].Length * 2;// 中文字符占两个长度
            log.logBuf = new byte[nS];
            log.logSize = 0;
            for (int i = 0; i < listLogLayout.Count; i++)
            
                byte[] tmp = Encoding.UTF8.GetBytes(listLogLayout[i]);
                Array.Copy(tmp, 0, log.logBuf, log.logSize, tmp.Length);
                log.logSize += tmp.Length;
            

            foreach (int nIdx in dictPath.Keys)
            
                String s = "";
                if (dictPath.TryGetValue(nIdx, out s))
                    listPathLayout[nIdx] = log.time.ToString(s);
            
            log.filePath = "";
            for (int i = 0; i < listPathLayout.Count; i++)
                log.filePath += listPathLayout[i];
        
        public String GetLogName()
        
            String s = GetFullPath();
            int n = s.LastIndexOf("\\\\");
            return s.Substring(n + 1, s.Length - n - 1);
        
        public String GetLogPath()
        
            foreach (int nIdx in dictPath.Keys)
            
                String s = "";
                DateTime time = DateTime.Now;
                if (dictPath.TryGetValue(nIdx, out s))
                    listPathLayout[nIdx] = time.ToString(s);
            
            String filePath = "";
            for (int i = 0; i < listPathLayout.Count; i++)
                filePath += pathLayout[i];

            return filePath;
        
        public String GetFullPath()
        
            String basePath = GetLogPath();

            if (IsStableName == true)
                return basePath + logName + "." + logNameExt;

            String[] files = Directory.GetFiles(basePath, logName + "#*", SearchOption.AllDirectories);
            if (files.Length > 0)
            
                List<String> listFiles = new List<String>(1000);
                for (int i = 0; i < files.Length; i++)
                    listFiles.Add(files[i]);
                listFiles.Sort(new CompareRisedTime());
                return listFiles[listFiles.Count - 1];
            
            return basePath + logName + "#" + (0).ToString("D3") + "." + logNameExt;
        
    
    public class MFilter
    
        String[] excludeMsg;
        String[] includeMsg;
        String[] excludeThr;
        String[] includeThr;
        String exMsg;
        String inMsg;
        String exThr;
        String inThr;
        bool[] isEnableLog = null;

        public bool IsEnable = false;
        public String ExMsg
        
            get
            
                return exMsg;
            
            set
            
                exMsg = value;
                excludeMsg = exMsg.Split(',');
            
        
        public String InMsg
        
            get
            
                return inMsg;
            
            set
            
                inMsg = value;
                includeMsg = inMsg.Split(',');
            
        
        public String ExThr
        
            get
            
                return exThr;
            
            set
            
                exThr = value;
                excludeThr = exThr.Split(',');
            
        
        public String InThr
        
            get
            
                return inThr;
            
            set
            
                inThr = value;
                includeThr = inThr.Split(',');
            
        

        public MFilter()
        
            int len = System.Enum.GetNames((new MType()).GetType()).Length;
            isEnableLog = new bool[len];
            for (int i = 0; i < len; i++)
                isEnableLog[i] = true;
        
        public void EnableLog(MType type, bool bEnable)
        
            isEnableLog[(int)type] = bEnable;
        
        public void EnableAllLog(bool bEnable)
        
            for (int i = 0; i < isEnableLog.Length; i++)
                isEnableLog[i] = bEnable;
        
        public bool IsEnableLog(MType type)
        
            return isEnableLog[(int)type];
        
        public bool Filt(LogItem log)
        
            if (IsEnable == false) return true;

            if (isEnableLog[(int)log.type] == false) return false;

            if (excludeMsg != null && excludeMsg.Length > 0)
                foreach (String str in excludeMsg)
                    if (log.msg.IndexOf(str) >= 0) return false;

            if (excludeThr != null && excludeThr.Length > 0)
                foreach (String str in excludeThr)
                    if (log.thrName.IndexOf(str) >= 0) return false;

            if (includeMsg != null && includeMsg.Length > 0)
            
                foreach (String str in includeMsg)
                    if (log.msg.IndexOf(str) >= 0) goto next1;
                return false;
            
        next1:

            if (includeThr != null && includeThr.Length > 0)
            
                foreach (String str in includeThr)
                    if (log.thrName.IndexOf(str) >= 0) goto next2;
                return false;
            
        next2:

            return true;
        
    
    public class MThr
    
        public bool IsEnable = false;
        public int ID
        
            get
            
                return Manager.GetCurThrID();
            
        
        public string Name
        
            get
            
                return Manager.GetCurThrName();
            
            set
            
                Manager.SetCurThrName(value);
            
        
    
    public static class Manager
    
        static Dictionary<String, MLog> dictLog = new Dictionary<String, MLog>();
        static Dictionary<String, MWriter> dictWrite = new Dictionary<String, MWriter>();
        static Dictionary<int, String> dictThr = new Dictionary<int, String>();
        static Object objLockLog = new object();
        static Object objLockThr = new object();


        public static int SetCurThrName(String name)
        
            int id = GetCurThrID();
            lock (objLockThr)
            
                if (dictThr.ContainsKey(id))
                    dictThr.Remove(id);
                dictThr.Add(id, name);
            
            return id;
        
        public static int GetCurThrID()
        
            return AppDomain.GetCurrentThreadId();
        
        public static String GetCurThrName()
        
            String name = "";
            lock (objLockThr)
            
                int id = GetCurThrID();
                if (!dictThr.TryGetValue(id, out name))
                    name = "";
            
            return name;
        


        public static void AddLog(String Name, MLog log, MWriter writer)
        
            lock (objLockLog)
            
                if (dictLog.ContainsKey(Name))
                    dictLog.Remove(Name);
                if (dictWrite.ContainsKey(Name))
                    dictWrite.Remove(Name);

                writer.Init(log);
                dictLog.Add(Name, log);
                dictWrite.Add(Name, writer);
            
        
        public static void RemoveLog(String Name)
        
            lock (objLockLog)
            
                MLog log = null;
                MWriter w = null;
                if (dictLog.TryGetValue(Name, out log) && dictWrite.TryGetValue(Name, out w))
                
                    dictLog.Remove(Name);
                    dictWrite.Remove(Name);
                    log.filter.EnableAllLog(false);
                    log.filter.IsEnable = true;
                    w.bExit = true;
                
            
        
        public static MLog GetLog(String Name)
        
            MLog log = null;
            lock (objLockLog)
            
                if (dictLog.ContainsKey(Name))
                    dictLog.TryGetValue(Name, out log);
                else
                
                    log = new MLog();
                    AddLog(Name, log, new MFileWriter());
                
            
            return log;
        
        public static MLog[] GetLogs()
        
            lock (objLockLog)
            
                return dictLog.Values.ToArray();
            
        
        public static String[] GetNames()
        
            lock (objLockLog)
            
                return dictLog.Keys.ToArray();
            
        
        public static MWriter GetWriter(String name)
        
            lock (objLockLog)
            
                MWriter w = null;
                dictWrite.TryGetValue(name, out w);
                return w;
            
        
    
    public class MWriter
    
        public bool bExit = false;
        public virtual void Init(MLog microLog)
        

        
        public virtual void OnWrite(LogItem log)  
        public virtual void Flush()  
    
    public class MFileWriter : MWriter
    
        Thread thr;
        List<String> listFiles;
        LinkItem<LogItem> linkLog = new LinkItem<LogItem>();

        int nameIdx = -1;
        int nExtraSize = 1024 * 1024;
        int maxLogSize = 1024 * 1024 * 10;
        int maxLogCount = 20;
        int logWriteTime = 100;
        int logSize = 0;
        byte[] buf = null;
        bool bFlush = false;
        object objLog = new object();

        public int NExtraSize
        
            get
            
                return nExtraSize;
            
            set
            
                nExtraSize = value;
                if (nExtraSize < 128)
                    nExtraSize = 128;
                if (nExtraSize > 1024 * 1024)
                    nExtraSize = 1024 * 1024;
            
        
        public int MaxLogSize
        
            get
            
                return maxLogSize;
            
            set
            
                maxLogSize = value;
                if (maxLogSize < 1024 * 1024) maxLogSize = 1024 * 1024;
            
        
        public int MaxLogCount
        
            get
            
                return maxLogCount;
            
            set
            
                maxLogCount = value;
                if (maxLogCount < 1) maxLogCount = 1;
            
        
        public int LogWriteTime
        
            get
            
                return logWriteTime;
            
            set
            
                logWriteTime = value;
                if (logWriteTime < 10) logWriteTime = 10;
                if (logWriteTime > 1000) logWriteTime = 1000;
            
        

        public override void Init(MLog microLog)
        
            buf = new byte[MaxLogSize + NExtraSize];
            listFiles = new List<String>();
            if (microLog == null)
                return;
            microLog.OnWrite += OnWrite;
            thr = new Thread(FuncWriteLog);
            thr.IsBackground = true;
            thr.Start();
        
        public override void OnWrite(LogItem log)
        
            lock (objLog)
            
                linkLog.AddEnd(log);
                logSize += log.logSize;
            
        
        public override void Flush()
        
            bFlush = true;
        
        void FuncWriteLog()
        
            Stopwatch sw = new Stopwatch();
            sw.Restart();
            while (true)
            
                Thread.Sleep(10);
                if (sw.ElapsedMilliseconds < LogWriteTime && bFlush == false)
                    continue;
                sw.Restart();

                if (logSize <= 0)
                
                    if (bExit == true)
                        break;
                    else
                        continue;
                

                LinkItem<LogItem> tmpLinkLog = null;
                lock (objLog)
                
                    tmpLinkLog = linkLog;
                    linkLog = new LinkItem<LogItem>();
                    logSize = 0;
                

                if (buf.Length != MaxLogSize + NExtraSize)
                    buf = new byte[MaxLogSize + NExtraSize];

                SubItem<LogItem> itm = tmpLinkLog.FromFirst();
                String basePath = itm.t.filePath;
                String baseName = itm.t.fileName;
                String baseNameExt = itm.t.fileExten;
                if (Directory.Exists(basePath) == false)
                
                    Directory.CreateDirectory(basePath);
                    listFiles.Clear();
                    nameIdx = -1;
                
                int remainSize = 0;
                String name = CheckFile(basePath, baseName, baseNameExt, itm.t.IsStableName, ref remainSize);
                int writedSize = 0;

                while (itm != null)
                
                    if (itm.t.filePath == basePath)
                    
                        if (remainSize == MaxLogSize && writedSize == 0 &&
                             itm.t.logHead != null
                           && itm.t.logHead.Length > 0)
                        
                            Array.Copy(itm.t.logHead, 0, buf, writedSize, itm.t.logHead.Length);
                            writedSize += itm.t.logHead.Length;
                        
                        if (writedSize < remainSize
                            && baseName == itm.t.fileName
                            && baseNameExt == itm.t.fileExten)
                        
                            Array.Copy(itm.t.logBuf, 0, buf, writedSize, itm.t.logSize);
                            writedSize += itm.t.logSize;
                        
                        else
                        
                            WriteLog(buf, writedSize, name);
                            basePath = itm.t.filePath;
                            baseName = itm.t.fileName;
                            baseNameExt = itm.t.fileExten;
                            name = CheckFile(basePath, baseName, baseNameExt, itm.t.IsStableName, ref remainSize);
                            writedSize = 0;
                            itm = itm.pPrev;
                        
                    
                    else
                    
                        basePath = itm.t.filePath;
                        baseName = itm.t.fileName;
                        baseNameExt = itm.t.fileExten;
                        if (Directory.Exists(basePath) == false)
                        
                            Directory.CreateDirectory(basePath);
                            listFiles.Clear();
                            nameIdx = -1;
                        
                        WriteLog(buf, writedSize, name);
                        name = CheckFile(basePath, baseName, baseNameExt, itm.t.IsStableName, ref remainSize);
                        writedSize = 0;
                        itm = itm.pPrev;
                    
                    if (itm != null)
                        itm = itm.pNext;
                
                if (writedSize > 0)
                    WriteLog(buf, writedSize, name);

                bFlush = false;
                GC.Collect();
            
        
        void WriteLog(byte[] buf, int size, String name)
        
            using (FileStream fs = new FileStream(name, FileMode.Append, FileAccess.Write, FileShare.ReadWrite))
            
                fs.Write(buf, 0, size);
                fs.Close();
            
        
        String CheckFile(String basePath, String baseName, String baseNameExt, bool bStableName, ref int remainSize)
        
            String s = "";
            int nFileSize = 0;
            if (bStableName)   // 如果是固定名字
            
                s = basePath + baseName + "." + baseNameExt;
                if (File.Exists(s))
                    nFileSize = (int)(new FileInfo(s)).Length;
                remainSize = MaxLogSize - nFileSize;
                if (remainSize < 0)
                
                    File.Delete(s);
                    remainSize = MaxLogSize;
                
                return s;
            

            String[] files = Directory.GetFiles(basePath, baseName + "#*", SearchOption.AllDirectories);
            if (listFiles.Count == 0 && files.Length > 0)
            
                for (int i = 0; i < files.Length; i++)
                    listFiles.Add(files[i]);
                listFiles.Sort(new CompareRisedTime());
            

            while (listFiles.Count > MaxLogCount)
            
                File.Delete(listFiles[0]);
                listFiles.RemoveAt(0);
            

            if (listFiles.Count > 0)
            
                s = listFiles[listFiles.Count - 1];
                if (nameIdx < 0)
                
                    int n = s.LastIndexOf("#");
                    String sub = s.Substring(n + 1, 3);
                    nameIdx = int.Parse(sub);
                
                nFileSize = 0;
                if (File.Exists(s))
                
                    int n1 = s.LastIndexOf("\\\\");
                    int n2 = s.LastIndexOf("#");
                    String sub = s.Substring(n1 + 1, n2 - n1 - 1);
                    if (sub != baseName)
                    
                        nameIdx = 0;
                        s = basePath + baseName + "#" + nameIdx.ToString("D3") + "." + baseNameExt;
                        listFiles.Clear();
                        listFiles.Add(s);
                        nFileSize = 0;
                    
                    else
                        nFileSize = (int)(new FileInfo(s)).Length;
                
            
            else
            
                nameIdx++;
                s = basePath + baseName + "#" + nameIdx.ToString("D3") + "." + baseNameExt;
            

            remainSize = MaxLogSize - nFileSize;
            if (remainSize <= 0)
            
                nameIdx++;
                s = basePath + baseName + "#" + nameIdx.ToString("D3") + "." + baseNameExt;
                listFiles.Add(s);
                remainSize = MaxLogSize;
            
            return s;
        
    
    public class MDebugWriter : MWriter
    
        public override void Init(MLog microLog)
        
            if (microLog == null)
                return;
            microLog.OnWrite += OnWrite;
        
        public override void OnWrite(LogItem log)
        
            if (bExit == true)
                return;
            if (log.mark.Length > 0)
                System.Diagnostics.Debug.Write(Encoding.UTF8.GetString(log.logBuf, 0, log.logSize), log.mark);
            else
                System.Diagnostics.Debug.Write(Encoding.UTF8.GetString(log.logBuf, 0, log.logSize));
        
        public override void Flush()
        
            System.Diagnostics.Debug.Flush();
        
    
    public class MTraceWriter : MWriter
    
        public override void Init(MLog microLog)
        
            if (microLog == null)
                return;
            microLog.OnWrite += OnWrite;
        
        public override void OnWrite(LogItem log)
        
            if (bExit == true)
                return;

            if (log.mark.Length > 0)
                System.Diagnostics.Trace.Write(Encoding.UTF8.GetString(log.logBuf, 0, log.logSize), log.mark);
            else
                System.Diagnostics.Trace.Write(Encoding.UTF8.GetString(log.logBuf, 0, log.logSize));
        
        public override void Flush()
        
            System.Diagnostics.Trace.Flush();
        
    
    public class MConsoleWriter : MWriter
    
        public override void Init(MLog microLog)
        
            if (microLog == null)
                return;
            microLog.OnWrite += OnWrite;
        
        public override void OnWrite(LogItem log)
        
            if (bExit == true)
                return;
            Console.Write(Encoding.UTF8.GetString(log.logBuf, 0, log.logSize));
        
        public override void Flush()
        
           
        
    
    public class SubItem<T>
    
        public T t;
        public SubItem<T> pPrev;
        public SubItem<T> pNext;
        public SubItem(T tVal, SubItem<T> pPrev_, SubItem<T> pNext_)
        
            t = tVal;
            pPrev = pPrev_;
            pNext = pNext_;
        
    
    public class LinkItem<T>
    
        SubItem<T> pZero = null;
        SubItem<T> pEnd = null;
        int nCount = 0;
        object obj = new object();

        public SubItem<T> FromFirst()
        
            return pZero;
        
        public void AddAt(T t_, int nPos)
        
            if (nPos < 0 || nPos > nCount)
                throw new ArgumentException("插入的位置不合适 nPos=" + nPos + " ,COunt=" + nCount);

            lock (obj)
            
                if (nPos == 0)
                
                    pZero.pPrev = new SubItem<T>(t_, null, pZero);
                    pZero = pZero.pPrev;
                
                else if (nPos == nCount)
                
                    pEnd.pNext = new SubItem<T>(t_, pEnd, null); ;
                    pEnd = pEnd.pNext;
                
                else
                
                    SubItem<T> pSel = pZero;
                    for (int i = 0; i < nCount; i++)
                    
                        if (i == nPos)
                        
                            pSel.pPrev.pNext = new SubItem<T>(t_, pSel.pPrev, pSel);
                            pSel.pPrev.pNext.pNext.pPrev = pSel.pPrev.pNext;
                            break;
                        
                        pSel = pSel.pNext;
                    
                
                nCount++;
            
        
        public void AddEnd(T t_)
        
            lock (obj)
            
                if (pEnd == null)
                
                    pEnd = new SubItem<T>(t_, null, null);
                    pZero = pEnd;
                
                else if (nCount == 1)
                
                    pEnd = new SubItem<T>(t_, pZero, null);
                    pZero.pNext = pEnd;
                
                else
                
                    pEnd.pNext = new SubItem<T>(t_, pEnd, null); ;
                    pEnd = pEnd.pNext;
                    //pNow.pNext = null;
                
                nCount++;
            
        
        public void AddFirst(T t_)
        
            lock (obj)
            
                if (pZero == null)
                
                    pZero = new SubItem<T>(t_, null, null);
                    pEnd = pZero;
                
                else
                
                    pZero.pPrev = new SubItem<T>(t_, null, pZero);
                    pZero = pZero.pPrev;
                    //pZero.pPrev = null;
                
                nCount++;
            
        

        public T RemoveAt(int nPos)
        
            if (nPos < 0 || nPos >= nCount)
                throw new ArgumentException("输入参数超限 idx=" + nPos + " ,Count=" + nCount);
            lock (obj)
            
                SubItem<T> pSel = pZero;
                for (int i = 0; i < nCount; i++)
                
                    if (i == nPos)
                    
                        if (pSel.pPrev != null)
                        
                            if (i == nCount - 1)
                                pEnd = pEnd.pPrev;

                            pSel.pPrev.pNext = pSel.pNext;
                        
                        if (pSel.pNext != null)
                        
                            if (i == 0)
                                pZero = pZero.pNext;

                            pSel.pNext.pPrev = pSel.pPrev;
                        
                        nCount--;
                        if (nCount == 0) Clear();
                        break;
                    
                    pSel = pSel.pNext;
                
                return pSel.t;
            
        
        public T RemoveEnd()
        
            if (nCount == 0)
                throw new ArgumentException("List容量为0,无法移除");

            lock (obj)
            
                T t_ = pEnd.t;
                if (pEnd.pPrev != null)
                
                    pEnd = pEnd.pPrev;
                    pEnd.pNext = null;
                    nCount--;
                
                else
                    Clear();
                return t_;
            
        
        public T RemoveFirst()
        
            if (nCount == 0)
                throw new ArgumentException("List容量为0,无法移除");

            lock (obj)
            
                T t_ = pZero.t;
                if (pZero.pNext != null)
                
                    pZero = pZero.pNext;
                    pZero.pPrev = null;
                    nCount--;
                
                else
                    Clear();
                return t_;
            
        

        public T ViewFirst()
        
            if (nCount < 1)
                throw new ArgumentException("数量为0 nCount=" + nCount);
            return pZero.t;
        
        public T ViewAt(int nPos)
        
            if (nPos < 0 || nPos >= nCount)
                throw new ArgumentException("输入参数超限 idx=" + nPos + " ,Count=" + nCount);
            lock (obj)
            
                SubItem<T> pSel = pZero;
                for (int i = 0; i < nCount; i++)
                
                    if (i == nPos)
                        break;
                    pSel = pSel.pNext;
                
                return pSel.t;
            
        
        public T ViewEnd()
        
            if (nCount < 1)
                throw new ArgumentException("数量为0 nCount=" + nCount);
            return pEnd.t;
        

        // 十分耗费资源
        public T this[int index]
        
            get
            
                lock (obj)
                
                    if (index < 0 || index >= nCount)
                        throw new ArgumentException("输入参数超限 idx=" + index + " ,Count=" + nCount);

                    SubItem<T> pSel = pZero;
                    T tRtn = pSel.t;
                    for (int i = 0; i < nCount; i++)
                    
                        if (i == index)
                        
                            tRtn = pSel.t;
                            break;
                        

                        pSel = pSel.pNext;
                    
                    return tRtn;
                
            

            set
            
                lock (obj)
                
                    if (index < 0 || index >= nCount)
                        throw new ArgumentException("输入参数超限 idx=" + index + " ,Count=" + nCount);

                    SubItem<T> pSel = pZero;
                    for (int i = 0; i < nCount; i++)
                    
                        if (i == index)
                        
                            pSel.t = value;
                            break;
                        

                        pSel = pSel.pNext;
                    
                
            
        
        public SubItem<T> Clear()
        
            SubItem<T> itm = null;
            lock (obj)
            
                itm = pZero;
                pZero = null;
                pEnd = null;
                nCount = 0;
            
            return itm;
        
        public int Count()
        
            return nCount;
        

        public T[] GetElements()
        
            if (Count() == 0)
                return null;

            T[] tt = null;
            lock (obj)
            
                tt = new T[Count()];
                for (int i = 0; i < Count(); i++)
                    tt[i] = this[i];
            

            return tt;
        
    
    public enum MType
    
        mType1 = 0,
        mType2,
        mType3,
        mType4
    
    class CompareRisedTime : IComparer<String>
    
        public int Compare(String a, String b)
        
            FileInfo f1 = new FileInfo(a);
            FileInfo f2 = new FileInfo(b);

            if (f1.CreationTime > f2.CreationTime) return 1;
            if (f1.CreationTime < f2.CreationTime) return -1;
            return 0;
        
    

 调用

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace MicroLog

    public partial class Form1 : Form
    
        public Form1()
        
            InitializeComponent();
        
        private void Form1_Load(object sender, EventArgs e)
        
            MLog log1 = new MLog();
            log1.convert.LogHead = "[Time] [Mark]  -ThrID:ThrName-  [Type]  Msg";       // 每个日志文件第一行都会输出
            log1.convert.LogName = "firstTest.log";
            log1.convert.PathLayout = "D:\\\\MLog\\\\Log1_yyy.MM.dd";
            log1.convert.LogLayout = "[time] [mark]  -thrid:thrname-  [type]  msg";
            log1.convert.LogMark = "mark1";
            log1.convert.IsEnableLogHead = true;
            log1.convert.IsStableName = false;        // 是否固定文件名,固定:只有一个文件,达到最大文件大小后悔删除源文件
            log1.thr.IsEnable = true;
            log1.thr.Name = "main";
            //log.filter.SetExcludeLog("first");
            //log.filter.EnableLog(LogType.Debug, false);

            MLog log2 = new MLog();
            log2.convert.LogName = "secondTest.log";
            log2.convert.PathLayout = "D:\\\\MLog\\\\Log2_yyy.MM.dd";
            log2.convert.LogLayout = "[time] [mark]  -thrid:thrname-  [type]  msg";
            log2.convert.LogMark = "mark2";
            log2.thr.IsEnable = false;
            log2.thr.Name = "222";
            log2.filter.IsEnable = true;
            //log2.filter.ExThr = "2";
            log2.filter.ExMsg = "10";
            //log2.filter.EnableLog(MType.mType1, false);
            //log1.transTo = log2;


            MConsoleWriter w1 = new MConsoleWriter();
            MDebugWriter w2 = new MDebugWriter();

            Manager.AddLog("log1", log1,w1);
            Manager.AddLog("log2", log2,w2);
        

        private void button1_Click(object sender, EventArgs e)
        
            Stopwatch sw = new Stopwatch();
            MLog log = Manager.GetLog("log1");
            sw.Restart();
            for (int i = 0; i < 1000000; i++)
                log.Write("firstLog   打两块就到啦世纪东方啦收到啦就是到了看静安寺多放辣椒撒冷的发几款   " + i.ToString("D10"));
            long l = sw.ElapsedMilliseconds;
            double n1 = l / 1000.0;
            double n2 = l / 100.0;
            MessageBox.Show("TotlaTime=" + n1.ToString() + " s\\n Ave 10000 Item = " + n2.ToString("F2") + " ms");
        

        private void button2_Click(object sender, EventArgs e)
        
            MLog log1 = Manager.GetLog("log1");
            MLog log2 = Manager.GetLog("log2");
            log1.transTo.Add(log2);   // log1 的日志会流转给 log2

            log1.Write("firstLog   打两块就到啦世纪东方啦收到啦就是到了看静安寺多放辣椒撒冷的发几款 10");
            log1.Write("firstLog   打两块就到啦世纪东方啦收到啦就是到了看静安寺多放辣椒撒冷的发几款 11");

            log1.transTo.Remove(log2);
        
    

以上是关于C#日志记录工具 MicroLog的主要内容,如果未能解决你的问题,请参考以下文章

C#日志记录工具 MicroLog

microlog4android如何将Android Log日志写到SD

c#中使用log4net工具记录日志

C# 使用ILogger接口编写日志

C# - NLog 为同一个调用记录多行

C# 如何设计一个好用的日志库?架构篇