c# 实现一个简单的异常日志记录(异常迭代+分片+定时清理)+AOP Rougamo全局注入

news2024/12/24 17:44:44

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[1].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 方法

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2264848.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据库压力测试详解

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 很多人提到 jmeter 时&#xff0c;只会说到 jmeter进行接口自动化或接口性能测试&#xff0c;其实jmeter还能对数据库进行自动化操作。个人常用的场景有以下&#…

深度学习中,用损失的均值或者总和反向传播的区别

如深度学习中代码&#xff1a; def train_epoch_ch3(net, train_iter, loss, updater):"""The training loop defined in Chapter 3."""# Set the model to training modeif isinstance(net, torch.nn.Module):net.train()# Sum of training lo…

UML图【重要】

文章目录 2.1 类图概述2.2 类图的作用2.3 类图表示法2.3.1 类的表示方式2.3.2 类与类之间关系的表示方式2.3.2.1 关联关系2.3.2.2 聚合关系2.3.2.3 组合关系2.3.2.4 依赖关系2.3.2.5 继承关系2.3.2.6 实现关系 统一建模语言&#xff08;Unified Modeling Language&#xff0c;U…

Flask中@app.route()的methods参数详解

诸神缄默不语-个人CSDN博文目录 在 Flask 中&#xff0c;app.route 是用于定义路由的核心装饰器&#xff0c;开发者可以通过它为应用指定 URL 映射及相应的处理函数。在处理 HTTP 请求时&#xff0c;不同的业务场景需要支持不同的 HTTP 方法&#xff0c;而 app.route 的 metho…

JavaSE---String(含一些源码)

&#xff08;一&#xff09;字符串构造 我们如何创建一个String类型的对象&#xff1f;有三种&#xff1a; String s1new String("hello"); //直接new一个String对象String s2"hello"; //使用常量串构造final char[] chars {h,e,l,l,o}; Strin…

0.96寸OLED显示屏详解

我们之前讲了 LCD1602&#xff0c;今天我们将它的进阶模块——OLED。它接线更少&#xff0c;性能更强&#xff0c;也能显示中文和图像了。 大家在学习单片机的时候是否会遇到调试的问题呢&#xff1f;例如 “这串代码我到底运行成功了没有” &#xff0c;我相信很多刚开始学习…

用un-app写的动漫风格的登录界面

动漫风格的的登录、注册界面模板&#xff0c;使用uni-app编写&#xff0c;直接复制粘贴即可。 废话不多说&#xff0c;代码如下&#xff1a; login.vue文件 <template><view class"content"><view class"tab-box"><text class"c…

Pytorch | 从零构建ParNet/Non-Deep Networks对CIFAR10进行分类

Pytorch | 从零构建ParNet/Non-Deep Networks对CIFAR10进行分类 CIFAR10数据集ParNet架构特点优势应用 ParNet结构代码详解结构代码代码详解SSEParNetBlock 类DownsamplingBlock 类FusionBlock 类ParNet 类 训练过程和测试结果代码汇总parnet.pytrain.pytest.py 前面文章我们构…

【服务器】linux服务器管理员查看用户使用内存情况

【服务器】linux服务器管理员查看用户使用硬盘内存情况 1、查看所有硬盘内存使用情况 df -h2、查看硬盘挂载目录下所有用户内存使用情况 du -sh /public/*3、查看某个用户所有文件夹占用硬盘内存情况 du -sh /public/zhangsan/*

[搜广推]王树森推荐系统——其他召回通道

地理位置召回 GeoHash召回 想法&#xff1a;用户可能对附近发生的事感兴趣 方法&#xff1a;对经纬度的编码&#xff0c;地图上一个长方形区域 索引&#xff1a;GeoHash -> 优质笔记列表(按时间倒排) 这条召回通道没有个性化 同城召回 想法&#xff1a;用户可能对同…

重温设计模式--外观模式

文章目录 外观模式&#xff08;Facade Pattern&#xff09;概述定义 外观模式UML图作用 外观模式的结构C 代码示例1C代码示例2总结 外观模式&#xff08;Facade Pattern&#xff09;概述 定义 外观模式是一种结构型设计模式&#xff0c;它为子系统中的一组接口提供了一个统一…

OpenCV学习——图像融合

import cv2 as cv import cv2 as cvbg cv.imread("test_images/background.jpg", cv.IMREAD_COLOR) fg cv.imread("test_images/forground.png", cv.IMREAD_COLOR)# 打印图片尺寸 print(bg.shape) print(fg.shape)resize_size (1200, 800)bg cv.resize…

ECharts热力图-笛卡尔坐标系上的热力图,附视频讲解与代码下载

引言&#xff1a; 热力图&#xff08;Heatmap&#xff09;是一种数据可视化技术&#xff0c;它通过颜色的深浅变化来表示数据在不同区域的分布密集程度。在二维平面上&#xff0c;热力图将数据值映射为颜色&#xff0c;通常颜色越深表示数据值越大&#xff0c;颜色越浅表示数…

进程间关系与守护进程

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 进程间关系与守护进程 收录于专栏[Linux学习] 本专栏旨在分享学习Linux的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录 1. 进程组 什…

LightGBM分类算法在医疗数据挖掘中的深度探索与应用创新(上)

一、引言 1.1 医疗数据挖掘的重要性与挑战 在当今数字化医疗时代,医疗数据呈爆炸式增长,这些数据蕴含着丰富的信息,对医疗决策具有极为重要的意义。通过对医疗数据的深入挖掘,可以发现潜在的疾病模式、治疗效果关联以及患者的健康风险因素,从而为精准医疗、个性化治疗方…

【文档搜索引擎】缓冲区优化和索引模块小结

开机之后&#xff0c;首次制作索引会非常慢&#xff0c;但后面就会快了 重启机器&#xff0c;第一次制作又会非常慢 这是为什么呢&#xff1f; 在 parserContent 里面&#xff0c;我们进行了一个读文件的操作 计算机读取文件&#xff0c;是一个开销比较大的操作&#xff0c; …

html+css网页设计 旅游 移动端 雪花旅行社4个页面

htmlcss网页设计 旅游 移动端 雪花旅行社4个页面 网页作品代码简单&#xff0c;可使用任意HTML辑软件&#xff08;如&#xff1a;Dreamweaver、HBuilder、Vscode 、Sublime 、Webstorm、Text 、Notepad 等任意html编辑软件进行运行及修改编辑等操作&#xff09;。 获取源码 …

3 JDK 常见的包和BIO,NIO,AIO

JDK常见的包 java.lang:系统基础类 java.io:文件操作相关类&#xff0c;比如文件操作 java.nio:为了完善io包中的功能&#xff0c;提高io性能而写的一个新包 java.net:网络相关的包 java.util:java辅助类&#xff0c;特别是集合类 java.sql:数据库操作类 IO流 按照流的流向分…

从零创建一个 Django 项目

1. 准备环境 在开始之前&#xff0c;确保你的开发环境满足以下要求&#xff1a; 安装了 Python (推荐 3.8 或更高版本)。安装 pip 包管理工具。如果要使用 MySQL 或 PostgreSQL&#xff0c;确保对应的数据库已安装。 创建虚拟环境 在项目目录中创建并激活虚拟环境&#xff…

ubuntu20.04安装imwheel实现鼠标滚轮调速

ubuntu20.04安装imwheel实现鼠标滚轮调速 Ubuntu 系统自带的设置中仅具备调节鼠标速度的功能&#xff0c;而无调节鼠标滚轮速度的功能。其默认的鼠标滚轮速度较为缓慢&#xff0c;在查看文档时影响尚可接受&#xff0c;但在快速浏览网页时&#xff0c;滚轮速度过慢会给用户带来…