2010-06-29 58 views
77

Theo tài liệu NLog của:Tại sao loggers khuyên bạn nên sử dụng một logger cho mỗi lớp?

Hầu hết các ứng dụng sẽ sử dụng một logger mỗi lớp, nơi tên của logger là giống như tên của lớp.

Đây cũng là cách mà log4net hoạt động. Tại sao đây là một thực hành tốt?

+1

hmm. dường như có hai vấn đề ở đây - một là có một đối tượng log thực tế cho mỗi lớp, và một là có tên của bản ghi giống như lớp. –

Trả lời

49

Với log4net, 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 điệp tường trình (ví dụ: 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ì có một trình ghi nhật ký cho toàn bộ ứng dụng, bạn cần phải sử dụng các thủ thuật phản chiếu khác để biết thông điệp nhật ký đến từ đâu.

Hãy so sánh như sau:

Log mỗi lớp

using System.Reflection; 
private static readonly ILog _logger = 
    LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);  

public void SomeMethod() 
{ 
    _logger.DebugFormat("File not found: {0}", _filename); 
} 

Một logger cho mỗi ứng dụng (hoặc tương tự)

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, Logger sẽ cần phải xây dựng một chồng dấu vết để xem ai đang gọi nó hoặc mã của bạn sẽ luôn phải vượt qua trong người gọi. Với phong cách logger-per-class, bạn vẫn làm điều này, nhưng bạn có thể làm điều đó 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ỏ một vấn đề hiệu suất nghiêm trọng.

+0

Cảm ơn, giúp làm rõ mọi thứ. Chúng tôi chỉ cần đặt tên và phương thức của lớp vào thư (ví dụ: "ImageCreator.CreateThumbnail() được gọi là"), nhưng tốt hơn nếu trình ghi nhật ký có thể xử lý nó. –

+1

Chỉ cần FYI, nó trở thành "tốt hơn" thực hành để có một Logger cho mỗi trường hợp, thay vì mỗi lớp (tức là tĩnh) vì điều đó giúp dễ dàng nắm bắt thông tin như thông tin về luồng. Rõ ràng đó là vấn đề về hương vị, không có "quy tắc cứng rắn và nhanh chóng", nhưng tôi muốn ném nó ra. –

+6

@will, bạn có thể giải thích thêm một chút không? Khi đăng nhập bằng cách sử dụng một Logger cho mỗi lớp, tôi luôn luôn đăng nhập ID thread để logger có thể nhận được thông tin luồng hiện tại. Mọi thông tin luồng khác cũng sẽ có sẵn cho trình ghi nhật ký. –

0

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 bị đóng gói, điều này cũng giúp dễ sử dụng lớp trong ứng dụng khác mà không vi phạm chức năng ghi nhật ký.

+0

Rất khó để sử dụng lớp đó trong một ứng dụng khác. Bạn phải tham khảo thư viện đăng nhập cho dù bạn có thích hay không. –

1

Có hai lý do ngay lập tức mùa xuân trong tâm trí:

  1. Có một bản ghi riêng biệt cho mỗi lớp học làm cho nó dễ dàng để nhóm lại với nhau tất cả các thư log/lỗi liên quan đến một lớp nhất định.
  2. Việc đăng nhập trong một lớp cho phép bạn ghi lại chi tiết nội bộ có thể không truy cập được bên ngoài lớp học (ví dụ: trạng thái riêng tư, thông tin liên quan đến việc triển khai lớp học, v.v.).
+1

Bạn có một trình ghi nhật ký trong lớp bất kể nó được xác định ở cấp lớp hay toàn cầu. Logger toàn cầu không phải là "bên ngoài" lớp học từ một quan điểm hiển thị. Bạn vẫn đang tham chiếu đến logger toàn cục từ * trong * lớp đang được đề cập, do đó bạn có khả năng hiển thị đầy đủ. – Robert

5

Tôi có thể thấy một vài lý do cho lựa chọn này.

  • Bạn sẽ luôn biết một báo cáo nhật ký cụ thể đến từ đâu, nếu bạn bao gồm tên của trình ghi nhật ký ở định dạng đầu ra nhật ký của mình.
  • Bạn có thể kiểm soát các báo cáo nhật ký bạn nhìn thấy ở cấp độ hạt mịn bằng cách bật hoặc tắt trình ghi nhật ký nhất định hoặc đặt mức độ của chúng.
3

Trong hầu hết các trường hợp, tên của lớp học cung cấp 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ể xem thông báo tường trình và liên kết trực tiếp với một dòng mã.

Một ví dụ tốt, đâ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 logger được chia sẻ có tên là "Hibernate.SQL" hoặc một cái gì đó tương tự, trong đó một số lớp khác nhau viết SQL thô ra một thể loại logger duy nhất.

0

Giúp dễ dàng định cấu hình ứng dụng theo không gian tên hoặc lớp học.

11

Lợi dụng để sử dụng "bộ 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. Ví 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ó đoạn mã rất hữu ích để thực hiện việc này. Đoạn mã nlogger sẽ tạo mã sau:

private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); 

Vì vậy, chỉ có vài lần nhấn phím và bạn có bộ ghi mỗi lớp. Nó sẽ sử dụng không gian tên và tên lớp như tên của trình ghi nhật ký. Để đặt tên khác nhau để logger lớp học của bạn, bạn có thể sử dụng 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 để có được tên của lớp đó đang cố gắng ghi lại một thông điệp : Tên của trình ghi nhật ký (thường là tên của lớp) có thể dễ dàng được 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.

0

Ngoài ra còn có lợi ích hiệu suất trong trường hợp NLog. Hầu hết người dùng sẽ sử dụng

Logger logger = LogManager.GetCurrentClassLogger() 

Tra cứu lớp hiện tại từ theo dõi ngăn xếp có hiệu suất (nhưng không nhiều).

0

Từ quan điểm phát triển, dễ nhất là nếu bạn không phải tạo đối tượng nhật ký mỗi lần. Mặt khác, nếu bạn không, nhưng thay vào đó bạn tạo nó một cách linh động bằng cách sử dụng sự phản chiếu, nó sẽ làm chậm hiệu năng. Để giải quyết điều này, bạn có thể sử dụng đoạn mã sau đó tạo ra các logger độ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); 

     } 
    } 
} 
0

Nếu bạn đang sử dụng nLog bạn có thể chỉ định callsite trong cấu hình, điều này sẽ ghi tên lớp và phương pháp mà báo cáo kết quả khai thác gỗ đã được đặt.

<property name="CallSite" value="${callsite}" /> 

Sau đó, bạn có thể sử dụng hằng số cho tên nhật ký hoặc tên lắp ráp của mình.

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, phỏng đoán của tôi sẽ phản ánh để bạn có thể cần xem xét hiệu suất. Có một vài vấn đề với các phương thức Async nếu bạn không sử dụng NLOG v4.4 hoặc mới hơn.

Các vấn đề liên quan