前言
有可能目标计算机缺少某些组件,导致无法生成access文件,或者打不开文件,这时txt文件就可以方便的使用了
一,标准的控制台程序输出日志到access
<?xml version="1.0" encoding="utf-8" ?> <log4net xmlns="urn:log4net"> <root xmlns=""> <level value="ALL" /> <appender-ref ref="AdoNetAppender_Access" /> </root> <appender xmlns="" name="AdoNetAppender_Access" type="log4net.Appender.AdoNetAppender"> <connectionString value="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=loglog.mdb" /> <commandText value="INSERT INTO Table1([LogDate],[Thread],[logLevel],[Logger],[Message]) VALUES(@logDate, @thread, @logLevel,@logger,@message)" /> <!--BufferSize为缓冲区大小,只有日志记录超10条才会一块写入到数据库--> <bufferSize value="10"/> <!--定义各个参数--> <parameter> <parameterName value="@logDate" /> <dbType value="String" /> <size value="240" /> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%date" /> </layout> </parameter> <parameter> <parameterName value="@thread"/> <dbType value="String" /> <size value="240" /> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%thread" /> </layout> </parameter> <parameter> <parameterName value="@logLevel" /> <dbType value="String" /> <size value="240" /> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%level" /> </layout> </parameter> <parameter> <parameterName value="@logger" /> <dbType value="String" /> <size value="240" /> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%logger" /> </layout> </parameter> <parameter> <parameterName value="@message" /> <dbType value="String" /> <size value="240" /> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%message" /> </layout> </parameter> </appender> </log4net>
注意:(1)文件属性设置为:如果较新则复制
(2)connectionString设置里面的文件路径。绝对路径
(3)在AssemblyInfo.cs文件里添加
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "Access.config", Watch = true)]
(4)在ConnectionString里面对应的路径中,创建log4net.mdb数据库,并创建表
CREATE TABLE [LogDetails] ( ID AutoIncrement, [logDate] longText, [Thread] longText, [logLevel] longText, [Logger] longText, [Message] longText, Primary Key (ID) )
(5)添加代码
log4net.ILog log = log4net.LogManager.GetLogger(typeof(Program)); Random random = new Random(); for (int i = 0; i < 2; i++) { //记录错误日志 if (log.IsErrorEnabled) log.Debug("你引起了一个错误,错误ID为:" + random.Next().ToString()); //记录严重错误 if (log.IsFatalEnabled) log.Fatal("你引发了一个终结者错误,可能导致系统终止,ID为:" + random.Next().ToString()); //记录一般信息 if (log.IsInfoEnabled) log.Info("你计划记录一个信息,id为:" + random.Next().ToString()); //记录调试信息 if (log.IsDebugEnabled) log.Debug("调试信息,调试ID为:" + random.Next().ToString()); //记录警告信息 if (log.IsWarnEnabled) { log.Warn("警告:警告ID为:" + random.Next().ToString()); } }
注意:在64位的Windows7系统调试时,如果office是32位将你的应用程序将原有的AnyCPU更改为CPU x86.
如果是64位,安装64位的Jet40驱动
否则会报错:未在本地计算机上注册“Microsoft.Jet.OLEDB.4.0”提供程序。
其它数据库,基本和Access类似,只是在连接字符串和,插入部分有所不同。
二、通过代码控制
1、引入log4net.dll
2、添加配置文件 myLog4net.config
<?xml version="1.0"?> <configuration> <configSections> <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/> </configSections> <log4net> <appender name="AllRollingLogFileAppender" type="log4net.Appender.RollingFileAppender"> <param name="File" value="Log"/> <!--按照何种方式产生多个日志文件(日期[Date],文件大小[Size],混合[Composite])--> <param name= "RollingStyle" value= "Composite"/> <!--按日期产生文件夹和文件名[在日期方式与混合方式下使用]--> <param name= "DatePattern" value= "yyyy-MM-dd\yyyy-MM-dd"log.txt""/> <!--是否追加到文件--> <param name= "AppendToFile" value= "false"/> <!--最多产生的日志文件数,超过则只保留最新的n个。设定值value="-1"为不限文件数--> <param name= "MaxSizeRollBackups" value= "1"/> <!--是否只写到一个文件中--> <param name= "StaticLogFileName" value= "false"/> <!--每个文件的大小。只在混合方式与文件大小方式下使用。 超出大小后在所有文件名后自动增加正整数重新命名,数字最大的最早写入。 可用的单位:KB|MB|GB。不要使用小数,否则会一直写入当前日志--> <param name= "maximumFileSize" value="50MB"/> <layout type="logDemo.ReflectionLayout"> <param name="ConversionPattern" value="[%-5level] [%date] [%property{Function}:%property{Line}] message:%property{Message} %newline" /> </layout> <filter type="log4net.Filter.LevelRangeFilter"> <param name="LevelMin" value="Debug" /> <param name="LevelMax" value="Fatal" /> </filter> </appender> <appender name="ColoredConsoleAppender" type="log4net.Appender.ColoredConsoleAppender"> <mapping> <level value="ERROR" /> <foreColor value="Red, HighIntensity" /> </mapping> <mapping> <level value="Info" /> <foreColor value="Green" /> </mapping> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%n%date{HH:mm:ss,fff} [%-5level] %m" /> </layout> <filter type="log4net.Filter.LevelRangeFilter"> <param name="LevelMin" value="Info" /> <param name="LevelMax" value="Fatal" /> </filter> <filter type="log4net.Filter.DenyAllFilter" /> </appender> <!--定义输出到数据库中,这里举例输出到Access数据库中,数据库为C盘的log4net.mdb--> <appender name="AdoNetAppender_Access" type="log4net.Appender.AdoNetAppender"> <!--连接数据库字符串--> <connectionString value="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=access\Log.mdb" /> <!--插入到表Log--> <commandText value="INSERT INTO LogDetails ( LogDate, Thread, LogLevel, File, Function, Line, Message, MainModule, SubModule, CustomModule1, CustomModule2) VALUES ( @logDate, @thread, @logLevel, @file, @function, @line, @message, @mainModule, @subModule, @customModule1, @customModule2)" /> <!--BufferSize为缓冲区大小,只有日志记录超设定值才会一块写入到数据库--> <bufferSize value="1" /> <!--定义各个参数--> <parameter> <parameterName value="@logDate" /> <dbType value="String" /> <size value="32" /> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%date" /> </layout> </parameter> <parameter> <parameterName value="@thread" /> <dbType value="String" /> <size value="16" /> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%thread" /> </layout> </parameter> <parameter> <parameterName value="@logLevel" /> <dbType value="String" /> <size value="8" /> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%level" /> </layout> </parameter> <parameter> <parameterName value="@file" /> <dbType value="String" /> <size value="128" /> <layout type="logDemo.ReflectionLayout"> <conversionPattern value="%property{File}" /> </layout> </parameter> <parameter> <parameterName value="@function" /> <dbType value="String" /> <size value="128" /> <layout type="logDemo.ReflectionLayout"> <conversionPattern value="%property{Function}" /> </layout> </parameter> <parameter> <parameterName value="@line" /> <dbType value="String" /> <size value="8" /> <layout type="logDemo.ReflectionLayout"> <conversionPattern value="%property{Line}" /> </layout> </parameter> <parameter> <parameterName value="@message" /> <dbType value="String" /> <size value="255" /> <layout type="logDemo.ReflectionLayout"> <conversionPattern value="%property{Message}" /> </layout> </parameter> <parameter> <parameterName value="@mainModule" /> <dbType value="String" /> <size value="32" /> <layout type="logDemo.ReflectionLayout"> <conversionPattern value="%property{MainModule}" /> </layout> </parameter> <parameter> <parameterName value="@subModule" /> <dbType value="String" /> <size value="32" /> <layout type="logDemo.ReflectionLayout"> <conversionPattern value="%property{SubModule}" /> </layout> </parameter> <parameter> <parameterName value="@customModule1" /> <dbType value="String" /> <size value="255" /> <layout type="logDemo.ReflectionLayout"> <conversionPattern value="%property{CustomModule1}" /> </layout> </parameter> <parameter> <parameterName value="@customModule2" /> <dbType value="String" /> <size value="32" /> <layout type="logDemo.ReflectionLayout"> <conversionPattern value="%property{CustomModule2}" /> </layout> </parameter> <filter type="log4net.Filter.LevelRangeFilter"> <param name="LevelMin" value="Debug" /> <param name="LevelMax" value="Fatal" /> <filter type="log4net.Filter.DenyAllFilter" /> </filter> </appender> <root> <level value="all" /> <appender-ref ref="ColoredConsoleAppender"/> <appender-ref ref="AllRollingLogFileAppender"/> <appender-ref ref="AdoNetAppender_Access"/> </root> </log4net> </configuration>
3、代码引用
①通过重写布局Layout输出传入的 message对象的属性 ReflectionLayout.cs
using log4net.Layout; using log4net.Layout.Pattern; using System.Reflection; namespace logDemo { // 通过重写布局Layout输出传入的 message对象的属性 // 通过继承log4net.Layout.PatternLayout类,使用log4net.Core.LoggingEvent类的方法得到了要输出的message类的名称,然后通过反射得到各个属性的值,使用PatternLayout类AddConverter方法传入得到的值。 public class ReflectionLayout : PatternLayout { public ReflectionLayout() { this.AddConverter("property", typeof(ReflectionPatternConverter)); } public ReflectionLayout(string pattern) : this() { base.ConversionPattern = pattern; } } public class ReflectionPatternConverter : 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()); } } /// <summary> /// 通过反射获取传入的日志对象的某个属性的值 /// </summary> /// <param name="property"></param> /// <returns></returns> 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; } } }
②自定义输出多列的类 LogModule.cs
namespace logDemo { public class LogModule { /// <summary> /// 无参构造函数 /// </summary> public LogModule() { } /// <summary> /// logModule构造方法 /// </summary> /// <param name="dutModule"></param> /// <param name="message"></param> /// <param name="mainModule"></param> /// <param name="subModule"></param> /// <param name="customModule1"></param> /// <param name="customModule2"></param> /// <param name="file"></param> /// <param name="function"></param> /// <param name="line"></param> public LogModule(string mainModule = "", string subModule = "", string customModule1 = "", string customModule2 = "", string file = "", string function = "", string line = "", string message = "") { this.MainModule = mainModule; this.SubModule = subModule; this.CustomModule1 = customModule1; this.CustomModule2 = customModule2; this.File = file; this.Function = function; this.Line = line; this.Message = message; } private string mainModule = ""; /// <summary> /// 场景模块信息 /// </summary> public string MainModule { get { return mainModule; } set { mainModule = value; } } private string subModule = ""; /// <summary> /// 子场景模块 /// </summary> public string SubModule { get { return subModule; } set { subModule = value; } } private string customModule1 = ""; /// <summary> /// 自定义1模块 /// </summary> public string CustomModule1 { get { return customModule1; } set { customModule1 = value; } } private string customModule2 = ""; /// <summary> /// 自定义2模块 /// </summary> public string CustomModule2 { get { return customModule2; } set { customModule2 = value; } } private string file = ""; /// <summary> /// 文件名(类名) /// </summary> public string File { get { return file; } set { file = value; } } private string function = ""; /// <summary> /// 方法名 /// </summary> public string Function { get { return function; } set { function = value; } } private string line = ""; /// <summary> /// 行号 /// </summary> public string Line { get { return line; } set { line = value; } } private string message = ""; /// <summary> /// 信息,主要收集需要收集的log信息(log内容) /// </summary> public string Message { get { return message; } set { message = value; } } } }
③添加类 LogHelper.cs
using System; using log4net; using System.IO; using log4net.Core; namespace logDemo { public class LogHelper { //如果定义了<logger>节点,则这里传入logger的name的值 log4net.ILog log = log4net.LogManager.GetLogger("logName"); protected log4net.ILog Log { get { return log; } set { log = value; } } LogModule module; /// <summary> /// 带入log模块信息 /// </summary> /// <param name="module"></param> public LogHelper(LogModule module) { this.module = module; } /// <summary> /// 打印log发送到log4ent /// </summary> /// <param name="level">等级</param> /// <param name="msg">log信息</param> public void Print(Levels level, String msg) { module.Message = msg; module.File = new System.Diagnostics.StackTrace(true).GetFrame(1).GetFileName(); module.Function = new System.Diagnostics.StackTrace(true).GetFrame(1).GetMethod().ToString(); module.Line = new System.Diagnostics.StackTrace(true).GetFrame(1).GetFileLineNumber().ToString(); Print(level, module); } /// <summary> /// log信息发送到log4net进行打印 /// </summary> /// <param name="level">等级</param> /// <param name="module">log模块</param> private void Print(Levels level, LogModule module) { if (module == null) return; if (level.Equals(Levels.FATAL)) Log.Fatal(module); if (level.Equals(Levels.ERROR)) Log.Error(module); if (level.Equals(Levels.DEBUG)) Log.Debug(module); if (level.Equals(Levels.WARN)) Log.Warn(module); if (level.Equals(Levels.INFO)) Log.Info(module); } } /// <summary> /// 自定义log等级 /// </summary> public enum Levels { OFF = 0, FATAL, ERROR, WARN, INFO, DEBUG } }
④用自定义的列输出日志
using System; using System.Windows.Forms; using System.IO; using ADOX; namespace logDemo { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { //如果没有数据库则创建一个 CreateAcces(Path.Combine(Application.StartupPath, "access")); //监听配置文件的变化 log4net.Config.XmlConfigurator.ConfigureAndWatch(new FileInfo(Path.Combine(Application.StartupPath, "myLog4net.config"))); } public static LogHelper newlog; private void button1_Click(object sender, EventArgs e) { LogModule module1 = new LogModule("main信息", "sub信息", "自定义1", "自定义2"); newlog = new LogHelper(module1); newlog.Print(Levels.FATAL, "fatal级别的message"); LogModule module2 = new LogModule(); module2.MainModule = "mianModule"; module2.SubModule = "SubModule"; module2.CustomModule1 = "CustomModule1"; newlog = new LogHelper(module2); newlog.Print(Levels.DEBUG, "debug级别的message"); } /// <summary> /// access操作类 /// </summary> /// <param name="accessDirectoryPath"></param> public static void CreateAcces(string accessDirectoryPath) { // 目录不存在 则创建目录 string temppath = accessDirectoryPath; if (!Directory.Exists(temppath)) { Directory.CreateDirectory(temppath); } string mdbPath = Path.Combine(accessDirectoryPath, "Log.mdb"); if (File.Exists(mdbPath)) //检查数据库是否已存在 { return; } // 数据库不存在 则创建数据库 (可以加上密码,这样创建后的数据库必须输入密码后才能打开) mdbPath = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + mdbPath; // 创建一个CatalogClass对象的实例, ADOX.CatalogClass cat = new ADOX.CatalogClass(); // 使用CatalogClass对象的Create方法创建ACCESS数据库 cat.Create(mdbPath); // 连接数据库 ADODB.Connection conn = new ADODB.Connection(); conn.Open(mdbPath, null, null, -1); cat.ActiveConnection = conn; // 创建一个自动增长的主键列 Column col = new Column(); col.ParentCatalog = cat; col.Type = DataTypeEnum.adInteger; col.Name = "ID"; col.DefinedSize = 9; col.Properties["AutoIncrement"].Value = true; // 创建表 Table table = new Table(); table.Name = "LogDetails"; table.Columns.Append(col, DataTypeEnum.adInteger, 9); table.Keys.Append("FirstPrimaryKey", KeyTypeEnum.adKeyPrimary, col, null, null); // 表中添加自定义列 table.Columns.Append("LogDate", DataTypeEnum.adVarWChar, 32); table.Columns.Append("Thread", DataTypeEnum.adVarWChar, 16); table.Columns.Append("LogLevel", DataTypeEnum.adVarWChar, 8); table.Columns.Append("File", DataTypeEnum.adVarWChar, 128); table.Columns.Append("Function", DataTypeEnum.adVarWChar, 128); table.Columns.Append("Line", DataTypeEnum.adVarWChar, 8); table.Columns.Append("Message", DataTypeEnum.adVarWChar, 255); table.Columns.Append("MainModule", DataTypeEnum.adVarWChar, 32); table.Columns.Append("SubModule", DataTypeEnum.adVarWChar, 32); table.Columns.Append("CustomModule1", DataTypeEnum.adVarWChar, 255); table.Columns.Append("CustomModule2", DataTypeEnum.adVarWChar, 32); cat.Tables.Append(table); //创建数据库后关闭连接 System.Runtime.InteropServices.Marshal.FinalReleaseComObject(cat.ActiveConnection); System.Runtime.InteropServices.Marshal.FinalReleaseComObject(cat); } } }
⑤输出结果,以txt和access两种形式保存
DebugLog2018-07-052018-07-05log.txt
Debugaccesslog.mdb
参考