C#实现线程安全的简易日志记录方法

所属分类: 软件编程 / C#教程 阅读数: 94
收藏 0 赞 0 分享

一般在实际项目的开发中,会要求涉及日志记录的问题,比较常用的有Log4Net,NLog等几个,而小项目小工具的话,则无需费此大驾。而譬如串口开发的话,需要记录串口过来的数据等等,这时候就要考虑日志记录上线程的问题。对此,为了方便后续使用,封装了下代码:

using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading;

namespace CSharpUtilHelpV2
{
  /// <summary>
  /// 日志类型枚举
  /// </summary>
  public enum LogType
  {
    /// <summary>
    /// 一般输出
    /// </summary>
    Trace,
    /// <summary>
    /// 警告
    /// </summary>
    Warning,
    /// <summary>
    /// 错误
    /// </summary>
    Error,
    /// <summary>
    /// SQL
    /// </summary>
    SQL
  }
  /// <summary>
  /// 基于.NET 2.0日志工具类
  /// </summary>
  public class LogToolV2
  {
    private static readonly Thread LogTask;
    private static readonly ThreadSafeQueueV2<string> LogColQueue;//自定义线程安全的Queue
    private static readonly object SyncRoot;
    private static readonly string FilePath;
    private static readonly long BackFileSize_MB = 2;//超过2M就开始备份日志文件
    static LogToolV2()
    {
      SyncRoot = new object();
      FilePath = AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "Log\\";
      LogTask = new Thread(WriteLog);
      LogColQueue = new ThreadSafeQueueV2<string>();
      LogTask.Start();
      Debug.WriteLine("Log Start......");
    }
    /// <summary>
    /// 记录日志
    /// </summary>
    /// <param name="msg">日志内容</param>
    public static void Log(string msg)
    {
      string _msg = string.Format("{0} : {2}", DateTime.Now.ToString("HH:mm:ss"), msg);
      LogColQueue.Enqueue(msg);
    }
    /// <summary>
    /// 记录日志
    /// </summary>
    /// <param name="msg">日志内容</param>
    /// <param name="type">日志类型</param>
    public static void Log(string msg, LogType type)
    {
      string _msg = string.Format("{0} {1}: {2}", DateTime.Now.ToString("HH:mm:ss"), type, msg);
      LogColQueue.Enqueue(_msg);
    }
    /// <summary>
    /// 记录日志
    /// </summary>
    /// <param name="ex">异常</param>
    public static void Log(Exception ex)
    {
      if (ex != null)
      {
        string _newLine = Environment.NewLine;
        StringBuilder _builder = new StringBuilder();
        _builder.AppendFormat("{0}: {1}{2}", DateTime.Now.ToString("HH:mm:ss"), ex.Message, _newLine);
        _builder.AppendFormat("{0}{1}", ex.GetType(), _newLine);
        _builder.AppendFormat("{0}{1}", ex.Source, _newLine);
        _builder.AppendFormat("{0}{1}", ex.TargetSite, _newLine);
        _builder.AppendFormat("{0}{1}", ex.StackTrace, _newLine);
        LogColQueue.Enqueue(_builder.ToString());
      }
    }
    private static void WriteLog()
    {
      while (true)
      {
        if (LogColQueue.Count() > 0)
        {
          string _msg = LogColQueue.Dequeue();
          Monitor.Enter(SyncRoot);
          if (!CreateDirectory()) continue;
          string _path = string.Format("{0}{1}.log", FilePath, DateTime.Now.ToString("yyyyMMdd"));
          Monitor.Exit(SyncRoot);
          lock (SyncRoot)
          {
            if (CreateFile(_path))
              ProcessWriteLog(_path, _msg);//写入日志到文本
          }
          ProcessBackLog(_path);//日志备份
        }
      }
    }
    private static void ProcessBackLog(string path)
    {
      lock (SyncRoot)
      {
        if (FileToolV2.GetMBSize(path) > BackFileSize_MB)
        {
          FileToolV2.CopyToBak(path);
        }
      }
    }
    private static void ProcessWriteLog(string path, string msg)
    {
      try
      {
        StreamWriter _sw = File.AppendText(path);
        _sw.WriteLine(msg);
        _sw.Flush();
        _sw.Close();
      }
      catch (Exception ex)
      {
        Debug.WriteLine(string.Format("写入日志失败,原因:{0}", ex.Message));
      }
    }
    private static bool CreateFile(string path)
    {
      bool _result = true;
      try
      {
        if (!File.Exists(path))
        {
          FileStream _files = File.Create(path);
          _files.Close();
        }
      }
      catch (Exception)
      {
        _result = false;
      }
      return _result;
    }
    private static bool CreateDirectory()
    {
      bool _result = true;
      try
      {
        if (!Directory.Exists(FilePath))
        {
          Directory.CreateDirectory(FilePath);
        }
      }
      catch (Exception)
      {
        _result = false;
      }
      return _result;
    }

  }
}

测试代码如下:

using CSharpUtilHelpV2;
using System;
using System.Diagnostics;
using System.Threading;

namespace LogUtilHelpV2Test
{
  class Program
  {
    static void Main(string[] args)
    {
      try
      {
        Debug.WriteLine("-------------");
        Action _writeLog = delegate()
        {
          for (int i = 0; i < 10000; i++)
            LogToolV2.Log(Guid.NewGuid().ToString(), LogType.Trace);
        };
        Thread _wireteLogTask1 = new Thread(new ThreadStart(_writeLog));
        _wireteLogTask1.Start();

        Thread _wireteLogTask2 = new Thread(new ThreadStart(_writeLog));
        _wireteLogTask2.Start();

        //throw new Exception("test  aaa bb cc");
      }
      catch (Exception ex)
      {
        LogToolV2.Log(ex);
        Console.WriteLine(ex.Message.Trim());
      }
      finally
      {
        Console.WriteLine("ok");
        Console.ReadLine();
      }
    }
  }
}

代码运行效果如下所示:

感兴趣的读者可以自己测试运行一下,希望能对大家起到一点帮助!

更多精彩内容其他人还在看

c#开发word批量转pdf源码分享

已经安装有Office环境,借助一些简单的代码即可实现批量Word转PDF,看下面的实例源码吧
收藏 0 赞 0 分享

c# xml API操作的小例子

这篇文章主要介绍了c# xml API操作的小例子,有需要的朋友可以参考一下
收藏 0 赞 0 分享

c#唯一值渲染实例代码

这篇文章主要介绍了c#唯一值渲染实例代码,有需要的朋友可以参考一下
收藏 0 赞 0 分享

淘宝IP地址库采集器c#代码

这篇文章主要介绍了淘宝IP地址库采集器c#代码,有需要的朋友可以参考一下
收藏 0 赞 0 分享

C#在后台运行操作(BackgroundWorker用法)示例分享

BackgroundWorker类允许在单独的专用线程上运行操作。如果需要能进行响应的用户界面,而且面临与这类操作相关的长时间延迟,则可以使用BackgroundWorker类方便地解决问题,下面看示例
收藏 0 赞 0 分享

c#文本加密程序代码示例

这是一个加密软件,但只限于文本加密,加了窗口控件的滑动效果,详细看下面的代码
收藏 0 赞 0 分享

c#生成站点地图(SiteMapPath)文件示例程序

这篇文章主要介绍了c#生成站点地图(SiteMapPath)文件的示例,大家参考使用
收藏 0 赞 0 分享

C# 键盘Enter键取代Tab键实现代码

这篇文章主要介绍了C# 键盘Enter键取代Tab键实现代码,有需要的朋友可以参考一下
收藏 0 赞 0 分享

C# WinForm导出Excel方法介绍

在.NET应用中,导出Excel是很常见的需求,导出Excel报表大致有以下三种方式:Office PIA,文件流和NPOI开源库,本文只介绍前两种方式
收藏 0 赞 0 分享

C#串口通信程序实例详解

在.NET平台下创建C#串口通信程序,.NET 2.0提供了串口通信的功能,其命名空间是System.IO.Ports,创建C#串口通信程序的具体实现是如何的呢?让我们开始吧
收藏 0 赞 0 分享
查看更多