在Global ignore pattern中加入bin obj並按下OK
接下來試著重新commit,就可以看到bin和obj資料夾已不在commit清單中。如果要排除特定副檔名的檔案,可使用萬用字元的方式,如*.suo。另外有一點要注意的是,Global ignore pattern是case-sensitive,所以大小寫要和欲排除的資料夾或檔案名稱一致。
<?xml version="1.0" encoding="utf-8" ?> <LogFormat xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.legitlog.com/LogFormatSchema.xsd" FormatName="NLog (Legit Log custom layout)"> <Description> Log format for Legit Log NLog layout. ${processid}|${longdate}|${level:uppercase=true}|${event-context:item=Context}|${logger}|${message} </Description> <LogLine> <Fields> <LogFieldFormat Name="ProcessId" FieldType="Int" Delimiter="|" FilterColumn="true" HighlightRows="true" /> <LogFieldFormat Name="DateTime" FieldType="DateTime" Delimiter="|" Format="yyyy-MM-dd HH:mm:ss.ffff" /> <LogFieldFormat Name="Level" FieldType="String" Delimiter="|" FilterColumn="true" HighlightRows="true" /> <LogFieldFormat Name="Context" FieldType="String" Delimiter="|" FilterColumn="true" /> <LogFieldFormat Name="Logger" FieldType="String" Delimiter="|" /> <LogFieldFormat Name="Message" FieldType="String" Delimiter="
" Multiline="true" /> </Fields> </LogLine> </LogFormat>設定檔的格式其實蠻直覺的,每個<LogFieldFormat>代表一個欄位,屬性Name為欄位標頭名稱,FieldType為欄位類型,Delimiter為資料分隔符號。<LogFormat>的FormatName屬性為定義檔的名稱,你可以修改為較有意義的名稱,例如專案名稱。<Description>內的文字則是用來當我們在Legit Log Viewer中點選此定義檔時要顯示的描述文字,例如顯示此定義檔使用的log檔layout格式(設定在NLog設定檔中<target>裡的layout屬性)為何,如範例中的${processid}|${longdate}|${level:uppercase=true}|${event-context:item=Context}|${logger}|${message}。
public const string ConstVersion = "2.0";改用
public static readonly string ReadonlyVersion = "2.0";在此章節還有幾個要點
public class Constants { public const string ConstVersion = "1.0"; public static readonly string ReadonlyVersion = "2.0"; }建立一console app專案ConstvsReadonly,參考並新增下方類別
class Program { static void Main(string[] args) { Console.WriteLine("Const:{0}", Constants.ConstVersion); Console.WriteLine("Readonly:{0}", Constants.ReadonlyVersion); Console.ReadKey(true); } }
public class Constants { public const string ConstVersion = "2.0"; public static readonly string ReadonlyVersion = "3.0"; }再次執行console app可以看到以下結果
Logger logger = LogManager.GetCurrentClassLogger(); logger.Debug("this is a Debug level");而log4net則使用factory method pattern建立一個ILog介面
ILog log = LogManager.GetLogger(typeof(Program)); log.Debug("this is just a debug message");接下來諸如上面的程式碼片段便開始散佈在各個使用logging framework的類別中。這樣會有什麼問題嗎?
public interface ILogService { void Debug(string message; void Info(string message); void Warn(string message); void Error(string message); // 以下省略 }接下來建立一個類別來實作ILogService介面,而這個實作類別裡直接使用logging framework,等於是將實際log的功能再委託給logging framework,以下面為例是直接呼叫NLog提供的API。
public class LogService : ILogService { private static Logger _logger = LogManager.GetCurrentClassLogger(); #region ILogService Members public void Debug(string message) { if (!_logger.IsDebugEnabled) { return; } if (string.IsNullOrWhiteSpace(message)) { throw new ArgumentNullException("message"); } _logger.Debug(message); } // 以下省略 #endregion }接著在client code只要搭配IoC container就可以反轉相依性讓client code相依於前面建立的抽象層(ILogService)。
ILogService logService = ObjectFactory.GetInstance<ILogService>(); logService.Debug("This is a debug level");如此便符合上述兩項原則,但為了符合這兩項原則還得大費周章建立一個抽象層來使用,真的值得嗎?以下就兩個面向來討論
[ExpectedException(typeof(RegisterUserAccountException))] [TestMethod] public void Register_ExistedUser_ThrowRegisterUserAccountException() { RegisterRequest request = new RegisterRequest() { Username = "petechen", Password = "petechen" }; IUserAccountRepository userAccountRepository = MockRepository.GenerateStub<IUserAccountRepository>(); userAccountRepository.Stub(c => c.CreateUserAndAccount(request.Username, request.Password)).IgnoreArguments().Throw(new Exception()); ILogService logService = MockRepository.GenerateStub<ILogService>(); IUserAccountService userAccountService = new UserAccountService(userAccountRepository, ILogService logService); userAccountService.Register(request); logService.AssertWasCalled(c => c.Error("exception occurs"); }實際要測試的類別為UserAccountService,但因為它相依了兩個介面IUserAccountRepository及ILogService,於是我們使用mock/stub來模擬這兩個介面的行為,這樣我們就可以專注在UserAccountService的功能(Register)是否如我們預期(丟出RegisterUserAccountException)般地執行。
ObjectFactory.Initialize(x => { //x.For<ILogService>().Use<LogService>(); x.For<ILogService>().Use<LogServiceForNLog>(); });
- ${aspnet-application} - ASP.NET Application variable.
- ${aspnet-request} - ASP.NET Request variable.
- ${aspnet-session} - ASP.NET Session variable.
- ${aspnet-sessionid} - ASP.NET Session ID.
- ${aspnet-user-authtype} - ASP.NET User variable.
- ${aspnet-user-identity} - ASP.NET User variable.
<?xml version="1.0" encoding="utf-8" ?> <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <extensions> <add assembly="NLog.Extended" /> </extensions> <!--以下省略--> </nlog>設定完後將layout屬性設定為${aspnet-request:serverVariable=AUTH_USER}|${aspnet-request:serverVariable=HTTP_REFERER}|${longdate}|${level:uppercase:true},嘗試登入ASP.NET應用程式及瀏覽其它網頁,可以看到如下資訊被NLog記錄到
In case of an ASP.NET application, the following files are searched:
- standard web application file web.config
- web.nlog located in the same directory as web.config
- NLog.config in application’s directory
- NLog.dll.nlog in a directory where NLog.dll is located
- file name pointed by the NLOG_GLOBAL_CONFIG_FILE environment variable (if defined, NLog 1.0 only - support removed in NLog 2.0)