參考了ABP的代碼,我也用依賴注入的原則,設計了日誌模塊。api
與abp不一樣之處在於:1)DI容器使用的是.net core自帶的注入容器,2)集成了excetpionless日誌模塊,3)不依賴於abpapp
主要的思想就是,1)定義日誌操做接口 2)使用log4net實現日誌接口,3)實現注入 4)使用日誌less
1)定義日誌接口,這裏直接使用了castle的日誌接口ide
2)使用log4net實現日誌接口this
[Serializable] public class Log4NetLogger : MarshalByRefObject, ILogger { private static readonly Type DeclaringType = typeof(Log4NetLogger); private log4net.Core.ILogger _logger; private Log4NetLoggerFactory _factory; public Log4NetLogger() { _factory = new Log4NetLoggerFactory(); _logger = _factory.GetLogger("cislog"); } public bool IsDebugEnabled { get { return _logger.IsEnabledFor(Level.Debug); } } public bool IsErrorEnabled { get { return _logger.IsEnabledFor(Level.Error); } } public bool IsFatalEnabled { get { return _logger.IsEnabledFor(Level.Fatal); } } public bool IsInfoEnabled { get { return _logger.IsEnabledFor(Level.Info); } } public bool IsWarnEnabled { get { return _logger.IsEnabledFor(Level.Warn); } } public override string ToString() { return _logger.ToString(); } public void Debug(string message) { if (IsDebugEnabled) { _logger.Log(DeclaringType, Level.Debug, message, null); } } public void Debug(Func<string> messageFactory) { if (IsDebugEnabled) { _logger.Log(DeclaringType, Level.Debug, messageFactory.Invoke(), null); } } public void Debug(string message, Exception exception) { if (IsDebugEnabled) { _logger.Log(DeclaringType, Level.Debug, message, exception); } } public void DebugFormat(string format, params Object[] args) { if (IsDebugEnabled) { _logger.Log(DeclaringType, Level.Debug, new SystemStringFormat(CultureInfo.InvariantCulture, format, args), null); } } public void DebugFormat(Exception exception, string format, params Object[] args) { if (IsDebugEnabled) { _logger.Log(DeclaringType, Level.Debug, new SystemStringFormat(CultureInfo.InvariantCulture, format, args), exception); } } public void DebugFormat(IFormatProvider formatProvider, string format, params Object[] args) { if (IsDebugEnabled) { _logger.Log(DeclaringType, Level.Debug, new SystemStringFormat(formatProvider, format, args), null); } } public void DebugFormat(Exception exception, IFormatProvider formatProvider, string format, params Object[] args) { if (IsDebugEnabled) { _logger.Log(DeclaringType, Level.Debug, new SystemStringFormat(formatProvider, format, args), exception); } } public void Error(string message) { if (IsErrorEnabled) { _logger.Log(DeclaringType, Level.Error, message, null); } } public void Error(Func<string> messageFactory) { if (IsErrorEnabled) { _logger.Log(DeclaringType, Level.Error, messageFactory.Invoke(), null); } } public void Error(string message, Exception exception) { if (IsErrorEnabled) { _logger.Log(DeclaringType, Level.Error, message, exception); } } public void ErrorFormat(string format, params Object[] args) { if (IsErrorEnabled) { _logger.Log(DeclaringType, Level.Error, new SystemStringFormat(CultureInfo.InvariantCulture, format, args), null); } } public void ErrorFormat(Exception exception, string format, params Object[] args) { if (IsErrorEnabled) { _logger.Log(DeclaringType, Level.Error, new SystemStringFormat(CultureInfo.InvariantCulture, format, args), exception); } } public void ErrorFormat(IFormatProvider formatProvider, string format, params Object[] args) { if (IsErrorEnabled) { _logger.Log(DeclaringType, Level.Error, new SystemStringFormat(formatProvider, format, args), null); } } public void ErrorFormat(Exception exception, IFormatProvider formatProvider, string format, params Object[] args) { if (IsErrorEnabled) { _logger.Log(DeclaringType, Level.Error, new SystemStringFormat(formatProvider, format, args), exception); } } public void Fatal(string message) { if (IsFatalEnabled) { _logger.Log(DeclaringType, Level.Fatal, message, null); } } public void Fatal(Func<string> messageFactory) { if (IsFatalEnabled) { _logger.Log(DeclaringType, Level.Fatal, messageFactory.Invoke(), null); } } public void Fatal(string message, Exception exception) { if (IsFatalEnabled) { _logger.Log(DeclaringType, Level.Fatal, message, exception); } } public void FatalFormat(string format, params Object[] args) { if (IsFatalEnabled) { _logger.Log(DeclaringType, Level.Fatal, new SystemStringFormat(CultureInfo.InvariantCulture, format, args), null); } } public void FatalFormat(Exception exception, string format, params Object[] args) { if (IsFatalEnabled) { _logger.Log(DeclaringType, Level.Fatal, new SystemStringFormat(CultureInfo.InvariantCulture, format, args), exception); } } public void FatalFormat(IFormatProvider formatProvider, string format, params Object[] args) { if (IsFatalEnabled) { _logger.Log(DeclaringType, Level.Fatal, new SystemStringFormat(formatProvider, format, args), null); } } public void FatalFormat(Exception exception, IFormatProvider formatProvider, string format, params Object[] args) { if (IsFatalEnabled) { _logger.Log(DeclaringType, Level.Fatal, new SystemStringFormat(formatProvider, format, args), exception); } } public void Info(string message) { if (IsInfoEnabled) { _logger.Log(DeclaringType, Level.Info, message, null); } } public void Info(Func<string> messageFactory) { if (IsInfoEnabled) { _logger.Log(DeclaringType, Level.Info, messageFactory.Invoke(), null); } } public void Info(string message, Exception exception) { if (IsInfoEnabled) { _logger.Log(DeclaringType, Level.Info, message, exception); } } public void InfoFormat(string format, params Object[] args) { if (IsInfoEnabled) { _logger.Log(DeclaringType, Level.Info, new SystemStringFormat(CultureInfo.InvariantCulture, format, args), null); } } public void InfoFormat(Exception exception, string format, params Object[] args) { if (IsInfoEnabled) { _logger.Log(DeclaringType, Level.Info, new SystemStringFormat(CultureInfo.InvariantCulture, format, args), exception); } } public void InfoFormat(IFormatProvider formatProvider, string format, params Object[] args) { if (IsInfoEnabled) { _logger.Log(DeclaringType, Level.Info, new SystemStringFormat(formatProvider, format, args), null); } } public void InfoFormat(Exception exception, IFormatProvider formatProvider, string format, params Object[] args) { if (IsInfoEnabled) { _logger.Log(DeclaringType, Level.Info, new SystemStringFormat(formatProvider, format, args), exception); } } public void Warn(string message) { if (IsWarnEnabled) { _logger.Log(DeclaringType, Level.Warn, message, null); } } public void Warn(Func<string> messageFactory) { if (IsWarnEnabled) { _logger.Log(DeclaringType, Level.Warn, messageFactory.Invoke(), null); } } public void Warn(string message, Exception exception) { if (IsWarnEnabled) { _logger.Log(DeclaringType, Level.Warn, message, exception); } } public void WarnFormat(string format, params Object[] args) { if (IsWarnEnabled) { _logger.Log(DeclaringType, Level.Warn, new SystemStringFormat(CultureInfo.InvariantCulture, format, args), null); } } public void WarnFormat(Exception exception, string format, params Object[] args) { if (IsWarnEnabled) { _logger.Log(DeclaringType, Level.Warn, new SystemStringFormat(CultureInfo.InvariantCulture, format, args), exception); } } public void WarnFormat(IFormatProvider formatProvider, string format, params Object[] args) { if (IsWarnEnabled) { _logger.Log(DeclaringType, Level.Warn, new SystemStringFormat(formatProvider, format, args), null); } } public void WarnFormat(Exception exception, IFormatProvider formatProvider, string format, params Object[] args) { if (IsWarnEnabled) { _logger.Log(DeclaringType, Level.Warn, new SystemStringFormat(formatProvider, format, args), exception); } } public ILogger CreateChildLogger(string loggerName) { throw new NotImplementedException(); } }
public class Log4NetLoggerFactory : AbstractLoggerFactory { internal const string DefaultConfigFileName = "log4net.config"; private readonly ILoggerRepository _loggerRepository; public Log4NetLoggerFactory() : this(DefaultConfigFileName) { } public Log4NetLoggerFactory(string configFileName) { _loggerRepository = LogManager.CreateRepository( typeof(Log4NetLoggerFactory).GetAssembly(), typeof(log4net.Repository.Hierarchy.Hierarchy) ); XmlConfigurator.Configure(_loggerRepository, new FileInfo("log4net.config")); } public log4net.Core.ILogger GetLogger(string name) { return LogManager.GetLogger(_loggerRepository.Name, name).Logger; } public override ILogger Create(string name) { if (name == null) { throw new ArgumentNullException(nameof(name)); } return new Log4NetLogger(); } public override ILogger Create(string name, LoggerLevel level) { throw new NotSupportedException("Logger levels cannot be set at runtime. Please review your configuration file."); } } public static class TypeExtensions { public static Assembly GetAssembly(this Type type) { return type.GetTypeInfo().Assembly; } }
下面是擴展方法,這裏實現注入:url
public static class Log4NetLoggerExtensions { public static IServiceCollection UseExceptionless(this IServiceCollection services) { services.AddTransient<ILogger, Log4NetLogger>(); return services; } }
而後就能夠在startup中使用了spa
public void ConfigureServices(IServiceCollection services) { services.AddMvc(); services.UseExceptionless(); }
好比咱們在HomeController中使用:.net
public class HomeController : Controller { private ILogger _logger; public HomeController(ILogger logger) { _logger = logger; } public IActionResult Index() { // throw new Exception("快點來!!!!!!!!!!!!!!!!!!"); _logger.Info("index view"); _logger.Debug("出錯了!,快點來,!!"); _logger.Error("Controller Error"); return View(); } }
最後是配置文件:設計
最重要的是注意exceptionless的配置日誌
<?xml version="1.0" encoding="utf-8" ?> <configuration> <!-- This section contains the log4net configuration settings --> <log4net> <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender"> <layout type="log4net.Layout.PatternLayout" value="%date [%thread] %-5level %logger - %message%newline" /> </appender> <appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender"> <file value="Logs/" /> <appendToFile value="true" /> <rollingStyle value="Composite" /> <staticLogFileName value="false" /> <datePattern value="yyyy-MM-dd'.log'" /> <maxSizeRollBackups value="10" /> <maximumFileSize value="1MB" /> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" /> </layout> </appender> <appender name="Exceptionless" type="Exceptionless.Log4net.ExceptionlessAppender,Exceptionless.Log4net"> <apiKey value="d5qna1t9qTUVwrRzLFz1T3z8wSUeO3xNtxOGMHLf" /> <serverUrl value="http://10.117.130.150:9001" /> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%-4timestamp [%thread] %-5level %logger %ndc - %message%newline"/> </layout> </appender> <!-- Setup the root category, add the appenders and set the default level --> <root> <level value="ALL" /> <appender-ref ref="ConsoleAppender" /> <appender-ref ref="RollingLogFileAppender" /> <appender-ref ref="Exceptionless"/> </root> </log4net> </configuration>
還有一點很是重要,記得引用,不然在exceptionless中也看不到日誌
效果如圖:
最後,提一點:
如今容器技術很火,若是把這套代碼放在容器中運行確定是不行,由於在配置文件中配置了apikey和url, 因此要稍作修改以下:
添加一個類:
public class ExceptionlessOption { /// <summary> /// 日誌應用標識,從Exceptionless面板獲取 /// </summary> public string ApiKey { get; set; } /// <summary> /// 日誌應用接口地址 /// </summary> public string Url { get; set; } }
services.AddMvc(); services.UseExceptionless(() => { return new ExceptionlessOption { ApiKey = "234na1t9qTU234234234z8wSUeO3x234234HLf", Url = "http://100.11.13.10:9001" }; });
public Log4NetLoggerFactory(ExceptionlessOption _option, string configFileName) { _loggerRepository = LogManager.CreateRepository( typeof(Log4NetLoggerFactory).GetAssembly(), typeof(log4net.Repository.Hierarchy.Hierarchy) ); //讀取配置 XmlConfigurator.Configure(_loggerRepository, new FileInfo("log4net.config")); //TODO這裏修改 ExceptionlessClient.Default.Configuration.ApiKey = _option.ApiKey ?? "d5qna1t9qTUVwrRzLFz1T3z8wSUeO3xNtxOGMHLf"; ExceptionlessClient.Default.Configuration.ServerUrl = _option.Url ?? "http://10.117.130.150:9001"; }
而後你就能夠在startup中經過讀取配置文件,實現參數的傳入了。