WinForm + log4net 企业级日志实战

群里有问我一个请教一个问题。我顺便写一个模板。并写出文档。

在实际项目开发中,我越来越意识到:

日志不是“能用就行”,而是必须“可维护、可分流、可扩展”。

因此我专门写了一个 WinForm + log4net 完整示例项目,实现:

  • ✅ 多级别日志分流
  • ✅ 控制台输出
  • ✅ 按日期滚动文件
  • ✅ 错误独立文件
  • ✅ Windows 事件日志写入
  • ✅ Fatal 邮件告警
  • ✅ 程序入口统一初始化
  • ✅ 配置文件热更新

下面我把完整实现思路 + 全部核心代码详细拆解。


一、日志初始化 —— 必须在程序入口完成

很多人喜欢在窗体里初始化日志,我不这么做。

我统一在 Program.cs 里完成配置加载。

Program.cs
using log4net;
using log4net.Config;
using System;
using System.IO;
using System.Windows.Forms;

namespace WinFormLog4netDemo
{
    internal static class Program
    {
        [STAThread]
        static void Main()
        {
            // ✅ 程序启动第一步:初始化日志系统
            ConfigureLog4net();

            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }

        /// <summary>
        /// 统一配置 log4net
        /// </summary>
        private static void ConfigureLog4net()
        {
            try
            {
                // 1. 定位配置文件
                string configPath = Path.Combine(
                    AppDomain.CurrentDomain.BaseDirectory,
                    "log4net.config");

                FileInfo configFile = new FileInfo(configPath);

                // 2. 检查配置文件是否存在
                if (!configFile.Exists)
                {
                    throw new FileNotFoundException("log4net 配置文件不存在", configPath);
                }

                // 3. 加载并监控配置文件(支持热更新)
                XmlConfigurator.ConfigureAndWatch(configFile);

                // 4. 写一条启动日志
                ILog logger = LogManager.GetLogger(typeof(Program));
                logger.Info("应用程序启动,log4net 配置加载成功");
            }
            catch (Exception ex)
            {
                MessageBox.Show(
                    $"log4net 配置初始化失败:{ex.Message}\n{ex.StackTrace}",
                    "致命错误",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Stop
                );

                Environment.Exit(1);
            }
        }
    }
}
为什么使用 ConfigureAndWatch?

因为它支持:

  • 修改 log4net.config 后自动生效
  • 不需要重启程序
  • 非常适合生产环境

二、日志调用层 —— Form1 实现

我在窗体中定义一个静态日志实例:

private static readonly ILog _logger = 
    LogManager.GetLogger(typeof(Form1));

使用当前类作为 logger 名称,方便定位日志来源。


Form1.cs 完整代码
using System;
using System.Windows.Forms;
using log4net;

namespace WinFormLog4netDemo
{
    public partial class Form1 : Form
    {
        // ✅ 使用当前类作为日志名称
        private static readonly ILog _logger =
            LogManager.GetLogger(typeof(Form1));

        public Form1()
        {
            InitializeComponent();
            // 日志已在 Program 中完成初始化
        }

        /// <summary>
        /// Debug 日志
        /// </summary>
        private void btnDebugLog_Click(object sender, EventArgs e)
        {
            _logger.Debug("用户点击了 Debug 按钮,调试信息:参数 x=123,参数 y=456");
            ShowSuccessTip("Debug 日志已记录!");
        }

        /// <summary>
        /// Info 日志
        /// </summary>
        private void btnInfoLog_Click(object sender, EventArgs e)
        {
            _logger.InfoFormat(
                "用户[{0}]在[{1:yyyy-MM-dd HH:mm:ss}]点击了 Info 按钮",
                Environment.UserName,
                DateTime.Now
            );
            ShowSuccessTip("Info 日志已记录!");
        }

        /// <summary>
        /// Warn 日志
        /// </summary>
        private void btnWarnLog_Click(object sender, EventArgs e)
        {
            _logger.Warn("用户输入的参数格式不规范(预期:数字,实际:字符串),已自动修正");
            ShowWarningTip("Warn 日志已记录!");
        }

        /// <summary>
        /// Error 日志(含异常堆栈)
        /// </summary>
        private void btnErrorLog_Click(object sender, EventArgs e)
        {
            try
            {
                int a = 10;
                int b = 0;
                int result = a / b;
            }
            catch (Exception ex)
            {
                _logger.Error("除法运算出现异常,已捕获并处理", ex);
                ShowErrorTip("Error 日志已记录(含异常堆栈)!");
            }
        }

        /// <summary>
        /// Fatal 日志
        /// </summary>
        private void btnFatalLog_Click(object sender, EventArgs e)
        {
            _logger.Fatal("数据库连接池耗尽,无法执行任何数据库操作,程序即将终止");
            ShowFatalTip("Fatal 日志已记录!");
        }

        #region 统一提示方法

        private void ShowSuccessTip(string message)
        {
            MessageBox.Show(message, "操作成功",
                MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        private void ShowWarningTip(string message)
        {
            MessageBox.Show(message, "警告",
                MessageBoxButtons.OK, MessageBoxIcon.Warning);
        }

        private void ShowErrorTip(string message)
        {
            MessageBox.Show(message, "错误",
                MessageBoxButtons.OK, MessageBoxIcon.Error);
        }

        private void ShowFatalTip(string message)
        {
            MessageBox.Show(message, "致命错误",
                MessageBoxButtons.OK, MessageBoxIcon.Stop);
        }

        #endregion
    }
}

三、核心配置文件 log4net.config

这是整套日志系统的灵魂。


1️⃣ Debug → 控制台输出
<appender name="DebugConsoleAppender" type="log4net.Appender.ConsoleAppender">
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%date [%-5level] %logger - %message%newline" />
  </layout>
  <filter type="log4net.Filter.LevelMatchFilter">
    <levelToMatch value="DEBUG" />
  </filter>
  <filter type="log4net.Filter.DenyAllFilter" />
</appender>

特点:
只匹配 DEBUG,不让其他级别混入。


2️⃣ Info / Warn → 按日期滚动文件
<appender name="InfoWarnFileAppender" type="log4net.Appender.RollingFileAppender">
  <file value="Logs/InfoWarn/" />
  <appendToFile value="true" />
  <rollingStyle value="Date" />
  <datePattern value="yyyyMMdd'.log'" />
  <staticLogFileName value="false" />
  <maxSizeRollBackups value="30" />
  <encoding value="utf-8" />
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%date [%-5level] %logger [%thread] - %message%newline" />
  </layout>
  <filter type="log4net.Filter.LevelRangeFilter">
    <levelMin value="INFO" />
    <levelMax value="WARN" />
  </filter>
</appender>

3️⃣ Error / Fatal → 单独错误文件
<appender name="ErrorFatalFileAppender" type="log4net.Appender.RollingFileAppender">
  <file value="Logs/ErrorFatal/" />
  <appendToFile value="true" />
  <rollingStyle value="Date" />
  <datePattern value="yyyyMMdd'.log'" />
  <staticLogFileName value="false" />
  <encoding value="utf-8" />
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%date [%-5level] %logger [%thread] - %message%newline%exception" />
  </layout>
  <filter type="log4net.Filter.LevelRangeFilter">
    <levelMin value="ERROR" />
    <levelMax value="FATAL" />
  </filter>
</appender>

4️⃣ Windows 事件日志输出
<appender name="ErrorEventAppender" type="log4net.Appender.EventLogAppender">
  <logName value="Application" />
  <applicationName value="WinFormLog4netDemo" />
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%date [%-5level] %logger - %message%newline%exception" />
  </layout>
  <filter type="log4net.Filter.LevelRangeFilter">
    <levelMin value="ERROR" />
    <levelMax value="FATAL" />
  </filter>
</appender>

5️⃣ Fatal 邮件告警
<appender name="FatalMailAppender" type="log4net.Appender.SmtpAppender">
  <to value="admin@your-domain.com" />
  <from value="alert@your-domain.com" />
  <subject value="【WinForm 程序致命错误告警】" />
  <smtpHost value="smtp.qq.com" />
  <smtpPort value="587" />
  <enableSsl value="true" />
  <smtpUsername value="alert@your-domain.com" />
  <smtpPassword value="你的SMTP授权码" />
  <bufferSize value="1" />
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%date [FATAL] %logger%newline%message%newline%exception" />
  </layout>
  <filter type="log4net.Filter.LevelMatchFilter">
    <levelToMatch value="FATAL" />
  </filter>
  <filter type="log4net.Filter.DenyAllFilter" />
</appender>

Root 节点
<root>
  <level value="ALL" />
  <appender-ref ref="DebugConsoleAppender" />
  <appender-ref ref="InfoWarnFileAppender" />
  <appender-ref ref="ErrorFatalFileAppender" />
  <appender-ref ref="ErrorEventAppender" />
  <appender-ref ref="FatalMailAppender" />
</root>

四、我的设计原则总结

在这个示例中,我遵循了三点原则:

  1. 日志分级必须清晰
  2. 错误必须独立文件
  3. 致命问题必须告警

这不是“写日志”,
而是“设计日志系统”。

五、注意

  1. 群友一直弄不起。原因是:log4net.config 配置文件的属性改了一下,复制输出到目录,始终复制
    在这里插入图片描述
    在这里插入图片描述
  2. 如果实现下面功能需要以管理员运行
    在这里插入图片描述

👋 关注我!持续分享 C# 实战技巧、代码示例 & 技术干货

Log4net在Winform项目中的实战配置与日志管理 本文详细介绍了Log4net在Winform项目中的实战配置与日志管理技巧,包括核心价值、环境搭建、高级配置、性能优化及企业级实践。通过异步日志记录、多维度滚动日志策略和敏感信息过滤等方案,帮助开发者提升日志管理效率,确保系统稳定运行。 阅读详情

相关推荐

轻量级Winform快速开发框架:设计、实现与实战应用

在C/S架构的桌面应用开发中,如何提升开发效率、保证代码质量并快速响应业务变化,是开发者面临的核心挑战。其原理在于通过分层架构、模块化设计和通用模式,将数据访问、用户界面、权限管理等通用功能标准化。这种技术方案的价值在于,它能将开发者从重复的“造轮子”工作中解放出来,专注于业务逻辑创新,显著缩短项目周期。典型的应用场景包括企业内部管理系统、中小型工具软件等需要快速迭代的Winform项目。本文聚焦于轻量级Winform快速开发框架的设计与实现,深入探讨了其**数据访问层(DAL)的抽象**与**权限管理模块

weixin_30907935的博客 446

C# winform 配置log4net

Winform配置了Log4net 但是总是不能输出,是log4net.config配置文件访问路径出错了。 就是程序在运行时候没把log4net.config 配置文件复制到Debug文件夹下,导致log4net访问不到配置文件,所以没有log输出。 C# winform 正确配置log4net. 1、项目结构: 2、log4net.config 文件: <?xml version...

进击的Ace 3544

WinForm自定义标签控件开发与优化实践

在WinForm开发中,TabControl控件是构建多页面界面的核心组件。传统系统控件存在样式单一、交互生硬等问题,通过自定义绘制和消息处理机制,开发者可以实现像素级样式控制与交互动画效果。本文介绍的ZYWFormTabControl采用分层架构设计,支持圆角、渐变色等现代化视觉效果,同时通过WndProc重写实现平滑的状态切换。该技术特别适用于ERP系统、工业控制界面等需要长期运行的桌面应用,实测显示能提升40%的视图切换效率。控件采用纯C#实现,无第三方依赖,包含完整的DPI适配和触摸优化方案,是企业

weixin_34162228的博客 445

Log4net在.Net Winform项目中的使用

这个配置文件将日志记录到一个名为“logs\log.txt”的文件中。您可以根据需要进行自定义配置。 在您的代码中,声明一个静态的ILog对象来进行日志记录: 在需要记录日志的地方,使用ILog对象的方法来记录日志。例如: 四、初始化Log4net 在您的Winform项目的入口点或App.config文件中,添加以下初始化代码: 这将告诉Log4net使用先前创建的log4net.config文件进行配置。以下是我修改完善后的代码示例,可以直接复制粘贴使用 结论: 通过按照上述步骤,在

故事不长丨的博客 3207

Winform中使用Log4Net实现日志记录到文件并循环覆盖

Apachelog4net库是一种帮助程序员将日志语句输出到各种输出目标的工具。log4net是优秀的Apache log4j的端口™ 框架到Microsoft®.NET运行时。保持了与原始log4j在精神上相似的框架,同时利用了.NET运行时中的新功能。Winform程序中需要将运行过程的错误日志记录到文件中。

BADAO_LIUMANG_QIZHI的博客 1151

C# Winform用户权限管理系统项目实战

Windows Forms(简称Winform)是基于.NET Framework的图形界面开发框架,它提供了丰富的控件库和事件驱动机制,使开发者能够快速构建功能完善的桌面应用程序。Winform的核心在于其可视化设计器和事件驱动模型,开发者可以通过拖放控件构建界面,并通过编写事件处理逻辑实现交互功能。例如,一个简单的Winform窗体应用可以通过以下C#代码创建一个按钮并绑定点击事件:btn.Text = "点击我";

weixin_42584586的博客 558

超越基础:log4net在WinForm中的高阶应用与性能优化指南

本文深入探讨了log4net在WinForm应用中的高阶应用与性能优化技巧,包括动态日志路径切换、异步日志写入优化、智能日志归档及内存泄漏诊断。通过实际案例和详细配置示例,帮助开发者提升企业级应用的日志管理效率与系统稳定性,特别适合需要处理高并发和复杂业务场景的WinForm开发者。

e1f2g的博客 639

C#多语言房卡棋牌游戏大厅源码:WinForm架构与实战

在桌面客户端开发中,WinForm凭借高效布局与成熟生态,依旧是构建业务复杂型应用的可靠选择。多语言切换机制基于resx资源文件与CultureInfo实现,SignalR则提供了稳定的实时通信能力,确保房间创建、好友加入等状态实时推送。本文从工程分层出发,梳理了登录、房卡消耗、摄像头扩展、插件加载等核心模块的源码实现,并针对语言切换不刷新、SignalR断线重连、DLL加载异常等典型问题给出排查方案。无论你是C#中高级开发者,还是正在接手“大厅+子游戏”模式的项目,都能从中获得可落地的工程参考,避免重复踩

weixin_32631179的博客 329

Winform项目上线后如何快速定位Bug?我用Log4net配置了这3种日志输出方式

本文详细介绍了在Winform项目中使用Log4net配置三种高效日志输出方式(文件日志、Windows事件日志和邮件告警),帮助开发者快速定位生产环境中的Bug。通过实战案例和优化配置,提升日志系统的排查效率,特别适合.Net开发者在Winform项目中应用。

weixin_42665255的博客 96

C#实现推箱子游戏:从核心算法到WinForms界面开发

面向对象编程(OOP)是构建复杂软件系统的核心范式,其通过封装、继承和多态等原则,将现实世界实体抽象为可复用的代码模块。在游戏开发领域,这一原理尤为关键,它帮助开发者将游戏状态、角色行为和交互逻辑清晰地建模为对象。C#作为一门现代、强类型的面向对象语言,凭借其丰富的类库和清晰的语法,成为实现这类逻辑的理想选择。其技术价值在于能够构建出结构清晰、易于维护和扩展的应用程序,尤其在需要精确状态管理和复杂规则处理的场景中,例如经典益智游戏。推箱子游戏正是这样一个绝佳的应用场景,它要求对游戏状态(如地图、玩家位置、箱

weixin_29012677的博客 284

WinForm Log4Net 配置和使用实例

WinForm Log4Net 配置和使用实例,完整的实例。有注释和说明。新手完全能看懂。

.net/c#常用框架/中间件简介

任务调度 Quartz.NET:Quartz.NET是一个开源的作业调度框架,非常适合在平时的工作中,定时轮询数据库同步,定时邮件通知,定时处理数据等。 Quartz.NET允 许开发人员根据时间间隔(或天)来调度作业。它实现了作业和触发器的多对多关系,还能把多个作业与不同的触发器关联。整合了 Quartz.NET的应用程序可以重用来自不同事件的作业,还可以为一个事件组合多个作业。 日志记

Denghejing的专栏 3916

C#Winform 下使用log4net成功的例子

C#Winform 下使用log4net成功的例子 vs2008+c#+winform

winform项目中使用log4net

winform项目中使用log4net1、添加log4net.config2、 修改AssemblyInfo.cs3、新增一个LogHelper4、初始化log4net5、使用 最近在一个winform项目中用到了log4net记录日志,没有阅读官方的文档,只参考了网上一些博客,使用的时候IsErrorEnable、IsInfoEnable等等都为false,导致log4net不能写日志,goog...

木木大哥的专栏 4679

ControlCAN.dll开发适配USBCAN_E/2E_U设备

摘要:本文提供了USBCAN_E/2E_U设备的配置指南:1)安装专用驱动;2)获取最新的ControlCAN.dll文件;3)修改VCI调用顺序,新增VCI_SetReference函数设置波特率;4)使用工具计算波特率配置值,并给出了常见波特率对应的代码参考值(如500K对应0x060007)。配置过程强调使用特定工具计算精确的波特率参数,并提供了相关软件下载链接。

weixin_43969033的博客 387

汽水音乐自动化薅羊毛教程:从零搭建稳定赚钱脚本

📖 前言:为什么要学习自动化脚本?在数字时代,时间就是金钱。汽水音乐等App通过观看广告奖励用户金币的模式,本质上是将我们的时间转化为收益。本教程将教你如何用Python自动化这个过程,让程序为你"打工",实现被动收入。通过本教程,你将学到:移动端自动化测试的核心技术Python在自动化领域的实际应用如何将重复性任务转化为自动化流程创造属于自己的"数字员工"第一章:环境准备与基础配置1.1 硬件要求Android手机一部(建议使用备用机)USB数据线。

weixin_44947827的博客 5773

winform .net程序中使用log4net

【代码】winform .net程序中使用log4net。

xiangyangzhai的博客 761

SAP License USMM SLAW2 SAP审计

引言 企业每年都会收到SAP License审计邮件,邮件内容大致就是根据贵公司与SAP签定的合同XXX条款规定,贵公司所安装的SAP系统需要进行测定。 关键字: SAP License、 SAP USMM、 SLAW2、 SAP 账号、SAP 账号审计、 SAP License 审计、 SAP 审计报告、SAP 账号优化 SAP License审计邮件 企业每年都会收到SAP License审计邮件,邮件内容大致就是根据贵公司与SAP签定的合同XXX条款规定,贵公司所安...

感悟人生 2975

C# winform之Log4Net的使用

下载完拷到项目DEBUG目录下,引用下右击选择添加引用,选择 刚拷贝过来的log4net.dill。在AssemblyInfo.cs文件中加入这条语句。配置文件属性更改为 如果较新则复制。代码添加使用这个log4net库。去下载log4net.dill。

zhoushangshi的博客 1232

Flutter for web 首次加载过慢问题优化

Flutter web 加载慢优化

Bright_TY的专栏 7835

STM32单片机语音提示盲人拐杖整点报时夜间警示超声波测距

STM32单片机语音提示盲人拐杖整点报时夜间警示超声波测距 关键词:语音提示盲人拐杖 整点报时 超声波测距拐杖

LS840233684的博客 2047

winform下使用Log4net(精简版)

1.下载log4net (Google log4net)     2.unzip log4net     3.运行VS,新建 c# Windows应用程序。     4.添加引用Log4NET     5.新建一个应用程序配置文件App.config(具体内容附在后面)     6.打开Form1.cs,       在Namespace上添加一行  [assembly:

1201

关于React Native Android找不到node的错误

最近,按照官方文档初始化了一个React Native项目,但是在Android端运行的时候,报了如下的一个错误。 org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':app:recordFilesBeforeBundleCommandDebug'. Caused by: org.gradle.process.internal.ExecException: A problem occurred starting p

xiangzhihong8的专栏 4246
上一篇: C# 接口(Interface)深入解析
下一篇: C# 命名空间(Namespace)详解
bugcome_com
博客等级 码龄3年 32粉丝 131原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bugcome_com

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值