2010-07-13 43 views
6

Tôi đang cố gắng tìm ra chiến lược tốt nhất để đăng nhập vào máy chủ web async-IO mà tôi đang làm việc. Tôi nghĩ cách đơn giản nhất là có một lớp singleton giúp Filestream mở cho các tệp nhật ký phù hợp để tôi có thể làm một cái gì đó như:C# Singleton Logging Class

Util.Logger.GetInstance().LogAccess(str); 

Hoặc tương tự.

Lớp học của tôi trông như thế này:

public sealed class Logger { 
    private static StreamWriter sw; 
    private static readonly Logger instance = new Logger(); 
    private Logger() { 
     sw = new StreamWriter(logfile); 
    } 
    public static Logger GetInstance() { 
     return instance; 
    } 
    public void LogAccess(string str) { 
     sw.WriteLine(str); 
    } 
} 

Đây là tất cả chỉ là trong đầu tôi thực sự, và tôi đang tìm gợi ý về cách để làm cho nó tốt hơn và cũng chắc chắn rằng tôi đang làm nó đúng cách. Điều lớn nhất là tôi cần nó để được thread an toàn, mà rõ ràng là nó không phải là ở trạng thái hiện tại của nó. Không chắc chắn cách tốt nhất để làm điều đó.

+0

Bạn đang sử dụng. NET 4, perchance? Thư viện async mới có thể giúp bạn. (Tôi cũng sẽ có cơ hội để chỉ ra cách thanh lịch này sẽ được thực hiện trong F #, và nghỉ phép của tôi!) –

+1

Giá trị của việc sử dụng Singleton so với chỉ sử dụng phương pháp tĩnh là gì? – kyoryu

+1

Tôi thích thực tế bạn muốn tự mình thử. Việc ghi nhật ký không khó để xây dựng nhưng tạo ra một cách hay để xử lý luồng là một thách thức. Các khung công tác được đề xuất đều ổn, nhưng tự tạo ra nó sẽ mang lại cho bạn cơ hội tốt để tìm hiểu và làm việc với thread-safety. Nó thực sự trở nên khó khăn nếu bạn muốn nhiều ứng dụng (hoặc trong các hồ bơi ứng dụng ASP.NET/máy chủ) ghi vào cùng một tệp, bởi vì trong trường hợp đó chỉ an toàn chỉ là không đủ. – Gertjan

Trả lời

5

Có một phương pháp TextWriter.Synchronized trong đó sản xuất một phiên bản thread-safe của TextWriter. Hãy thử điều đó.

0

Tôi không nghĩ có cách nào đơn giản xung quanh khóa nếu bạn muốn ghi vào cùng một tệp từ nhiều chuỗi.

Vì vậy, giải pháp đơn giản là thêm lock xung quanh mọi cuộc gọi đến StreamWriter. Ngoài ra, bạn có thể đệm đầu ra trong bộ nhớ và chỉ ghi nó vào tập tin một lần trong một thời gian mà vẫn yêu cầu khóa, nhưng tranh chấp khóa sẽ thấp hơn rất nhiều. Tuy nhiên, nếu bạn đi đến chiều dài đó, bạn cũng có thể đi với một khung đăng nhập thích hợp như log4net, which is thread-safe.

4

a) Không bao gồm "Nhật ký" trong tên phương thức. Rõ ràng là một nhật ký logger. .Warning, .Error, vv là các tên phương thức tốt hơn vì chúng mô tả mức độ mà mục nhật ký có.

b) Tạo chủ đề nền viết cho nhật ký.

c) Nhập các mục nhập từ phương thức ghi nhật ký và báo hiệu chuỗi công nhân.

d) Sử dụng (Tôi không biết nếu tôi nhớ tên phương pháp chính xác)

var methodInfo = new StackFrame(1).GetMethod(); 
var classAndMethod = methodInfo.DeclaringType.Name + "." + methodInfo.Name; 

để có được những phương pháp gọi điện thoại.

Làm như vậy sẽ chỉ cung cấp cho bạn một chuỗi truy cập tệp.

+2

Tôi không đồng ý với (a), vì 'Cảnh báo' và' Lỗi' không phải là động từ. Tên phương thức nên là động từ theo quy ước. 'Warn' sẽ tốt hơn, nhưng làm thế nào chúng ta nên đặt tên các phương thức để ghi lại các lỗi và các lỗi nghiêm trọng? 'LogWarning' và' LogError' là IMO tốt hơn nhiều, hoặc tôi muốn sử dụng một phương thức chung gọi là 'Log' với đối số' severity' hiển thị kiểu. Trong khi (b) có thể tăng hiệu suất, hầu hết các khung công tác ghi nhật ký không đăng nhập nền. Đó là khó khăn, và thường an toàn hơn nhiều để thực hiện đồng bộ. – Steven

+0

Cũng có quy tắc cho biết tên lớp không được lặp lại trong tên phương thức. Trong trường hợp này, đó là tất cả về hương vị vì nó khá rõ ràng rằng lỗi và LogError làm điều tương tự. Tôi thích phương pháp Lỗi thay vì phương thức Đăng nhập có thông số mức độ nghiêm trọng vì nó ít để nhập và đọc. Nhưng như tôi đã nói: Đó là tất cả về hương vị. (b) Tôi không thấy cách ghi vào nhật ký trong một chủ đề riêng biệt là khó khăn hoặc không an toàn. Nó khá thẳng về phía trước. Một chủ đề, một hàng đợi và một khóa, không có gì hơn là cần thiết – jgauffin

+0

Tôi đã không nói nó sẽ khó thực hiện; vấn đề là việc ghi nhật ký thường là một phần quan trọng trong quy trình nghiệp vụ và trong trường hợp đó bạn không muốn tiếp tục xử lý trước khi bạn biết rằng thông điệp tường trình của bạn vẫn còn tồn tại. Tất nhiên trong kịch bản khác của nó có thể là tốt để giữ một hàng đợi của các thông điệp tường trình. Nó phụ thuộc. Nhưng vì lý do đó, các khung ghi nhật ký thường xử lý chúng một cách đồng bộ. – Steven

8

Điều này được tự động xử lý cho bạn nếu bạn sử dụng NLog - bạn xác định tất cả các trình ghi nhật ký của mình trong tệp .config và sau đó bạn truy cập tất cả chúng qua lớp LogManager tĩnh, là Singleton.

Dưới đây là một ví dụ minh họa tính chất thread-safe của NLog:

http://nlog-project.org/wiki/Tutorial#Adding_NLog_to_an_application

2

Có thể bạn nên thử NLog hoặc Log4net. Cả hai đều là khung đăng nhập tuyệt vời.

Nhưng nếu bạn muốn viết thành phần nhật ký của riêng mình, Khóa là phải khi bạn xuất thông điệp tường trình. Thông thường, việc lưu thông điệp tường trình vào bộ nhớ và ghi chúng vào tệp một lần trong một thời gian.

1

Một khuôn khổ khác bổ sung những vấn đề này cho bạn là the Object Guy's logging framework. Nó có thể tùy ý đăng nhập trong nền.Nhiều luồng có thể đăng nhập vào cùng một tệp. Và nhiều quy trình có thể đăng nhập vào cùng một tệp.

0

Hoặc bạn có thể sử dụng một lớp học với phương pháp chỉ chia sẻ ..

Imports System.Threading 

Public Class Logger 
    Private Shared ReadOnly syncroot As New Object 

    Public Shared Sub log(ByVal vInt As Integer) 
     ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf logThread), CStr(vInt)) 
    End Sub 

    Public Shared Sub log(ByVal vStr As String) 
     ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf logThread), vStr) 
    End Sub 

    Private Shared Sub logThread(ByVal o As Object) 
     Dim str As String = CStr(o) 
     SyncLock syncroot 
      Using objWriter As New System.IO.StreamWriter(GetLogPath, True) 

       objWriter.WriteLine(str) 
       objWriter.Close() 

      End Using 
     End SyncLock 
    End Sub 

    Private Shared Function GetLogPath() As String 
     Return "logs.txt" 
    End Function 
End Class 

tôi thấy nó có thể sử dụng nhiều cách này vì sử dụng một singleton:

Logger.log("Something to log") 

Cheers