之前寫過文章利用.net 及Java 寫紀錄, 現在則會示範在.net Core 中利用log4net 進行記錄.
- 安裝log4net.
在Package Management Console 中, 輸入以下指令.Install-Package log4net
- 設定log4net.
建立XML 檔, 命名為log4net.config, 並輸入以下設定.<?xml version="1.0" encoding="utf-8" ?> <configuration> <log4net> <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender"> <file value="C:\log\log4net" /> <appendToFile value="true" /> <rollingStyle value="Composite" /> <datePattern value="_yyyy-MM-dd.lo\g" /> <maximumFileSize value="5MB" /> <maxSizeRollBackups value="15" /> <staticLogFileName value="false" /> <PreserveLogFileNameExtension value="true" /> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%date [%thread] %level %logger - %message%newline" /> </layout> </appender> <root> <appender-ref ref="RollingFileAppender" /> </root> </log4net> </configuration>
- 建立Logger
因為Log4net 本身沒有implement ILogger, 加上雙方的log level 不同, 因此需要自行處理.
建立class file 並命名為log4netLogger.cs, 並輸入以下代碼.public class Log4netLogger : ILogger { private readonly ILog _log; public Log4netLogger(string name, FileInfo fileInfo) { var repository = LogManager.CreateRepository( Assembly.GetEntryAssembly(), typeof(log4net.Repository.Hierarchy.Hierarchy) ); XmlConfigurator.Configure(repository, fileInfo); _log = LogManager.GetLogger(repository.Name, name); } public IDisposable BeginScope<TState>(TState state) { return null; } public bool IsEnabled(LogLevel logLevel) { switch (logLevel) { case LogLevel.Critical: return _log.IsFatalEnabled; case LogLevel.Debug: case LogLevel.Trace: return _log.IsDebugEnabled; case LogLevel.Error: return _log.IsErrorEnabled; case LogLevel.Information: return _log.IsInfoEnabled; case LogLevel.Warning: return _log.IsWarnEnabled; default: throw new ArgumentOutOfRangeException(nameof(logLevel)); } } public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter) { if (!IsEnabled(logLevel)) { return; } if (formatter == null) { throw new ArgumentNullException(nameof(formatter)); } string message = null; if (null != formatter) { message = formatter(state, exception); } if (!string.IsNullOrEmpty(message) || exception != null) { switch (logLevel) { case LogLevel.Critical: _log.Fatal(message); break; case LogLevel.Debug: case LogLevel.Trace: _log.Debug(message); break; case LogLevel.Error: _log.Error(message); break; case LogLevel.Information: _log.Info(message); break; case LogLevel.Warning: _log.Warn(message); break; default: _log.Warn($"Unknown log level {logLevel}.\r\n{message}"); break; } } } }
- 建立Provider.
因為在.net core 中, ILogger 是透過Factory Pattern 產生, 而其factory 是ILoggerProvider, 所以須要implement 它.
建立class file 並命名為Log4netProvider.cs, 並輸入以下代碼.public class Log4netProvider : ILoggerProvider { private readonly FileInfo _fileInfo; public Log4netProvider(string log4netConfigFile) { _fileInfo = new FileInfo(log4netConfigFile); } public ILogger CreateLogger(string name) { return new Log4netLogger(name, _fileInfo); } public void Dispose() { } }
- 加入logger 到Webhost 中.
在program.cs 中修改CreateWebHostBuilder method chain 如下.public static IWebHostBuilder CreateWebHostBuilder(string[] args) => WebHost.CreateDefaultBuilder(args) .ConfigureLogging(logging=> { logging.AddProvider(new Log4netProvider(@"log4net.config")); }) .ConfigureAppConfiguration((builderContext, config) => { config.AddEnvironmentVariables(); }) .UseStartup<Startup>();
- 測試.
按F5 執行程式, 當見到有記錄檔產生及資料寫入, 代表測試成功.
雖然log4net 可以透過database 儲存, 但現在其AdoNetAppender仍未支援.net Core, 所以並沒有用作實戰使用. 但仍將建立紀錄留記, 示範中會利用SQL server 存儲記錄.
- 建立Table.
於SQL Server Management Studio 中執行以下指令.CREATE TABLE [dbo].[Log]( [Id] [bigint] IDENTITY(1,1) NOT NULL, [Date] [datetime2] NOT NULL, [Thread] [varchar](255) NOT NULL, [Level] [varchar](50) NOT NULL, [Logger] [varchar](255) NOT NULL, [Message] [varchar](max) NOT NULL, [Exception] [varchar](max) NULL ) ON [PRIMARY] GO
- 加入AdoNetAppender.
修改log4net.config, 並加入以下設定.<?xml version="1.0" encoding="utf-8" ?> <configuration> <log4net> <appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender"> <bufferSize value="1" /> <connectionType value="System.Data.SqlClient.SqlConnection,System.Data,Version=4.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089" /> <connectionString value="<<Connection String Here>>" /> <commandText value="INSERT INTO Log ([Date],[Thread],[Level],[Logger],[Message],[Exception]) VALUES (@log_date, @thread, @log_level, @logger, @message, @exception)" /> <parameter> <parameterName value="@log_date" /> <dbType value="DateTime" /> <layout type="log4net.Layout.RawTimeStampLayout" /> </parameter> <parameter> <parameterName value="@thread" /> <dbType value="String" /> <size value="255" /> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%thread" /> </layout> </parameter> <parameter> <parameterName value="@log_level" /> <dbType value="String" /> <size value="50" /> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%level" /> </layout> </parameter> <parameter> <parameterName value="@logger" /> <dbType value="String" /> <size value="255" /> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%logger" /> </layout> </parameter> <parameter> <parameterName value="@message" /> <dbType value="String" /> <size value="4000" /> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%message" /> </layout> </parameter> <parameter> <parameterName value="@exception" /> <dbType value="String" /> <size value="2000" /> <layout type="log4net.Layout.ExceptionLayout" /> </parameter> </appender> <root> <appender-ref ref="AdoNetAppender" /> </root> </log4net> </configuration>
Leave a Reply