说明一下:本文基于随visual studio 2015 RC公开的DNX1.0.0-beta4,git上最新的aspnet的开发版本已经发生了很大变化。
首先,理论部分看[汤姆大叔的博客] 解读ASP.NET 5 & MVC6系列(9):日志框架
实际上aspnet的开发人员已经在最近版的系统里开始集成nlog了。 本文的目的主要帮助大家理解aspnet mvc 6的框架。
新建工程 "NlogTest"
选“asp.net 5”的”web site”, 然后不要认证模块,我们主要演示NLog的用法,对auth认证没兴趣。
◎添加Nlog参照
打开project.json, 添加 NLog,同时删除dnxcore50,Nlog还没有支持coreclr,所以先删了。
修改frameworks部分,修改后的样子。
"frameworks": { "dnx451": { "dependencies": { "NLog": "3.2.0" } } },
◎添加nlog的配置到config.json里,5行以下为本次追加内容。
1 { 2 "AppSettings": { 3 "SiteTitle": "NLogTest" 4 }, 5 "nlog": { 6 "targets": { 7 "file": { 8 "type": "File", 9 "layout": "${date:format=HH\:MM\:ss} ${logger} ${message}", 10 "fileName": "c:\work\aaa.txt" 11 }, 12 "file2": { 13 "type": "File", 14 "fileName": "c:\work\bbb.txt" 15 } 16 "mail1": { 17 18 } 19 }, 20 "rules": { 21 "rule1": { 22 "minlevel": "Debug", 23 "writeTo": "file" 24 }, 25 "rule2": { 26 "name": "*", 27 "minlevel": "Info", 28 "writeTo": "file2" 29 } 30 } 31 } 32 }
配置到此为止,下面开始编程。
◎添加一个NLogProvider类, 实现ILoggerProvider并在其内部实现ILogger
先上代码,我是微软的实现中搬过来的,做了一些修改。
1 using Microsoft.Framework.Logging; 2 using System; 3 4 namespace NLogTest 5 { 6 public class NLogProvider:ILoggerProvider 7 { 8 private readonly global::NLog.LogFactory _logFactory; 9 10 public NLogProvider(global::NLog.LogFactory logFactory) 11 { 12 _logFactory = logFactory; 13 } 14 15 public ILogger CreateLogger(string name) 16 { 17 return new Logger(_logFactory.GetLogger(name)); 18 } 19 20 private class Logger : ILogger 21 { 22 private readonly global::NLog.Logger _logger; 23 24 public Logger(global::NLog.Logger logger) 25 { 26 _logger = logger; 27 } 28 29 public IDisposable BeginScope(object state) 30 { 31 return global::NLog.NestedDiagnosticsContext.Push(state.ToString()); 32 } 33 34 public bool IsEnabled(LogLevel logLevel) 35 { 36 return _logger.IsEnabled(GetLogLevel(logLevel)); 37 } 38 39 public void Log(LogLevel logLevel, int eventId, object state, Exception exception, Func<object, Exception, string> formatter) 40 { 41 var nLogLogLevel = GetLogLevel(logLevel); 42 var message = string.Empty; 43 if (formatter != null) 44 { 45 message = formatter(state, exception); 46 } 47 else 48 { 49 message = LogFormatter.Formatter(state, exception); 50 } 51 52 if (!string.IsNullOrEmpty(message)) 53 { 54 var eventInfo = global::NLog.LogEventInfo.Create(nLogLogLevel, _logger.Name, message); 55 eventInfo.Properties["EventId"] = eventId; 56 _logger.Log(eventInfo); 57 } 58 } 59 60 private global::NLog.LogLevel GetLogLevel(LogLevel logLevel) 61 { 62 switch (logLevel) 63 { 64 case LogLevel.Verbose: return global::NLog.LogLevel.Debug; 65 case LogLevel.Information: return global::NLog.LogLevel.Info; 66 case LogLevel.Warning: return global::NLog.LogLevel.Warn; 67 case LogLevel.Error: return global::NLog.LogLevel.Error; 68 case LogLevel.Critical: return global::NLog.LogLevel.Fatal; 69 } 70 return global::NLog.LogLevel.Debug; 71 } 72 } 73 } 74 }
代码很简单,就是在微软的日志框架和NLog的函数间实现一个桥接。
◎添加一个NLogLoggerFactoryExtensions类,追加ILoggerFactory的扩张函数,这里是本次演示的重点了。
using Microsoft.Framework.ConfigurationModel; using Microsoft.Framework.Logging; using System; using System.Linq; using System.Text; namespace NLogTest { public static class NLogLoggerFactoryExtensions { public static ILoggerFactory AddNLog( this ILoggerFactory factory, IConfiguration configuration) { var config = new global::NLog.Config.LoggingConfiguration(); var targets = configuration.GetSubKey("targets"); foreach (var item in targets.GetSubKeys()) { AddTargets(config, item.Key, item.Value); } var rules = configuration.GetSubKey("rules"); foreach (var item in rules.GetSubKeys()) { AddLoggingRule(config, item.Value); } factory.AddProvider(new NLogProvider(new global::NLog.LogFactory(config))); return factory; } private static void AddTargets(global::NLog.Config.LoggingConfiguration configuration, string targetName, IConfiguration targetConf) { string targetType = ""; if (targetConf.TryGet("type", out targetType)) { switch (targetType.ToLower()) { case "file": configuration.AddTarget(targetName, GenFileTarget(targetName, targetConf)); break; case "mail": configuration.AddTarget(targetName, GenMailTarget(targetName, targetConf)); break; default: break; } } } private static global::NLog.Targets.Target GenFileTarget(string targetName, IConfiguration targetConf) { var fileTarget = new global::NLog.Targets.FileTarget(); fileTarget.Name = targetName; string confVal = GetVal(targetConf, "fileName"); if (string.IsNullOrEmpty(confVal)) { //Filename is not setting , throw exception! throw new ArgumentNullException("fileTarget's filename is empty."); } fileTarget.FileName = confVal; confVal = GetVal(targetConf, "layout"); if (!string.IsNullOrEmpty(confVal)) { fileTarget.Layout = confVal; } confVal = GetVal(targetConf, "keepfileopen"); if (!string.IsNullOrEmpty(confVal)) { fileTarget.KeepFileOpen = (confVal.ToLower() == "true"); } confVal = GetVal(targetConf, "encoding"); if (!string.IsNullOrEmpty(confVal)) { fileTarget.Encoding = Encoding.GetEncoding(confVal); } fileTarget.AutoFlush = true; return fileTarget; } private static global::NLog.Targets.Target GenMailTarget(string targetName, IConfiguration targetConf) { var mailTarget = new global::NLog.Targets.MailTarget(); mailTarget.Name = targetName; string confVal = GetVal(targetConf, "to"); if (string.IsNullOrEmpty(confVal)) { //to is not setting , throw exception! throw new ArgumentNullException("mailTarget's [to] is empty."); } mailTarget.To = confVal; confVal = GetVal(targetConf, "from"); if (string.IsNullOrEmpty(confVal)) { //to is not setting , throw exception! throw new ArgumentNullException("mailTarget's [from] is empty."); } mailTarget.From = confVal; confVal = GetVal(targetConf, "layout"); if (!string.IsNullOrEmpty(confVal)) { mailTarget.Layout = confVal; } confVal = GetVal(targetConf, "subject"); if (!string.IsNullOrEmpty(confVal)) { mailTarget.Subject = confVal; } confVal = GetVal(targetConf, "smtpusername"); if (!string.IsNullOrEmpty(confVal)) { mailTarget.SmtpUserName = confVal; } confVal = GetVal(targetConf, "smtppassword"); if (!string.IsNullOrEmpty(confVal)) { mailTarget.SmtpPassword = confVal; } confVal = GetVal(targetConf, "smtpserver"); if (!string.IsNullOrEmpty(confVal)) { mailTarget.SmtpServer = confVal; } confVal = GetVal(targetConf, "smtpport"); if (!string.IsNullOrEmpty(confVal)) { int nPort = 25; if (int.TryParse(confVal, out nPort)) { mailTarget.SmtpPort = nPort; } } return mailTarget; } private static void AddLoggingRule(global::NLog.Config.LoggingConfiguration configuration, IConfiguration ruleConf) { string namePattern = "*"; string confVal = GetVal(ruleConf, " name"); if (!string.IsNullOrEmpty(confVal)) { namePattern = confVal; } confVal = GetVal(ruleConf, "minlevel"); global::NLog.LogLevel minLevel = global::NLog.LogLevel.Debug; if (!string.IsNullOrEmpty(confVal)) { minLevel = GetLogLevel(confVal, global::NLog.LogLevel.Trace); } confVal = GetVal(ruleConf, "writeto"); global::NLog.Targets.Target target = null; if (!string.IsNullOrEmpty(confVal)) { target = configuration.ConfiguredNamedTargets.Where(t => t.Name == confVal).FirstOrDefault(); } if (target != null) { configuration.LoggingRules.Add(new global::NLog.Config.LoggingRule(namePattern, minLevel, target)); } } private static string GetVal(IConfiguration configuration, string key) { string val = ""; if (configuration.TryGet(key, out val)) { return val; } else { return null; } } private static global::NLog.LogLevel GetLogLevel(string logLevel, global::NLog.LogLevel defaultLevel = null) { switch (logLevel.ToLower()) { case "debug": return global::NLog.LogLevel.Debug; case "info": return global::NLog.LogLevel.Info; case "warn": return global::NLog.LogLevel.Warn; case "error": return global::NLog.LogLevel.Error; case "fatal": return global::NLog.LogLevel.Fatal; } return defaultLevel; } } }
实例化Nlog.LogFactory类,并从config里读取的配置,设置到该LogFactory里。
下面是NLog的使用了。
◎打开 Startup.cs文件,并在Configure函数里AddLog。
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerfactory) { // Configure the HTTP request pipeline. // Add the console logger. loggerfactory.AddConsole(); //Add the NLog logger loggerfactory.AddNLog(Configuration.GetSubKey("nlog")); //Log Output Test. var logger = loggerfactory.CreateLogger("NLogTest"); logger.LogInformation("this is infomation from startup"); try { var i = 100 - 100; var j = 100 / i; } catch (DivideByZeroException ex) { logger.LogError("error log test", ex); } 。。。。。。。。。。以下略 }
◎在Controller里使用
打开HomeController.cs文件,并追加代码。
public class HomeController : Controller { private ILogger _logger = null; public HomeController(ILoggerFactory logFactory) { _logger = logFactory.CreateLogger(nameof(HomeController)); _logger.LogWarning("I am created."); } public IActionResult Index() { _logger.LogWarning("hello from index of home control... "); return View(); } ・・・・・・・・・・・以下略 }
编译通过后,F5一下,看看自己的成果吧。
本文完结。
另外,俺不会提供完整的project代码,大家还是自己敲吧,因为偷懒的木匠从来都不是好司机。