Theo tài liệu của NLog:
Hầu hết các ứng dụng sẽ sử dụng một bộ ghi cho mỗi lớp, trong đó tên của bộ ghi giống với tên của lớp.
Đây cũng giống như cách log4net hoạt động. Tại sao đây là một thực hành tốt?
Theo tài liệu của NLog:
Hầu hết các ứng dụng sẽ sử dụng một bộ ghi cho mỗi lớp, trong đó tên của bộ ghi giống với tên của lớp.
Đây cũng giống như cách log4net hoạt động. Tại sao đây là một thực hành tốt?
Câu trả lời:
Với log4net, việc sử dụng một trình ghi nhật ký cho mỗi lớp giúp dễ dàng nắm bắt nguồn của thông báo nhật ký (tức là lớp ghi vào nhật ký). Nếu bạn không có một trình ghi nhật ký cho mỗi lớp, nhưng thay vào đó có một trình ghi nhật ký cho toàn bộ ứng dụng, bạn cần sử dụng nhiều thủ thuật phản ánh hơn để biết thông báo nhật ký đến từ đâu.
So sánh những điều sau:
using System.Reflection;
private static readonly ILog _logger =
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public void SomeMethod()
{
_logger.DebugFormat("File not found: {0}", _filename);
}
Logger.DebugFormat("File not found: {0}", _filename); // Logger determines caller
-- or --
Logger.DebugFormat(this, "File not found: {0}", _filename); // Pass in the caller
Sử dụng ví dụ thứ hai, Người ghi nhật ký sẽ cần phải xây dựng một dấu vết ngăn xếp để xem ai đang gọi nó hoặc mã của bạn sẽ luôn phải chuyển trong trình gọi. Với kiểu ghi nhật ký cho mỗi lớp, bạn vẫn làm điều này, nhưng bạn có thể thực hiện một lần cho mỗi lớp thay vì một lần cho mỗi cuộc gọi và loại bỏ vấn đề hiệu suất nghiêm trọng.
Lợi thế khi sử dụng "trình ghi trên mỗi tệp" trong NLog: bạn có khả năng quản lý / lọc nhật ký theo không gian tên và tên lớp. Thí dụ:
<logger name="A.NameSpace.MyClass" minlevel="Debug" writeTo="ImportantLogs" />
<logger name="A.NameSpace.MyOtherClass" minlevel="Trace" writeTo="ImportantLogs" />
<logger name="StupidLibrary.*" minlevel="Error" writeTo="StupidLibraryLogs" />
<!-- Hide other messages from StupidLibrary -->
<logger name="StupidLibrary.*" final="true" />
<!-- Log all but hidden messages -->
<logger name="*" writeTo="AllLogs" />
NLogger có một đoạn mã rất hữu ích để làm điều này. Các nlogger
đoạn mã sẽ tạo ra đoạn mã sau:
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
Vì vậy, chỉ có một vài lần nhấn phím và bạn có trình ghi nhật ký cho mỗi lớp. Nó sẽ sử dụng không gian tên và tên lớp làm tên của trình ghi nhật ký. Để đặt tên khác cho trình ghi lớp của bạn, bạn có thể sử dụng điều này:
private static NLog.Logger logger = NLog.LogManager.GetLogger("MyLib.MyName");
Và, như @JeremyWiebe đã nói, bạn không cần phải sử dụng thủ thuật để lấy tên của lớp đang cố gắng ghi thông báo: Tên của trình ghi nhật ký (thường là tên của lớp) có thể dễ dàng ghi vào tệp (hoặc mục tiêu khác) bằng cách sử dụng ${logger}
trong bố cục.
Tôi có thể thấy một vài lý do cho sự lựa chọn này.
Trong hầu hết các trường hợp, tên của lớp cung cấp một tên tốt cho trình ghi nhật ký. Khi quét các tệp nhật ký, bạn có thể thấy thông báo nhật ký và liên kết trực tiếp nó với một dòng mã.
Một ví dụ điển hình mà đây không phải là cách tiếp cận tốt nhất là nhật ký SQL của Hibernate. Có một trình ghi nhật ký được chia sẻ tên là "Hibernate.SQL" hoặc một cái gì đó tương tự, nơi một số lớp khác nhau ghi SQL thô ra một danh mục trình ghi nhật ký duy nhất.
Từ quan điểm phát triển, thật dễ dàng nhất nếu bạn không phải tạo một đối tượng ghi nhật ký mỗi lần. Mặt khác, nếu bạn không làm như vậy, mà thay vào đó bạn tạo nó động bằng cách sử dụng phản chiếu, nó sẽ làm chậm hiệu suất. Để giải quyết vấn đề này, bạn có thể sử dụng mã sau để tạo trình ghi nhật ký động không đồng bộ:
using NLog;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WinForms
{
class log
{
public static async void Log(int severity, string message)
{
await Task.Run(() => LogIt(severity, message));
}
private static void LogIt(int severity, string message)
{
StackTrace st = new StackTrace();
StackFrame x = st.GetFrame(2); //the third one goes back to the original caller
Type t = x.GetMethod().DeclaringType;
Logger theLogger = LogManager.GetLogger(t.FullName);
//https://github.com/NLog/NLog/wiki/Log-levels
string[] levels = { "Off", "Trace", "Debug", "Info", "Warn", "Error", "Fatal" };
int level = Math.Min(levels.Length, severity);
theLogger.Log(LogLevel.FromOrdinal(level), message);
}
}
}
Hai lý do ngay lập tức xuất hiện trong tâm trí:
Có thể vì bạn muốn có thể ghi các phương thức chỉ hiển thị cho lớp mà không phá vỡ tính đóng gói, điều này cũng giúp bạn dễ dàng sử dụng lớp trong ứng dụng khác mà không phá vỡ chức năng ghi.
Nếu bạn đang sử dụng NLOG, bạn có thể chỉ định vùng gọi trong cấu hình, điều này sẽ ghi lại tên lớp và phương thức nơi đặt câu lệnh ghi nhật ký.
<property name="CallSite" value="${callsite}" />
Sau đó, bạn có thể sử dụng một hằng số cho tên trình ghi của bạn hoặc tên hợp ngữ.
Tuyên bố từ chối trách nhiệm: Tôi không biết NLOG thu thập thông tin này như thế nào, tôi đoán là phản ánh nên bạn có thể cần xem xét hiệu suất. Có một số vấn đề với các phương thức Async nếu bạn không sử dụng NLOG v4.4 trở lên.