简体   繁体   中英

C# Singleton Logging Class

I am trying to figure out the best strategy for logging on the async-IO web server I am working on. I thought the easiest way was to have a singleton class that keeps Filestreams open for the appropriate log files so I could just do something like:

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

Or something like that.

My class looks like this:

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);
   }
}

This is all just in my head really, and I'm looking for suggestions on how to make it better and also make sure I'm doing it properly. The biggest thing is I need it to be thread safe, which obviously it is not in its current state. Not sure of the best way to do that.

This is taken care of for you automatically if you use NLog - you define all of your loggers in a .config file and then you access all of them via the static LogManager class, which is a Singleton.

Here's an example which illustrates the thread-safe nature of NLog:

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

There's a method TextWriter.Synchronized which produces a thread-safe version of TextWriter. Try that.

a) Do not include "Log" in method names. It obvious that a logger logs. .Warning, .Error, etc are better method names since they describe which level the log entry has.

b) Create a background thread that writes to the log.

c) Enqueue entries from the logging methods and signal the worker thread.

d) Use (I don't know if I remember the method names correctly)

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

to get the calling method.

Doing that will give you only one thread that access the file.

Maybe you should try NLog or Log4net. Both of them are wonderful log framework.

But if you do want to write your own log component, Lock is a must when you output log messages. It's common that buffering log messages in memory and write them to file once in a time.

Another framework that addreses these issues for you is the Object Guy's logging framework . It can optionally log in the background. Multiple threads can log to the same file. And multiple processes can log to the same file.

I don't think there's any simple way around locking if you want to write to the same file from multiple threads.

So the simple solution is to add a lock around any calls to the StreamWriter . Alternatively you could buffer the output in memory and only write it to the file once in a while which still requires locking, but the lock contention would be a lot lower. If you go to that length, though, you might as well go with a proper logging framework like log4net, which is thread-safe .

Or you could use a class with only shared methods..

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

I found it more usable this way than using a singleton :

Logger.log("Something to log")

Cheers

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM