zoukankan      html  css  js  c++  java
  • C#写日志工具类

    CPU:i5-8265U 硬盘:固态硬盘 测试结果:每秒写入文件大约1万到3万条日志,每条日志的字符串长度是140多个字符

    支持多线程并发,支持多进程并发,支持按文件大小分隔日志文件

    LogUtil.cs代码:

    using System;
    using System.Collections.Concurrent;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Reflection;
    using System.Text;
    using System.Text.RegularExpressions;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace Utils
    {
        /// <summary>
        /// 写日志类
        /// </summary>
        public class LogUtil
        {
            #region 字段
            private static string _path = null;
    
            private static Mutex _mutexDebug = new Mutex(false, "LogUtil.Mutex.Debug.252F8025254D4DAA8EFB7FFE177F13E0");
            private static Mutex _mutexInfo = new Mutex(false, "LogUtil.Mutex.Info.180740C3B1C44D428683D35F84F97E22");
            private static Mutex _mutexError = new Mutex(false, "LogUtil.Mutex.Error.81273C1400774A3B8310C2EC1C3AFFFF");
    
            private static ConcurrentDictionary<string, int> _dictIndex = new ConcurrentDictionary<string, int>();
            private static ConcurrentDictionary<string, long> _dictSize = new ConcurrentDictionary<string, long>();
            private static ConcurrentDictionary<string, FileStream> _dictStream = new ConcurrentDictionary<string, FileStream>();
            private static ConcurrentDictionary<string, StreamWriter> _dictWriter = new ConcurrentDictionary<string, StreamWriter>();
    
            private static ConcurrentDictionary<string, string> _dictPathFolders = new ConcurrentDictionary<string, string>();
    
            private static TaskSchedulerEx _scheduler = new TaskSchedulerEx(2, 2);
    
            private static int _fileSize = 10 * 1024 * 1024; //日志分隔文件大小
            #endregion
    
            #region 写文件
            /// <summary>
            /// 写文件
            /// </summary>
            private static void WriteFile(LogType logType, string log, string path)
            {
                try
                {
                    FileStream fs = null;
                    StreamWriter sw = null;
    
                    if (!(_dictStream.TryGetValue(logType.ToString() + path, out fs) && _dictWriter.TryGetValue(logType.ToString() + path, out sw)))
                    {
                        foreach (string key in _dictWriter.Keys)
                        {
                            if (key.StartsWith(logType.ToString()))
                            {
                                StreamWriter item;
                                _dictWriter.TryRemove(key, out item);
                                item.Close();
                            }
                        }
    
                        foreach (string key in _dictStream.Keys)
                        {
                            if (key.StartsWith(logType.ToString()))
                            {
                                FileStream item;
                                _dictStream.TryRemove(key, out item);
                                item.Close();
                            }
                        }
    
                        if (!Directory.Exists(Path.GetDirectoryName(path)))
                        {
                            Directory.CreateDirectory(Path.GetDirectoryName(path));
                        }
    
                        fs = new FileStream(path, FileMode.Append, FileAccess.Write, FileShare.ReadWrite);
                        sw = new StreamWriter(fs);
                        _dictWriter.TryAdd(logType.ToString() + path, sw);
                        _dictStream.TryAdd(logType.ToString() + path, fs);
                    }
    
                    fs.Seek(0, SeekOrigin.End);
                    sw.WriteLine(log);
                    sw.Flush();
                    fs.Flush();
                }
                catch (Exception ex)
                {
                    string str = ex.Message;
                }
            }
            #endregion
    
            #region 生成日志文件路径
            /// <summary>
            /// 生成日志文件路径
            /// </summary>
            private static string CreateLogPath(LogType logType, string log)
            {
                try
                {
                    if (_path == null)
                    {
                        UriBuilder uri = new UriBuilder(Assembly.GetExecutingAssembly().CodeBase);
                        _path = Path.GetDirectoryName(Uri.UnescapeDataString(uri.Path));
                    }
    
                    string pathFolder = Path.Combine(_path, "Log\" + logType.ToString() + "\");
                    if (!_dictPathFolders.ContainsKey(pathFolder))
                    {
                        if (!Directory.Exists(Path.GetDirectoryName(pathFolder)))
                        {
                            Directory.CreateDirectory(Path.GetDirectoryName(pathFolder));
                        }
                        _dictPathFolders.TryAdd(pathFolder, pathFolder);
                    }
    
                    int currentIndex;
                    long size;
                    string strNow = DateTime.Now.ToString("yyyyMMdd");
                    string strKey = pathFolder + strNow;
                    if (!(_dictIndex.TryGetValue(strKey, out currentIndex) && _dictSize.TryGetValue(strKey, out size)))
                    {
                        _dictIndex.Clear();
                        _dictSize.Clear();
    
                        GetIndexAndSize(pathFolder, strNow, out currentIndex, out size);
                        if (size >= _fileSize)
                        {
                            currentIndex++;
                            size = 0;
                        }
                        _dictIndex.TryAdd(strKey, currentIndex);
                        _dictSize.TryAdd(strKey, size);
                    }
    
                    int index = _dictIndex[strKey];
                    string logPath = Path.Combine(pathFolder, strNow + (index == 1 ? "" : "_" + index.ToString()) + ".txt");
    
                    _dictSize[strKey] += Encoding.UTF8.GetByteCount(log);
                    if (_dictSize[strKey] > _fileSize)
                    {
                        _dictIndex[strKey]++;
                        _dictSize[strKey] = 0;
                    }
    
                    return logPath;
                }
                catch (Exception ex)
                {
                    string str = ex.Message;
                    return null;
                }
            }
            #endregion
    
            #region 拼接日志内容
            /// <summary>
            /// 拼接日志内容
            /// </summary>
            private static string CreateLogString(LogType logType, string log)
            {
                return string.Format(@"{0} {1} {2}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), ("[" + logType.ToString() + "]").PadRight(7, ' '), log);
            }
            #endregion
    
            #region 获取初始Index和Size
            /// <summary>
            /// 获取初始Index和Size
            /// </summary>
            private static void GetIndexAndSize(string pathFolder, string strNow, out int index, out long size)
            {
                index = 1;
                size = 0;
                Regex regex = new Regex(strNow + "_*(\d*).txt");
                string[] fileArr = Directory.GetFiles(pathFolder);
                string currentFile = null;
                foreach (string file in fileArr)
                {
                    Match match = regex.Match(file);
                    if (match.Success)
                    {
                        string str = match.Groups[1].Value;
                        if (!string.IsNullOrWhiteSpace(str))
                        {
                            int temp = Convert.ToInt32(str);
                            if (temp > index)
                            {
                                index = temp;
                                currentFile = file;
                            }
                        }
                        else
                        {
                            index = 1;
                            currentFile = file;
                        }
                    }
                }
    
                if (currentFile != null)
                {
                    FileInfo fileInfo = new FileInfo(currentFile);
                    size = fileInfo.Length;
                }
            }
            #endregion
    
            #region 写调试日志
            /// <summary>
            /// 写调试日志
            /// </summary>
            public static Task Debug(string log)
            {
                return Task.Factory.StartNew(() =>
                {
                    try
                    {
                        _mutexDebug.WaitOne();
    
                        log = CreateLogString(LogType.Debug, log);
                        string path = CreateLogPath(LogType.Debug, log);
                        WriteFile(LogType.Debug, log, path);
                    }
                    catch (Exception ex)
                    {
                        string str = ex.Message;
                    }
                    finally
                    {
                        _mutexDebug.ReleaseMutex();
                    }
                }, CancellationToken.None, TaskCreationOptions.None, _scheduler);
            }
            #endregion
    
            #region 写错误日志
            public static Task Error(Exception ex, string log = null)
            {
                return Error(string.IsNullOrEmpty(log) ? ex.Message + "
    " + ex.StackTrace : (log + "") + ex.Message + "
    " + ex.StackTrace);
            }
    
            /// <summary>
            /// 写错误日志
            /// </summary>
            public static Task Error(string log)
            {
                return Task.Factory.StartNew(() =>
                {
                    try
                    {
                        _mutexError.WaitOne();
    
                        log = CreateLogString(LogType.Error, log);
                        string path = CreateLogPath(LogType.Error, log);
                        WriteFile(LogType.Error, log, path);
                    }
                    catch (Exception ex)
                    {
                        string str = ex.Message;
                    }
                    finally
                    {
                        _mutexError.ReleaseMutex();
                    }
                }, CancellationToken.None, TaskCreationOptions.None, _scheduler);
            }
            #endregion
    
            #region 写操作日志
            /// <summary>
            /// 写操作日志
            /// </summary>
            public static Task Log(string log)
            {
                return Task.Factory.StartNew(() =>
                {
                    try
                    {
                        _mutexInfo.WaitOne();
    
                        log = CreateLogString(LogType.Info, log);
                        string path = CreateLogPath(LogType.Info, log);
                        WriteFile(LogType.Info, log, path);
                    }
                    catch (Exception ex)
                    {
                        string str = ex.Message;
                    }
                    finally
                    {
                        _mutexInfo.ReleaseMutex();
                    }
                }, CancellationToken.None, TaskCreationOptions.None, _scheduler);
            }
            #endregion
    
        }
    
        #region 日志类型
        /// <summary>
        /// 日志类型
        /// </summary>
        public enum LogType
        {
            Debug,
    
            Info,
    
            Error
        }
        #endregion
    
    }
    View Code

    依赖的TaskSchedulerEx.cs代码:

    using System;
    using System.Collections.Concurrent;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.InteropServices;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace Utils
    {
        /// <summary>
        /// TaskScheduler扩展
        /// 每个实例都是独立线程池
        /// </summary>
        public class TaskSchedulerEx : TaskScheduler, IDisposable
        {
            #region 外部方法
            [DllImport("kernel32.dll", EntryPoint = "SetProcessWorkingSetSize")]
            public static extern int SetProcessWorkingSetSize(IntPtr process, int minSize, int maxSize);
            #endregion
    
            #region 变量属性事件
            private ConcurrentQueue<Task> _tasks = new ConcurrentQueue<Task>();
            private int _coreThreadCount = 0;
            private int _maxThreadCount = 0;
            private int _auxiliaryThreadTimeOut = 20000; //辅助线程释放时间
            private int _activeThreadCount = 0;
            private System.Timers.Timer _timer;
            private object _lockCreateTimer = new object();
            private bool _run = true;
            private AutoResetEvent _evt = new AutoResetEvent(false);
    
            /// <summary>
            /// 活跃线程数
            /// </summary>
            public int ActiveThreadCount
            {
                get { return _activeThreadCount; }
            }
    
            /// <summary>
            /// 核心线程数
            /// </summary>
            public int CoreThreadCount
            {
                get { return _coreThreadCount; }
            }
    
            /// <summary>
            /// 最大线程数
            /// </summary>
            public int MaxThreadCount
            {
                get { return _maxThreadCount; }
            }
            #endregion
    
            #region 构造函数
            /// <summary>
            /// TaskScheduler扩展
            /// 每个实例都是独立线程池
            /// </summary>
            /// <param name="coreThreadCount">核心线程数(大于或等于0,不宜过大)(如果是一次性使用,则设置为0比较合适)</param>
            /// <param name="maxThreadCount">最大线程数</param>
            public TaskSchedulerEx(int coreThreadCount = 10, int maxThreadCount = 20)
            {
                _maxThreadCount = maxThreadCount;
                CreateCoreThreads(coreThreadCount);
            }
            #endregion
    
            #region override GetScheduledTasks
            protected override IEnumerable<Task> GetScheduledTasks()
            {
                return _tasks;
            }
            #endregion
    
            #region override TryExecuteTaskInline
            protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
            {
                return false;
            }
            #endregion
    
            #region override QueueTask
            protected override void QueueTask(Task task)
            {
                CreateTimer();
                _tasks.Enqueue(task);
                _evt.Set();
            }
            #endregion
    
            #region 资源释放
            /// <summary>
            /// 资源释放
            /// 队列中尚未执行的任务不再执行
            /// </summary>
            public void Dispose()
            {
                _run = false;
    
                if (_timer != null)
                {
                    _timer.Stop();
                    _timer.Dispose();
                    _timer = null;
                }
    
                while (_activeThreadCount > 0)
                {
                    _evt.Set();
                }
            }
            #endregion
    
            #region 创建核心线程池
            /// <summary>
            /// 创建核心线程池
            /// </summary>
            private void CreateCoreThreads(int? coreThreadCount = null)
            {
                if (coreThreadCount != null) _coreThreadCount = coreThreadCount.Value;
    
                for (int i = 0; i < _coreThreadCount; i++)
                {
                    Interlocked.Increment(ref _activeThreadCount);
                    Thread thread = null;
                    thread = new Thread(new ThreadStart(() =>
                    {
                        Task task;
                        while (_run)
                        {
                            if (_tasks.TryDequeue(out task))
                            {
                                TryExecuteTask(task);
                            }
                            else
                            {
                                _evt.WaitOne();
                            }
                        }
                        Interlocked.Decrement(ref _activeThreadCount);
                        if (_activeThreadCount == 0)
                        {
                            GC.Collect();
                            GC.WaitForPendingFinalizers();
                            if (Environment.OSVersion.Platform == PlatformID.Win32NT)
                            {
                                SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1);
                            }
                        }
                    }));
                    thread.IsBackground = true;
                    thread.Start();
                }
            }
            #endregion
    
            #region 创建辅助线程
            /// <summary>
            /// 创建辅助线程
            /// </summary>
            private void CreateThread()
            {
                Interlocked.Increment(ref _activeThreadCount);
                Thread thread = null;
                thread = new Thread(new ThreadStart(() =>
                {
                    Task task;
                    DateTime dt = DateTime.Now;
                    while (_run && DateTime.Now.Subtract(dt).TotalMilliseconds < _auxiliaryThreadTimeOut)
                    {
                        if (_tasks.TryDequeue(out task))
                        {
                            TryExecuteTask(task);
                            dt = DateTime.Now;
                        }
                        else
                        {
                            _evt.WaitOne(_auxiliaryThreadTimeOut);
                        }
                    }
                    Interlocked.Decrement(ref _activeThreadCount);
                    if (_activeThreadCount == _coreThreadCount)
                    {
                        GC.Collect();
                        GC.WaitForPendingFinalizers();
                        if (Environment.OSVersion.Platform == PlatformID.Win32NT)
                        {
                            SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1);
                        }
                    }
                }));
                thread.IsBackground = true;
                thread.Start();
            }
            #endregion
    
            #region 创建定时器
            private void CreateTimer()
            {
                if (_timer == null) //_timer不为空时,跳过,不走lock,提升性能
                {
                    if (_activeThreadCount >= _coreThreadCount && _activeThreadCount < _maxThreadCount) //活跃线程数达到最大线程数时,跳过,不走lock,提升性能
                    {
                        lock (_lockCreateTimer)
                        {
                            if (_timer == null)
                            {
                                _timer = new System.Timers.Timer();
                                _timer.Interval = _coreThreadCount == 0 ? 1 : 500;
                                _timer.Elapsed += (s, e) =>
                                {
                                    if (_activeThreadCount >= _coreThreadCount && _activeThreadCount < _maxThreadCount)
                                    {
                                        if (_tasks.Count > 0)
                                        {
                                            if (_timer.Interval != 20) _timer.Interval = 20;
                                            CreateThread();
                                        }
                                        else
                                        {
                                            if (_timer.Interval != 500) _timer.Interval = 500;
                                        }
                                    }
                                    else
                                    {
                                        if (_timer != null)
                                        {
                                            _timer.Stop();
                                            _timer.Dispose();
                                            _timer = null;
                                        }
                                    }
                                };
                                _timer.Start();
                            }
                        }
                    }
                }
            }
            #endregion
    
            #region 全部取消
            /// <summary>
            /// 全部取消
            /// 取消队列中尚未执行的任务
            /// </summary>
            public void CancelAll()
            {
                Task tempTask;
                while (_tasks.TryDequeue(out tempTask)) { }
            }
            #endregion
    
        }
    }
    View Code

    依赖的RunHelper.cs代码:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace Utils
    {
        /// <summary>
        /// 线程工具类
        /// </summary>
        public static class RunHelper
        {
            #region 变量属性事件
    
            #endregion
    
            #region 线程中执行
            /// <summary>
            /// 线程中执行
            /// </summary>
            public static Task Run(this TaskScheduler scheduler, Action<object> doWork, object arg = null, Action<Exception> errorAction = null)
            {
                return Task.Factory.StartNew((obj) =>
                {
                    try
                    {
                        doWork(obj);
                    }
                    catch (Exception ex)
                    {
                        if (errorAction != null) errorAction(ex);
                        LogUtil.Error(ex, "ThreadUtil.Run错误");
                    }
                }, arg, CancellationToken.None, TaskCreationOptions.None, scheduler);
            }
            #endregion
    
            #region 线程中执行
            /// <summary>
            /// 线程中执行
            /// </summary>
            public static Task Run(this TaskScheduler scheduler, Action doWork, Action<Exception> errorAction = null)
            {
                return Task.Factory.StartNew(() =>
                {
                    try
                    {
                        doWork();
                    }
                    catch (Exception ex)
                    {
                        if (errorAction != null) errorAction(ex);
                        LogUtil.Error(ex, "ThreadUtil.Run错误");
                    }
                }, CancellationToken.None, TaskCreationOptions.None, scheduler);
            }
            #endregion
    
            #region 线程中执行
            /// <summary>
            /// 线程中执行
            /// </summary>
            public static Task<T> Run<T>(this TaskScheduler scheduler, Func<object, T> doWork, object arg = null, Action<Exception> errorAction = null)
            {
                return Task.Factory.StartNew<T>((obj) =>
                {
                    try
                    {
                        return doWork(obj);
                    }
                    catch (Exception ex)
                    {
                        if (errorAction != null) errorAction(ex);
                        LogUtil.Error(ex, "ThreadUtil.Run错误");
                        return default(T);
                    }
                }, arg, CancellationToken.None, TaskCreationOptions.None, scheduler);
            }
            #endregion
    
            #region 线程中执行
            /// <summary>
            /// 线程中执行
            /// </summary>
            public static Task<T> Run<T>(this TaskScheduler scheduler, Func<T> doWork, Action<Exception> errorAction = null)
            {
                return Task.Factory.StartNew<T>(() =>
                {
                    try
                    {
                        return doWork();
                    }
                    catch (Exception ex)
                    {
                        if (errorAction != null) errorAction(ex);
                        LogUtil.Error(ex, "ThreadUtil.Run错误");
                        return default(T);
                    }
                }, CancellationToken.None, TaskCreationOptions.None, scheduler);
            }
            #endregion
    
            #region 线程中执行
            /// <summary>
            /// 线程中执行
            /// </summary>
            public static async Task<T> RunAsync<T>(this TaskScheduler scheduler, Func<object, T> doWork, object arg = null, Action<Exception> errorAction = null)
            {
                return await Task.Factory.StartNew<T>((obj) =>
                {
                    try
                    {
                        return doWork(obj);
                    }
                    catch (Exception ex)
                    {
                        if (errorAction != null) errorAction(ex);
                        LogUtil.Error(ex, "ThreadUtil.Run错误");
                        return default(T);
                    }
                }, arg, CancellationToken.None, TaskCreationOptions.None, scheduler);
            }
            #endregion
    
            #region 线程中执行
            /// <summary>
            /// 线程中执行
            /// </summary>
            public static async Task<T> RunAsync<T>(this TaskScheduler scheduler, Func<T> doWork, Action<Exception> errorAction = null)
            {
                return await Task.Factory.StartNew<T>(() =>
                {
                    try
                    {
                        return doWork();
                    }
                    catch (Exception ex)
                    {
                        if (errorAction != null) errorAction(ex);
                        LogUtil.Error(ex, "ThreadUtil.Run错误");
                        return default(T);
                    }
                }, CancellationToken.None, TaskCreationOptions.None, scheduler);
            }
            #endregion
    
        }
    }
    View Code

    测试代码:

    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;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    using Utils;
    
    namespace LogUtilTest
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                Task.Factory.StartNew(() =>
                {
                    int n = 100000;
                    string processId = Process.GetCurrentProcess().Id.ToString().PadLeft(8, ' ');
                    List<Task> taskList = new List<Task>();
                    string str = "    abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcda3.1415bcdabcdabcdabcdabc@#$%^&dabcdabcdabcdabcdabcdabcdabcdabcd";
                    DateTime dtStart = DateTime.Now;
                    for (int i = 1; i <= n; i++)
                    {
                        Task task = LogUtil.Log("ProcessId:【" + processId + "】 测试" + i.ToString().PadLeft(8, '0') + str);
                        taskList.Add(task);
                        task = LogUtil.Debug("ProcessId:【" + processId + "】 测试" + i.ToString().PadLeft(8, '0') + str);
                        taskList.Add(task);
                    }
                    Task.WaitAll(taskList.ToArray());
    
                    double sec = DateTime.Now.Subtract(dtStart).TotalSeconds;
                    MessageBox.Show(n + "条日志完成,耗时" + sec.ToString("0.000") + "");
                });
            }
        }
    }
    View Code

    测试结果截图:

  • 相关阅读:
    PAT甲级1114. Family Property
    PAT甲级1111. Online Map
    Android零基础入门第84节:引入Fragment原来是这么回事
    Android零基础入门第83节:Activity间数据传递方法汇总
    Android零基础入门第82节:Activity数据回传
    Android零基础入门第81节:Activity数据传递
    Android零基础入门第80节:Intent 属性详解(下)
    Android零基础入门第79节:Intent 属性详解(上)
    Android零基础入门第78节:四大组件的纽带——Intent
    Android零基础入门第77节:Activity任务栈和启动模式
  • 原文地址:https://www.cnblogs.com/s0611163/p/4023859.html
Copyright © 2011-2022 走看看