参考:C# log4net的使用。输出的日志内容添加文件名和行号。_log4net 发布 输出的文件中行号-CSDN博客
1.NuGet增加log4net
2.增加log4net.config文件
log4net.config的内容如下,没有的功能可以搜一搜,设置 log4net.config的属性 复制到输出目录 设为始终复制
<?xml version="1.0" encoding="utf-8"?> <configuration><configSections><section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/></configSections><!--(高) OFF > FATAL > ERROR > WARN > INFO > DEBUG > ALL (低)--><log4net><!--调试信息--><logger name="InfoLog"><level value="ALL" /><appender-ref ref="InfoAppender" /></logger><!--错误信息--><logger name="ErrorLog"><level value="ALL" /><appender-ref ref="ErrorAppender" /></logger><!--Info日志附加介质--><appender name="InfoAppender" type="log4net.Appender.RollingFileAppender"><!--日志路径--><param name= "File" value= "Logs\"/><!--是否是向文件中追加日志--><param name= "AppendToFile" value= "true"/><!--log保留天数--><param name= "MaxSizeRollBackups" value= "100"/><!--写到一个文件--><staticLogFileName value="false"/><!--单个文件大小。单位:KB|MB|GB--><maximumFileSize value="200MB"/><!--最多保留的文件数,设为"-1"则不限--><maxSizeRollBackups value="-1"/><!--日志文件名格式--><param name= "DatePattern" value= "yyyyMM\\yyyyMMdd'_InfoLog.log'"/><!--不以独占方式记录日志,仅在记录每个日志的最短时间内锁定,因为部署到服务器上遇到了文件被占用无法下载日志--><lockingModel type="log4net.Appender.FileAppender+MinimalLock" /><!--日志根据日期滚动--><param name= "RollingStyle" value= "Date"/><!--日志文本格式--><layout type="log4net.Layout.PatternLayout"><!--%d 时间,等价于 date--><!--%t 线程--><!--%-5p 日志级别--><!--%C 出错类,等价于 class,可以使用:%class{1},如果给出了精度说明符,则只会打印类名中最右边的组件的相应数量。默认情况下,类名以完全限定形式输出。--><!--%L 出错行--><!--%M 方法名,等价于 method--><!--%m 日志信息,等价于 message--><!--%n 换行--><!--这种情况输出的类名方法名输出的是封装的类名<LogHelper>方法名每有意义--><!--<param name="ConversionPattern" value="**********%d 线程[%t] 日志级别[%p]**********%n类名:%C 方法名:%M - 第 [%L] 行%n消息:%m%n%n" />--><param name="ConversionPattern" value="**********%d 线程[%t] 日志级别[%p]**********%n消息:%m%n%n"/></layout></appender><!--Error日志附加介质--><appender name="ErrorAppender" type="log4net.Appender.RollingFileAppender"><!--日志路径--><param name= "File" value= "Logs\"/><!--是否是向文件中追加日志--><param name= "AppendToFile" value= "true"/><!--log保留天数--><param name= "MaxSizeRollBackups" value= "100"/><!--日志文件名是否是固定不变的--><param name= "StaticLogFileName" value= "false"/><!--日志文件名格式--><param name= "DatePattern" value= "yyyyMM\\yyyyMMdd'_ErrorLog.log'"/><!--日志根据日期滚动--><param name= "RollingStyle" value= "Date"/><param name="MaxFileSize" value="1"/><!--日志文本格式--><layout type="log4net.Layout.PatternLayout"><!--%d 时间,等价于 date--><!--%t 线程--><!--%-5p 日志级别--><!--%C 出错类,等价于 class,可以使用:%class{1},如果给出了精度说明符,则只会打印类名中最右边的组件的相应数量。默认情况下,类名以完全限定形式输出。--><!--%L 出错行--><!--%M 方法名,等价于 method--><!--%m 日志信息,等价于 message--><!--%n 换行--><!--这种情况输出的类名方法名输出的是封装的类名<LogHelper>方法名每有意义--><!--<param name="ConversionPattern" value="**********%d 线程[%t] 日志级别[%p]**********%n类名:%C 方法名:%M - 第 [%L] 行%n消息:%m%n%n" />--><param name="ConversionPattern" value="**********%d 线程[%t] 日志级别[%p]**********%n消息:%m%n%n"/></layout></appender></log4net> </configuration>
3.创建LogHelper.cs类
using System.Diagnostics; using System.IO; using log4net;[assembly: log4net.Config.XmlConfigurator(ConfigFile = "Log4net\\log4net.config", Watch = true)]namespace TestLog4net.Log4net {/// <summary>/// 日志助手类/// </summary>internal class LogHelper{private static ILog InfoLog = LogManager.GetLogger("InfoLog");private static ILog ErrorLog = LogManager.GetLogger("ErrorLog");//Debug Info Warn Error方法 在日志里体现在日志级别上/// <summary>/// 写日志/// </summary>/// <param name="message">日志信息</param>
public static void WriteInfoLog(string message)
{
InfoLog.Info(AppendClassLine(message));
}
/// <summary>/// 写错误日志/// </summary>/// <param name="message">日志信息</param>public static void WriteErrorLog(string message){ErrorLog.Error(AppendClassLine(message));}/// <summary>/// 给日志信息附加所在文件名和行/// </summary>/// <param name="msg">日志信息</param>/// <returns>附加后的日志信息</returns>static string AppendClassLine(string msg){string logStr = msg;try{//测试了一下这个new StackTrace(true) 10w次耗时1.3秒,性能可以接收啊//这个原理是读pdb文件,也许大项目读这个文件会更耗时StackTrace st = new StackTrace(true);StackFrame sf = st.GetFrame(2);logStr = $"{msg} [{Path.GetFileName(sf.GetFileName())}:{sf.GetFileLineNumber().ToString()}]";}catch{logStr = $"{msg} [没找到文件名和所在行]";}return logStr;}} }
这里的new StackTrace(true)性能测试代码如下
using System; using System.Diagnostics;namespace ConsoleApp1 {internal class Program{static void Main(string[] args){const int iterations = 100000;// 测试 new StackTrace(false) 的性能var stopwatch1 = Stopwatch.StartNew();for (int i = 0; i < iterations; i++){var stackTrace = new StackTrace(false);}stopwatch1.Stop();Console.WriteLine($"new StackTrace(false) 耗时: {stopwatch1.ElapsedMilliseconds} 毫秒");// 测试 new StackTrace(true) 的性能var stopwatch2 = Stopwatch.StartNew();for (int i = 0; i < iterations; i++){var stackTrace = new StackTrace(true);}stopwatch2.Stop();Console.WriteLine($"new StackTrace(true) 耗时: {stopwatch2.ElapsedMilliseconds} 毫秒");}} }
4.日志调用
using TestLog4net.Log4net;namespace TestLog4net {internal class Program{static void Main(string[] args){LogHelper.WriteInfoLog("info日志");LogHelper.WriteErrorLog("error日志");}} }
5.日志效果