0

以下のロガークラスを批判していただけませんか?マルチスレッドのWeb環境で使用できますか?そうでない場合、どうすればそれを改善できますか?WriteToLogメソッドのロックまたはFlushLogメソッドのマルチスレッドに何か問題がありますか?

public class Logger
{
    private static Logger instance;
    private static Queue<LogData> logQueue;
    private static string logDir = HttpContext.Current.Server.MapPath(ConfigurationManager.AppSettings["LogDirectory"]);
    private static string logFile = "log.txt";
    private static int maxLogAge = Int32.Parse(ConfigurationManager.AppSettings["LogMaxAge"]);
    private static int queueSize = Int32.Parse(ConfigurationManager.AppSettings["LogQueueSize"]);
    private static DateTime LastFlushed = DateTime.Now;

    private Logger() { }

    public static Logger Instance
    {
        get
        {
            if (instance == null)
            {
                instance = new Logger();
                logQueue = new Queue<LogData>();
            }
            return instance;
        }
    }

    public void WriteToLog(string message)
    {
        lock (logQueue)
        {
            LogData logEntry = new LogData(message);
            logQueue.Enqueue(logEntry);

            if (logQueue.Count >= queueSize || DoPeriodicFlush())
            {
                FlushLog();
            }
        }            
    }

    private bool DoPeriodicFlush()
    {
        TimeSpan logAge = DateTime.Now - LastFlushed;
        if (logAge.TotalSeconds >= maxLogAge)
        {
            LastFlushed = DateTime.Now;
            return true;
        }
        else
        {
            return false;
        }
    }

    private void FlushLog()
    {
        System.Threading.ThreadPool.QueueUserWorkItem(q => {
            while (logQueue.Count > 0)
            {
                LogData entry = logQueue.Dequeue();
                string logPath = logDir + entry.LogDate + "_" + logFile;

                using (System.IO.StreamWriter file = new System.IO.StreamWriter(logPath, true, System.Text.Encoding.UTF8))
                {
                    file.WriteLine(string.Format("{0}\t{1}", entry.LogTime, entry.Message));
                }
            }
        });
    }

    ~Logger()
    {
        FlushLog();
    }
}

public class LogData
{
    public string Message { get; set; }
    public string LogTime { get; set; }
    public string LogDate { get; set; }

    public LogData(string message)
    {
        Message = message;
        LogDate = DateTime.Now.ToString("yyyy-MM-dd");
        LogTime = DateTime.Now.ToString("HH:mm:ss.fff tt");
    }
}

前もって感謝します、

4

1 に答える 1

2

このコードはスレッドセーフではありません。キューへの追加中に同期 (ロック) しますが、コードから削除するコードはキューをロックせず、常にバックグラウンド スレッドで実行されるため、競合状態が発生する可能性があります。

本当に独自のロギングを作成する必要がある場合は、少なくとも、ConcurrentQueue<T>追加時にロックする必要がないように使用することを検討します。 BlockingCollection<T>アイテムが追加されたときにアイテムを処理するためのスレッド呼び出しを持つことができるので、これははるかに簡単にGetConsumingEnumerable()なります。

そうは言っても、ロギングは何度も処理され、適切に処理されたものです。新しいSemantic Logging Application Block (P&P から) やlog4netなどを使用する方がはるかに良いでしょう。

于 2013-02-27T18:29:54.793 に答える