ASP.NET MVC会计教学管理端项目系列--Log4Net日志组件
02: ASP.NET MVC会计教学管理端项目系列–三层+MVVM搭建
03: ASP.NET MVC会计教学管理端项目系列–autofac批量注入
文章目录
- Log4Net
- logger节点配置详解
- 日志级别等级
- ILog对象说明
- 简单使用
- 自定义配置扩展
- ES 扩展
Log4Net
log4net库是Apache log4j框架在Microsoft .NET平台的实现,是一个帮助程序员将日志信息输出到各种目标(控制台、文件、数据库等)的工具
logger节点配置详解
logger节点支持的属性:name、additivity。
name 必须的,logger的名称,在代码中得到ILog对象时用到。
additivity 可选,取值是true或false,默认值是true。设置为false时将阻止父logger中的appender。
logger支持的子元素:level、appender-ref、param。
level 最多一个。在这个级别或之上的才会被记录。OFF、FATAL、ERROR、WARN 、INFO、DEBUG、ALL
appender-ref 0个或多个,要引用的appender的名字。
param 0个或多个,设置一些参数。
日志级别等级
高到底分别为:OFF > FATAL > ERROR > WARN > INFO > DEBUG > ALL
ILog对象说明
ILog是实现Logger的一个接口,ILog定义了5个方法(Debug,Inof,Warn,Error,Fatal)分别对不同的日志等级记录日志。这5个方法都有1个重载,以Debug为例说明一下,其它的和它差不多。
ILog中对Debug方法的定义如下:
void Debug(object message);
void Debug(object message, Exception exception);
还有一个布尔属性:
bool IsDebugEnabled { get; }
如果使用Debug(object message, Exception exception)则无论Layout如何配置,日志都会输出Exception信息,包括Exception的Message和Trace。如果使用Debug(object message),则无论Layout如何配置是不会输出Exception信息的。
在代码中可以使用LogManager类来得到Logger配置下的相应的ILog对象,LogManager类用来管理所应得Logger,它的GetLogger静态方法,可以获得配置文件中相应的Logger,代码如下:
ILog log = LogManager.GetLogger("logger-name")
简单使用
1、在web站点中的Web.config中根节点 configuration添加如下配置
<!--此处是log4net的配置-->
<log4net>
<!--错误日志类-->
<logger name="logerror">
<!--日志类的名字-->
<level value="ALL" />
<!--定义记录的日志级别-->
<appender-ref ref="ErrorAppender" />
<!--记录到哪个介质中去-->
</logger>
<root>
<level value="WARN" />
<appender-ref ref="LogFileAppender" />
<appender-ref ref="ConsoleAppender" />
</root>
<!--异常日志→name的值要对应你LogHelper的log4net.LogManager.GetLogger("logerror");不区分大小写-->
<logger name="LogError">
<level value="ALL" />
<appender-ref ref="InfoAppender" />
</logger>
<appender name="ErrorAppender" type="log4net.Appender.RollingFileAppender">
<!-- name属性指定其名称,type则是log4net.Appender命名空间的一个类的名称,意思是,指定使用哪种介质-->
<param name="File" value="App_Data\\LogError\\" />
<!--日志输出到exe程序这个相对目录下-->
<param name="AppendToFile" value="true" />
<!--输出的日志不会覆盖以前的信息-->
<param name="MaxSizeRollBackups" value="100" />
<!--备份文件的个数-->
<param name="MaxFileSize" value="10240" />
<!--当个日志文件的最大大小-->
<param name="StaticLogFileName" value="false" />
<!--是否使用静态文件名-->
<param name="DatePattern" value="yyyyMMdd".txt"" />
<!--日志文件名-->
<param name="RollingStyle" value="Date" />
<!--文件创建的方式,这里是以Date方式创建-->
<!--错误日志布局-->
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="<HR COLOR=red>%n异常时间:%d [%t] <BR>%n异常级别:%-5p <BR>%n异 常 类:%c [%x] <BR>%n%m <BR>%n <HR Size=1>" />
</layout>
</appender>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%d [%t] %-5p %c [%x] - %m%n" />
</layout>
</appender>
</log4net>
2、Web站点安装Nuget包
3、在Global.asax中Application_Start方法添加如下代码:
log4net.Config.XmlConfigurator.Configure();
4、新建基础类库同样安装log4net包,添加日志记录帮助类:
public class LogHelper
{
public static readonly log4net.ILog loginfo = log4net.LogManager.GetLogger("loginfo");
public static readonly log4net.ILog logerror = log4net.LogManager.GetLogger("logerror");
/// <summary>
/// 操作日志
/// </summary>
/// <param name="info"></param>
public static void Info(string info)
{
if (loginfo.IsInfoEnabled)
{
loginfo.Info(info);
}
}
/// <summary>
/// 错误日志
/// </summary>
/// <param name="info"></param>
/// <param name="ex"></param>
public static void Error(string info, Exception ex)
{
if (logerror.IsErrorEnabled)
{
logerror.Error(info, ex);
}
}
/// <summary>
/// 警告日志
/// </summary>
/// <param name="info"></param>
/// <param name="ex"></param>
public static void Warn(string info, Exception ex)
{
if (logerror.IsWarnEnabled)
{
logerror.Warn(info, ex);
}
}
/// <summary>
/// 调试日志
/// </summary>
/// <param name="info"></param>
/// <param name="ex"></param>
public static void Debug(string info, Exception ex)
{
if (logerror.IsDebugEnabled)
{
logerror.Debug(info, ex);
}
}
}
自定义配置扩展
1、WebConfig 中添加默认日志路径:
<!--默认文本日志路径-->
<add key="TxtLogPath" value="D:\Log\\"/>
<!--自定义日志文件路径,如果没配置走文本日志路径-->
<add key="Log4NetConfigPath" value="D:\\Log4Net.Config"/>
2、自定义扩展并支持日志分卷
/// <summary>
/// Log4文件上限分卷日志组件
/// </summary>
public static class Logger
{
//是否使用组件默认配置
public static bool IsDefaultConfig;
static Logger()
{
try
{
var log4NetConfigPath = ConfigManager.AppSetting("Log4NetConfigPath");
if (log4NetConfigPath == null)
{
IsDefaultConfig = true;
return;
}
XmlConfigurator.Configure(new System.IO.FileInfo(log4NetConfigPath));
}
catch
{
IsDefaultConfig = true;
}
}
#region 日志静态实现方法,不可被重写
/// <summary>
/// 提示信息
/// </summary>
/// <param name="logPath">日志记录的自定义路径(D://Log//),如果是业务路径,则自动忽略</param>
/// <param name="msg"></param>
/// <param name="isDefaultlogPath"></param>
public static void Info(string msg, string logPath = "", bool isDefaultlogPath = true)
{
logPath = GetLogPath(isDefaultlogPath, logPath);
Logging.LogInfo(logPath, msg);
}
/// <summary>
/// 告警信息
/// </summary>
/// <param name="logPath">日志记录的自定义路径(D://Log//),如果是业务路径,则自动忽略</param>
/// <param name="msg"></param>
/// <param name="isDefaultlogPath"></param>
public static void Warn(string msg, string logPath = "", bool isDefaultlogPath = true)
{
logPath = GetLogPath(isDefaultlogPath, logPath);
Logging.LogInfo(logPath, msg);
}
/// <summary>
/// 记录错误日志
/// </summary>
/// <param name="logPath">日志记录的自定义路径(D://Log//),如果是业务路径,则自动忽略</param>
/// <param name="msg"></param>
/// <param name="ex"></param>
/// <param name="isDefaultlogPath"></param>
public static void Error(string msg, Exception ex = null, string logPath = "", bool isDefaultlogPath = true)
{
logPath = GetLogPath(isDefaultlogPath, logPath);
Logging.LogError(logPath, msg, ex);
}
private static string GetLogPath(bool isDefaultlogPath, string logPath = "")
{
try
{
//如果不是默认路径,则根据跟目录获取相关域名
if (!isDefaultlogPath || !IsDefaultConfig)
{
return logPath;
}
logPath = ConfigManager.AppSetting("TxtLogPath");
if (logPath == null)
{
throw new Exception($"初始化日志配置文件出错,请检查【TxtLogPath】是否配置,且路径完全正确");
}
return logPath;
}
catch (Exception ex)
{
throw new Exception($"初始化日志配置文件出错,请检查【TxtLogPath】是否配置,且路径完全正确,异常信息:{ex}");
}
}
#endregion
}
ES 扩展
【本次项目暂不使用ES,这里只做示范】
1、安装包log4stash,log4stash是日志记录es的一个组件
2、配置es
<!--ES日志管理,本次项目暂不使用ES-->
<add key="ElasticSearchService" value="10.1.21.1|9200|eadminlog"/>
3、调用
/// <summary>
/// 日志记录工具类
/// </summary>
public static class Logging
{
private static readonly object MLock = new object();
private const string Maxfilesize = "LogMaxFileSize";
private const string Maxsizerollbackups = "LogMaxSizeRollBackups";
public static string[] Configs;
public static ConcurrentDictionary<string, object> Dic = new ConcurrentDictionary<string, object>();
static Logging()
{
BasicConfigurator.Configure();
var elasticSearch = ConfigManager.AppSetting("ElasticSearchService");
if (elasticSearch == null)
{
return;
}
Configs = elasticSearch.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
if (Configs.Length != 3)
{
throw new Exception($"初始化日志配置文件出错,请检查【ElasticSearchService】是否配置,正确格式如下:10.1.21.1|9200|efinancelog");
}
}
#region Info
/// <summary>
/// 日志目录地址(绝对路径)
/// </summary>
/// <param name="logpath"></param>
/// <param name="info"></param>
public static void LogInfo(string logpath, string info)
{
var logFile = GetLog("loginfo", logpath);
if (!logFile.IsInfoEnabled) return;
logFile.Info(info);
}
#endregion
#region error
/// <summary>
/// A private method that really do the work of logging
/// </summary>
/// <param name="message"></param>
/// <param name="ex"></param>
/// <param name="logPath"></param>
public static void LogError(string logPath, string message, Exception ex)
{
var logFile = GetLog("logerror", logPath);
if (!logFile.IsErrorEnabled) return;
logFile.Error(message, ex);
}
#endregion
#region commom
public static ILog GetLog(string name, string logpath = "")
{
try
{
var log = LogManager.GetLogger(name);
if (((log4net.Repository.Hierarchy.Logger)log.Logger).GetAppender(name) != null) return log;
lock (MLock)
{
((log4net.Repository.Hierarchy.Logger)log.Logger).AddAppender(new NRollingFileAppender(logpath, name));
if (Configs?.Length == 3)
{
((log4net.Repository.Hierarchy.Logger)log.Logger).AddAppender(new NElasticSearchAppender("ElasticSearch"));
}
}
return log;
}
catch
{
return LogManager.GetLogger("logFile");
}
}
internal static bool IsPhysicsPath(string path)
{
var regex = new Regex(@"^([a-zA-Z]:\\)?[^\/\:\*\?\""\<\>\|\,]*$");
return regex.IsMatch(path);
}
#endregion
#region config
/// <summary>
/// 构建日志RollingFileAppender
/// </summary>
private sealed class NRollingFileAppender : RollingFileAppender
{
public NRollingFileAppender(string logPath, string logName)
{
File = Path.Combine(logPath, $"{logName}\\");
Name = logName;
Layout = new PatternLayout("%n记录时间:%date 线程ID:[%thread] 日志级别:%-5level %n日志描述:%message %n");
ImmediateFlush = true;
MaxFileSize = GetMaxFileSize();
DatePattern = "yyyy-MM-dd-HH.'txt'";
MaxSizeRollBackups = GetMaxSizeRollBackups();
RollingStyle = RollingMode.Composite;
AppendToFile = true;
StaticLogFileName = false;
LockingModel = new MinimalLock();
base.ActivateOptions();
}
/// <summary>
/// 当日志文件达到MaxFileSize大小,就自动创建备份文件。备份文件的多少由MaxSizeRollBackups决定
/// </summary>
/// <returns></returns>
private static int GetMaxSizeRollBackups()
{
var config = ConfigManager.AppSetting(Maxsizerollbackups);
if (string.IsNullOrEmpty(config))
config = "-1";
int i;
int.TryParse(config, out i);
return i != 0 ? i : -1;
}
/// <summary>
/// 获取每个日志文件最大容量
/// </summary>
/// <returns></returns>
private static long GetMaxFileSize()
{
var config = ConfigManager.AppSetting(Maxfilesize);
double rate = 1024;
string unit = "m";
if (string.IsNullOrEmpty(config))
config = "20M";
config = config.ToLower();
if (config.EndsWith("m"))
{
rate = Math.Pow(rate, 2);
}
else if (config.EndsWith("g"))
{
rate = Math.Pow(rate, 3);
unit = "g";
}
int i = config.IndexOf(unit, StringComparison.Ordinal);
int quota = 0;
if (i > 0)
{
var data = config.Substring(0, i);
int.TryParse(data, out quota);
}
quota = quota == 0 ? 20 : quota;
return (long)(quota * rate);
}
}
private sealed class NElasticSearchAppender : ElasticSearchAppender
{
public NElasticSearchAppender(string logName)
{
Server = Configs[0];
Port = Convert.ToInt32(Configs[1]);
IndexName = $"{Configs[2]}_{DateTime.Now.ToString("yyyy-MM-dd")}";
IndexType = "LogEvent";
Name = logName;
Layout = new PatternLayout("%n记录时间:%date 线程ID:[%thread] 日志级别:%-5level %n日志描述:%message %n");
base.ActivateOptions();
}
}
private sealed class SmtpAppenderAppender : SmtpAppender
{
public SmtpAppenderAppender(string logName)
{
Authentication=SmtpAuthentication.Basic;
Port = Convert.ToInt32(Configs[1]);
Name = logName;
Layout = new PatternLayout("%n记录时间:%date 线程ID:[%thread] 日志级别:%-5level %n日志描述:%message %n");
base.ActivateOptions();
}
}
#endregion
}