泉缘泉 发表于 2024-12-25 22:23:57

c# 实现一个简朴的非常日志记录(非常迭代+分片+定时清理)+AOP Rougamo全

1. 日志目录和文件管理



[*]日志目录:日志文件存储在 ./Exceptions 目录下。
[*]日志文件定名:日志文件的定名格式为 yyyy_MM_dd.log,表现当天的日期。假如当天的日志文件大小超过 maxFileSizeBytes(3KB),则会创建新的日志文件,文件名格式为 yyyy_MM_dd_P{cnt}.log,此中 cnt 是日志文件的编号。
[*]日志文件编码:日志文件使用 UTF-8 编码。
2. 非常日志记录



[*]WriteExceptionLog(Exception ex) 方法:
该方法用于记录非常信息。首先检查日志目录是否存在,假如不存在则创建。
获取当前日期的日志文件列表,并选择最新的日志文件(按文件名顺序)。
假如日志文件存在且大小超过 maxFileSizeBytes,则创建一个新的日志文件,文件名中包罗 _P{cnt},此中 cnt 是文件的编号。
将非常信息追加到日志文件中,使用 GetLogEntry(ex) 方法天生非常信息的日志条目。
末了调用 CleanupOldLogFiles() 方法清理超过 maxLogFileAgeDays(1天)的旧日志文件。
3. 日志条目天生



[*]GetLogEntry(Exception ex, int depth = 0) 方法:
– 该方法递归地天生非常信息的日志条目。
– 每层非常信息使用 depth 参数控制缩进,便于阅读。
– 日志条目包括非常时间、非常信息、非常对象和调用堆栈。
– 假如非常有嵌套的内部非常(InnerException),则递归调用 GetLogEntry 方法天生内部非常的日志条目。
4. 旧日志文件清理



[*]CleanupOldLogFiles() 方法:
– 该方法用于清理超过 maxLogFileAgeDays(1天)的旧日志文件。
–获取日志目录中全部 .log 文件,检查文件的末了修改时间,假如超过 maxLogFileAgeDays,则删除该文件。
5. 非常处置处罚



[*]非常处置处罚:在 WriteExceptionLog(Exception ex) 方法中,全部的利用都在 lock 块中举行,确保线程安全。假如发生非常,内部非常会被捕捉但不会记录,制止日志记录自己抛出的非常导致步伐瓦解。
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Shapes;

namespace DataParser.Helpers;

public class LogHelper
{
    private static readonly object objException = new object();
    private static readonly string logDirectory = "./Exceptions";
    private static string curfileName = $"{DateTime.Now:yyyy_MM_dd}.log";
    private static readonly int maxLogFileAgeDays = 1;
    private static readonly long maxFileSizeBytes = 3*1024;
    private static readonly Encoding encoding =Encoding.UTF8;

    static int cnt= 0;

    public static void WriteExceptionLog(Exception ex)
    {
      try
      {
            lock (objException)
            {
                if (!Directory.Exists(logDirectory))
                {
                  Directory.CreateDirectory(logDirectory);
                }

                var files = Directory.GetFiles(logDirectory, "*.log")
                  .Select(x=>System.IO.Path.GetFileName(x))
                  .Where(x => x.Contains($"{DateTime.Now:yyyy_MM_dd}"));

                if(files.Count()>0)
                {
                  var tmp = files.OrderBy(x => x.Length);

                  curfileName = tmp.Last();

                  if (curfileName.Contains("_P"))
                  {
                        Match match = Regex.Match(curfileName, @"_P(\d+)");

                        if (match.Success)
                        {
                            string str = match.Groups.Value;

                            int.TryParse(str, out cnt);
                        }
                  }
                }
                else
                {
                  curfileName = $"{DateTime.Now:yyyy_MM_dd}.log";
                }

                string fileName = System.IO.Path.Combine(logDirectory, curfileName);

                string logEntry = GetLogEntry(ex);


                if (File.Exists(fileName) && (new FileInfo(fileName).Length > maxFileSizeBytes))
                {
                  cnt++;
                  fileName = System.IO.Path.Combine(logDirectory, $"{DateTime.Now:yyyy_MM_dd}_P{cnt}.log");
                }
                else if(!fileName.Contains("_P"))
                {
                  cnt = 0;
                }

                File.AppendAllText(fileName, logEntry, encoding);

                CleanupOldLogFiles();
            }
      }
      catch (Exception innerEx)
      {

      }
    }

    private static string GetLogEntry(Exception ex, int depth = 0)
    {
      string indent = new string(' ', depth * 4);
      string logEntry =
            $"{indent}【异常时间】{DateTime.Now}{Environment.NewLine}" +
            $"{indent}【异常信息】{ex.Message}{Environment.NewLine}" +
            $"{indent}【异常对象】{ex.Source}{Environment.NewLine}" +
            $"{indent}【调用堆栈】{Environment.NewLine}   {ex.StackTrace?.Trim() ?? "N/A"}{Environment.NewLine}{Environment.NewLine}{Environment.NewLine}";

      if (ex.InnerException != null)
      {
            logEntry += GetLogEntry(ex.InnerException, depth + 1);
      }

      return logEntry;
    }

    private static void CleanupOldLogFiles()
    {
      var files = Directory.GetFiles(logDirectory, "*.log")
                .Select(f => new FileInfo(f))
                .Where(f => (DateTime.Now - f.LastWriteTime).TotalDays > maxLogFileAgeDays);

      foreach (var file in files)
      {
            File.Delete(file.FullName);
      }

    }
}
Rougamo 实现AOP

导包Rougamo.Fody
using DataParser.Helpers;
using Rougamo;
using Rougamo.Context;
namespace DataParser
{

    public class ExceptionLogAttribute : MoAttribute
    {
      public override void OnException(MethodContext context)
      {
            LogHelper.WriteExceptionLog(context.Exception);
            context.HandledException(this, null);
      }
    }
}
    public partial class MainViewModel:IRougamo<ExceptionLogAttribute>
    {}
MainViewModel 类实现了接口 IRougamo<ExceptionLogAttribute>。这意味着在这个类中,全部被 ExceptionLogAttribute 特性标记的方法或类,都会在抛出非常时自动调用 ExceptionLogAttribute 的 OnException 方法

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: c# 实现一个简朴的非常日志记录(非常迭代+分片+定时清理)+AOP Rougamo全