OperatorLog
/****** Object: Table [dbo].[OperatorLog] Script Date:
SET ANSI_NULLS ON
GO SET QUOTED_IDENTIFIER ON
GO CREATE TABLE [dbo].[OperatorLog](
[Id] [BIGINT] IDENTITY(1,1) NOT NULL,
[Createdate] [DATETIME] NOT NULL DEFAULT (GETDATE()),
[CreatedBy] [NVARCHAR](50) NULL,
[IsDeleted] [BIT] NOT NULL,
[ModuleName] [NVARCHAR](30) NULL,
[Origin] [NVARCHAR](50) NULL,
[Type] [NVARCHAR](50) NULL,
[LogLevel] [NVARCHAR](20) NOT NULL,
[LogMessage] [NVARCHAR](500) NULL,
[Exception] [NVARCHAR](500) NULL,
[Logger] [NVARCHAR](500) NULL
CONSTRAINT [PK_OperatorLog] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] GO EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'日志表主键ID' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'OperatorLog', @level2type=N'COLUMN',@level2name=N'Id'
GO EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'创建时间' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'OperatorLog', @level2type=N'COLUMN',@level2name=N'Createdate'
GO EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'创建人' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'OperatorLog', @level2type=N'COLUMN',@level2name=N'CreatedBy'
GO EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'是否删除' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'OperatorLog', @level2type=N'COLUMN',@level2name=N'IsDeleted'
GO EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'模块名称' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'OperatorLog', @level2type=N'COLUMN',@level2name=N'ModuleName'
GO EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'来源' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'OperatorLog', @level2type=N'COLUMN',@level2name=N'Origin'
GO EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'类型' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'OperatorLog', @level2type=N'COLUMN',@level2name=N'Type'
GO EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'日志级别' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'OperatorLog', @level2type=N'COLUMN',@level2name=N'LogLevel'
GO EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'日志内容' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'OperatorLog', @level2type=N'COLUMN',@level2name=N'LogMessage'
GO EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'异常信息' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'OperatorLog', @level2type=N'COLUMN',@level2name=N'Exception'
GO EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'日志名称' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'OperatorLog', @level2type=N'COLUMN',@level2name=N'Logger'
GO EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'日志记录' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'OperatorLog'
GO
loghelper:
using System;
using System.ComponentModel;
using System.IO;
using log4net;
using ShiShuo.Utilities; namespace Log4Net
{
public enum LogCategory
{
[Description("调试")]
Debug,
[Description("信息")]
Info,
[Description("警告")]
Warn,
[Description("错误")]
Error,
[Description("过错")]
Fault
}
public class LogHelper
{
private static readonly log4net.ILog infoLogger = log4net.LogManager.GetLogger("loginfo"); //选择<logger name="loginfo">的配置
private static readonly log4net.ILog errorLogger = log4net.LogManager.GetLogger("logerror"); //选择<logger name="logerror">的配置
private static readonly log4net.ILog warnLogger = log4net.LogManager.GetLogger("logwarn"); //选择<logger name="logwarn">的配置
private static readonly log4net.ILog debugLogger = log4net.LogManager.GetLogger("logdebug"); //选择<logger name="logdebug">的配置
private static OperatorLogModel logEntity;
public static string CreatedBy = String.Empty; static LogHelper()
{
string configPath = Path.Combine(PathHelper.ConfigDir, "log4net.xml");
if (!File.Exists(configPath))
{
throw new FileNotFoundException("找不到日志服务配置文件!");
}
log4net.Config.XmlConfigurator.ConfigureAndWatch(new FileInfo(configPath));
} /// <summary>
/// 记录log信息到文件中 LogHelper.Log("检测更新启动时异常", LogCategory.Error, ex); LogHelper.Log(ex);
/// </summary>
/// <param name="message">需要记录的信息</param>
/// <param name="category">log类型</param>
/// <param name="exception">异常信息</param>
public static void Log(string message, LogCategory category, Exception exception = null)
{
try
{
switch (category)
{
case LogCategory.Debug:
{ debugLogger.Debug(BuildMessageMode(message));
break;
}
case LogCategory.Info:
{
infoLogger.Info(BuildMessageMode(message));
break;
}
case LogCategory.Warn:
{
if (null == exception)
{
warnLogger.Warn(BuildMessageMode(message));
}
else
{
warnLogger.Warn(BuildMessageMode(message), exception);
}
break;
}
case LogCategory.Error:
{
if (null == exception)
{
errorLogger.Error(BuildMessageMode(message));
}
else
{
errorLogger.Error(BuildMessageMode(message), exception);
}
break;
}
}
}
catch (Exception ex)
{
throw;
}
} /// <summary>
/// 构造消息实体
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
private static OperatorLogModel BuildMessageMode(string message) {
if (logEntity == null) {
logEntity = new OperatorLogModel();
logEntity.Createdate = DateTime.Now;
logEntity.CreatedBy = CreatedBy;
logEntity.IsDeleted = false;
logEntity.LogMessage = message;
}
else
logEntity.LogMessage = message; return logEntity;
} /// <summary>
/// 写基本信息日志
/// </summary>
/// <param name="mesage"></param>
public static void Log(string mesage)
{
Log(mesage, LogCategory.Info, null);
} /// <summary>
/// 出错信息日志
/// </summary>
/// <param name="exception"></param>
public static void Log(Exception exception)
{
Log($"error message:{exception.Message}", LogCategory.Error, exception);
} }
}
pathhelper:
using System;
using System.IO;
using System.Reflection; namespace ShiShuo.Utilities
{
public static class PathHelper
{
private static readonly string _appDir;
private static readonly string _configDir;
private static readonly string _dataDir;
static PathHelper()
{
//网站与后台服务路径不同,网站需要上翻一级;后台服务则不需要;通过判断使用的配置文件是否是web.config来判断是网站,还是服务。
bool isWeb = false;
var appDomain = AppDomain.CurrentDomain; if (appDomain != null)
{
var startInfo = appDomain.SetupInformation;
if (startInfo != null)
{
if (startInfo.ConfigurationFile != null)
{
if (startInfo.ConfigurationFile.EndsWith("web.config", StringComparison.OrdinalIgnoreCase))
{
isWeb = true; //配置文件是网站
}
}
}
}
_appDir = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase.Substring())); //获取此处配置文件在程序目录
//_appDir = _appDir.Substring(0, _appDir.Length - 4); if (isWeb)
{
_appDir = _appDir.Substring(, _appDir.LastIndexOf("\\", StringComparison.Ordinal)); // LastIndexOf("\\") => LastIndexOf(@"\"),向上翻一级
}
_configDir = Path.Combine(_appDir, "Config\\");
_dataDir = Path.Combine(_appDir, "App_Data\\");
}
#region 公共目录
/// <summary>
/// 应用程序所在的目录
/// </summary>
public static string AppDir => _appDir; /// <summary>
/// 根目录中的Cinfig文件夹
/// </summary>
public static string ConfigDir => _configDir; /// <summary>
/// 根目录中的App_Data文件夹
/// </summary>
public static string DataDir => _dataDir; #endregion
}
}
MyLayout:
using log4net.Layout;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web; namespace Log4Net {
public class MyLayout : PatternLayout {
public MyLayout() {
this.AddConverter("property", typeof(MyPatternConverter));
}
}
}
MyPatternConverter:
using log4net.Layout.Pattern;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Web; namespace Log4Net {
public class MyPatternConverter : PatternLayoutConverter {
protected override void Convert(System.IO.TextWriter writer, log4net.Core.LoggingEvent loggingEvent) {
if (Option != null)
WriteObject(writer, loggingEvent.Repository, LookupProperty(Option, loggingEvent));
else
WriteDictionary(writer, loggingEvent.Repository, loggingEvent.GetProperties());
} //通过反射获取传入的日志对象的某个属性的值
private object LookupProperty(string property, log4net.Core.LoggingEvent loggingEvent) {
object propertyvalue = string.Empty;
PropertyInfo propertyInfo = loggingEvent.MessageObject.GetType().GetProperty(property); if (propertyInfo != null)
propertyvalue = propertyInfo.GetValue(loggingEvent.MessageObject, null);
return propertyvalue;
}
}
}
log4net.xml
<?xml version="1.0" encoding="utf-8"?>
<log4net debug="false"> <!--错误日志配置-->
<appender name="ErrorAppender" type="log4net.Appender.RollingFileAppender">
<param name="File" value="./Log/Error/" />
<param name="Encoding" value="utf-8"/>
<param name="AppendToFile" value="true" />
<param name="MaxSizeRollBackups" value="" />
<param name="MaxFileSize" value="" />
<!--设置单个文件大小,设置文件名使用组合方式-->
<param name="MaximumFileSize" value="100MB"/>
<!--最小锁定模型以允许多个进程可以写入同一个文件-->
<param name="lockingModel" type="log4net.Appender.FileAppender+MinimalLock" />
<param name="StaticLogFileName" value="false" />
<param name="DatePattern" value="""yyyyMMdd".log"" />
<param name="RollingStyle" value="Composite" />
<filter type="log4net.Filter.LevelRangeFilter">
<levelMin value="ERROR" />
<levelMax value="FATAL" />
</filter>
<!--<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%n异常时间:%d [%t] %n异常级别:%-5p %n异 常 类:%c [%x] %n%m %n " />
</layout>-->
<layout type="Log4Net.MyLayout">
<param name="ConversionPattern" value="日志时间:%d [%t] %n日志级别:%-5p %n日志信息:%property{LogMessage} %n异常信息:%exception %n%n"/>
</layout>
</appender> <!--信息日志配置-->
<appender name="InfoAppender" type="log4net.Appender.RollingFileAppender">
<param name="File" value="./Log/Info/" />
<param name="Encoding" value="utf-8"/>
<param name="AppendToFile" value="true" />
<param name="MaxSizeRollBackups" value="" />
<param name="MaxFileSize" value="" />
<param name="MaximumFileSize" value="100MB"/>
<param name="lockingModel" type="log4net.Appender.FileAppender+MinimalLock" />
<param name="MaxSizeRollBackups" value="" />
<param name="StaticLogFileName" value="false" />
<param name="DatePattern" value="""yyyyMMdd".log"" />
<param name="RollingStyle" value="Composite" />
<filter type="log4net.Filter.LevelRangeFilter">
<levelMin value="DEBUG" />
<levelMax value="WARN" />
</filter>
<!--<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%n异常时间:%d [%t] %n异常级别:%-5p %n异 常 类:%c [%x] %n%m %n " />
</layout>-->
<layout type="Log4Net.MyLayout">
<param name="ConversionPattern" value="日志时间:%d [%t] %n日志级别:%-5p %n日志信息:%property{LogMessage} %n异常信息:%exception %n%n"/>
</layout>
</appender> <appender name="ADONetAppender" type="log4net.Appender.ADONetAppender">
<bufferSize value="" />
<connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<connectionString value="Data Source=.\sql2014;Initial Catalog=FirstVueAdminDB;Persist Security Info=True;User ID=sa;Password=Aa123456;MultipleActiveResultSets=True;"/>
<commandText value="INSERT INTO OperatorLog(Createdate,CreatedBy,IsDeleted,ModuleName,Origin,Type,LogLevel,LogMessage,Exception,Logger) VALUES(@Createdate,@CreatedBy,@IsDeleted,@ModuleName,@Origin,@Type,@LogLevel,@LogMessage,@Exception,@logger)" />
<parameter>
<parameterName value="@Createdate" />
<dbType value="DateTime" />
<layout type="log4net.Layout.RawTimeStampLayout" />
</parameter>
<parameter>
<parameterName value="@CreatedBy" />
<dbType value="String" />
<size value="" />
<layout type="Log4Net.MyLayout" >
<conversionPattern value = "%property{CreatedBy}"/>
</layout>
</parameter>
<parameter>
<parameterName value="@IsDeleted" />
<dbType value="String" />
<size value="" />
<layout type="Log4Net.MyLayout" >
<conversionPattern value = "%property{IsDeleted}"/>
</layout>
</parameter>
<parameter>
<parameterName value="@ModuleName" />
<dbType value="String" />
<size value="" />
<layout type="Log4Net.MyLayout" >
<conversionPattern value = "%property{ModuleName}"/>
</layout>
</parameter>
<parameter>
<parameterName value="@Origin" />
<dbType value="String" />
<size value="" />
<layout type="Log4Net.MyLayout" >
<conversionPattern value = "%property{Origin}"/>
</layout>
</parameter>
<parameter>
<parameterName value="@Type" />
<dbType value="String" />
<size value="" />
<layout type="Log4Net.MyLayout" >
<conversionPattern value = "%property{Type}"/>
</layout>
</parameter>
<parameter>
<parameterName value="@LogLevel" />
<dbType value="String" />
<size value="" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%p" />
</layout>
</parameter>
<parameter>
<parameterName value="@LogMessage" />
<dbType value="String" />
<size value="" />
<layout type="Log4Net.MyLayout">
<conversionPattern value="%property{LogMessage}" />
</layout>
</parameter>
<parameter>
<parameterName value="@Exception"/>
<dbType value="String"/>
<size value=""/>
<layout type="log4net.Layout.ExceptionLayout"/>
</parameter>
<parameter>
<parameterName value="@logger" />
<dbType value="String" />
<size value="" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%logger" />
</layout>
</parameter>
</appender> <!--log4net.LogManager.GetLogger("logerror")用这个来选择这种类型-->
<!--<logger name="logerror">
<level value="ERROR" />
<appender-ref ref="ErrorAppender" />
</logger>
<logger name="loginfo">
<level value="INFO" />
<appender-ref ref="InfoAppender" />
</logger>
<logger name="logwarn">
<level value="WARN"/>
<appender-ref ref="WarningAppender"/>
</logger>
<logger name="logdebug">
<level value="DEBUG"/>
<appender-ref ref="DebugAppender"/>
</logger>
-->
<!--<logger name="logexceptionless">
<level value="INFO"/>
<appender-ref ref="Exceptionless"/>
</logger>-->
<root>
<!--控制级别,由低到高: ALL|DEBUG|INFO|WARN|ERROR|FATAL|OFF-->
<!--比如定义级别为INFO,则INFO级别向下的级别,比如DEBUG日志将不会被记录-->
<!--如果没有定义LEVEL的值,则缺省为DEBUG-->
<level value="ALL" />
<!--根据log级别记录到不同的日志文件-->
<!--文件形式记录日志-->
<appender-ref ref="InfoAppender"/>
<appender-ref ref="ErrorAppender" />
<appender-ref ref="ADONetAppender" /> </root> </log4net>
log4net 有四种主要的组件,分别是Logger(记录器), Repository(库), Appender(附着器)以及 Layout(布局).
Log4net框架定义了一个ILog接口,所有的logger类都必须实现这个接口。如果你想实现一个自定义的logger,你必须首先实现这个接口。你可以参考在/extension目录下的几个例子。
log4net.Layout.PatternLayout中的转换模式(ConversionPattern)
%m(message):输出的日志消息,如ILog.Debug(…)输出的一条消息
%n(new line):换行
%d(datetime):输出当前语句运行的时刻
%r(run time):输出程序从运行到执行到当前语句时消耗的毫秒数
%t(thread id):当前语句所在的线程ID
%p(priority): 日志的当前优先级别,即DEBUG、INFO、WARN…等
%c(class):当前日志对象的名称,例如:
模式字符串为:%-10c -%m%n
代码为:
ILog log=LogManager.GetLogger(“Exam.Log”);
log.Debug(“Hello”);
则输出为下面的形式:
Exam.Log - Hello
%L:输出语句所在的行号
%F:输出语句所在的文件名
%-数字:表示该项的最小长度,如果不够,则用空格填充
Logger
作用:直接与应用交互的组件,用于触发日志事件
级别(日志事件) 优先级
OFF 6
FATAL 5
ERROR 4
WARN 3
INFO 2
DEBUG 1
ALL 0
其他参考
http://www.cnblogs.com/zhangchenliang/p/4546352.html
http://www.cnblogs.com/RainbowInTheSky/p/5914766.html 自定义记录日志
https://www.cnblogs.com/maijin/p/4618435.html
https://www.cnblogs.com/zhihaospace/p/8419946.html
https://blog.csdn.net/kongwei521/article/details/52242319
https://blog.51cto.com/790381375/1742018
https://www.cnblogs.com/izreo/p/5651139.html