Color coat your code like below at: ASP.NET Resources
Free Threaded Logger for C# 2005/2008
  • Works with Framework 2.0/3.0/3.5(SP1)
  • Seperate logs in a single folder by using Application Name
  • Set the max log level.
  • Set the path of where the logs are to be written.
  • Set Max Log size.
  • Set to show timezone.
  • Set to show daylight savings flag.
  • Send logs to any of the polymorphic methods.
  • Pause physical writes without missing incoming logs.
  • Reset logs in mid stream without missing new logging.
  • Write to the Eventlog
  • // Log.cs File          :  v.1.8
    // CLog Assembly        :  v.1.8
    // CEventLog Assembly   :  v.1.3
    //
    // NOTE: I use the version number of each class will reflect latest changes to the interface.
    //      Example: If the last interface changed in v.1.4, then the assembly will be v.1.4 
    //      even if the file version is v.1.6.
    //
    //      Free threaded logger for Debug, Info, Errors log writting.  
    //      Also can write to the EventLog.
    //
    // Versions:
    //      1.8 - 03/06/2010 - Added error handling around File.Delete and checking to 
    //              make sure when creating new file, it doesn't already exist.
    //              Added new interface methods to append Exceptions to the end of your buffer 
    //              automatically.
    //      1.7 - 02/07/2010 - Changed a method name from LogShutdown() to StopLogger().
    //              This is more consistant with StartLogger() method. 
    //              Also modified property "LogLevel" as a defined LOG_TYPE instead of int.
    //              This way we are not always casting logging levels to int.
    //              Modified WriteLine params to have LogLevel in front of Buffer. 
    //              This makes it more constistant with the other methods.
    //              Also modified CEventLog methods to have EventType as the first param so that it too
    //              will be more consistant with the logger methods.
    //              Added a control if log file already exists, which could happen if you have multiple 
    //              applications opening log files at the same time.
    //      1.6 - 11/01/2009 - Added properties ShowTimeZone and ShowDaylightSavings
    //              During daylight savings time shift, logs can look a bit strange at first.  
    //              Adding the timezone in front of the time will help this transition.
    //      1.5 - 10/17/2009 - Added ConsoleWrite
    //              This allows the user to write information to console if it's a console application.
    //      1.4 - 10/11/2009 - Fixed bug in LogReset()
    //              Once reset m_arrFileHandles wasn't being updated with the new file handles.
    //      1.3 - 03/17/2007 - First Release
    //      
    // Written In:
    //      Visual Studio C# 2005/2008
    //      Framework 2.0, 3.0, 3.5/sp1
    //
    // Example of use:
    //      using Chizl.AsyncLogger;                  //CLog
    //
    //      CEventlog.Write("My Tester App", "Log Test Starting");
    //      CLog.LogLevel = LOG_TYPE.LOG_DEBUG;
    //      CLog.MaxLogKBSize = 1024;   //1024 = 1MB    //Minimum Size
    //      CLog.LogFolder = @"MyLogFolder\SubFolder";
    //      CLog.ConsoleWrite = false;
    //      CLog.ApplicationName = "MyAppName";
    //      CLog.ShowDaylightSavings = true;
    //      CLog.ShowTimeZone = true;
    //      
    //      CLog.LogReset(true);    //delete all log files. (TRUE) = Historical
    //      
    //      Thread log = new Thread(new ThreadStart(CLog.StartLogger));
    //      log.Start();
    //      
    //      int iSize = 1000000;
    //      CLog.WriteLine("Starting Test", LOG_TYPE.LOG_DEBUG);
    //      
    //      for (int k = 0; k < iSize; k++)
    //      {
    //          CLog.TRACE("{0} of {1} Test Writes....", k.ToString(), iSize.ToString());
    //          Thread.Sleep(0);    //required for slower machines..
    //      }
    //
    //      CLog.WriteLine(LOG_TYPE.LOG_DEBUG, "Testing with Params: {0}, {1}", DateTime.Now, "WoW");
    //      CLog.WriteLine("Ending Test", LOG_TYPE.LOG_DEBUG);
    //      CLog.StopLogger();
    //      CEventlog.Write("My Tester App", "Log Test Ended");
    //
    //      //shutdown
    //
    // Copyright:
    //      2007-2010, Karland International (www.karland.com)
    // Written By:
    //      Gavin Landon, aka Chizl
    //
    // Permission:
    //      Permission to use, copy, modify, distribute and sell this software and its 
    //      documentation for any purpose is hereby granted without fee, provided that the 
    //      above copyright notice appears in all copies and that both that copyright notice 
    //      and this permission notice appear in supporting documentation. Karland International 
    //      makes no representations about the suitability of this software for any purpose. 
    //      It is provided "as is" without express or implied warranty.
    
    using System;                       //String, DateTime, Byte
    using System.IO;                    //File, FileStream
    using System.Text;                  //ASCIIEncoding
    using System.Threading;             //Thread
    using System.Collections;           //ArrayList
    using System.Diagnostics;           //EventLog
    using System.Reflection;            //Assembly
    
    namespace Chizl.AsyncLogger
    {
        //Log types..
        public enum LOG_TYPE
        {
            LOG_ERR = 0,
            LOG_WARN = 1,
            LOG_DEBUG = 2,
        }   //LOG_TYPE
    
        public class CLog
        {
            #region private structures and enums
            //holds all the transaction information for this socket..
            private enum EVENT_ID
            {
                ID_CHECKMAXSIZE = 100,
                ID_CREATEFILEHANDLE = 101,
            }   //EVENT_ID
    
            private struct FileHandles
            {
                public FileStream twHandle;
                public String szFileName;
                public decimal dwFileSize;
                public String szRootFileName;
            }   //FileHandles
    
            private struct TransLog
            {
                public String szBuffer;
                public LOG_TYPE enumFileType;
                public String AddedDateTime;
                public bool bAddReturn;
                public String szFileName;
            }   //TransLog
            #endregion
    
            #region Static Vars
            private static bool m_bPathSetup = false;
            private static int m_lLogLevel = (int)LOG_TYPE.LOG_WARN;		//default log level
            private static long m_lMaxKBLogSize = 1024;             //default 1MB
            private static String m_szRootLogFolder = @"Logs\";      //set root log folder
            private static ArrayList m_arrLogQueue = new ArrayList();
            private static int m_iPauseLogging = 0;
            private static ArrayList m_arrFileHandles = new ArrayList();
            private static object m_Locker = new object();
            private static AutoResetEvent[] m_autoLogEvents;
            private static bool m_bLogsInUse = false;
            private static bool m_bConsoleWrite = false;
            private static bool m_bTimezone = false;
            private static bool m_bDaylightSavings = false;
            private static bool m_LogFailure = false;
            private static String m_strFilenameFormat = "";     //will be set during LogFolder setup.
            private static String m_strApplicationName = "";    //application name, part of the filename.
    
            //##################################################################
            //## Making this true, you test this logger, have extra info    //##
            //## written to logs, like write time and queue count.          //##
            //## Keep in mind, this will slow the logger down, because      //##
            //## it's doing string copies to add information to the write.  //##
            private static bool m_bDebugSpeed = false;                      //##
            //##################################################################
    
            #endregion
    
            #region const data
            //constant events..
            const int EVENT_MESSAGE = 0;
            const int EVENT_SHUTDOWN = 1;
            //default log extension..
            const String LOG_EXTENSION = ".log";
            //base log names..
            const String LOG_DEBUG_NAME = "Debug_";
            const String LOG_WARN_NAME = "Warning_";
            const String LOG_ERR_NAME = "Error_";
            //timezone and time formats..
            const String LOG_DEFAULT_DST_FORMAT = "z";  //z = -6, zz = -06, zzz = -06:00
            const String LOG_DEFAULT_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss:ffff";
            #endregion
    
            #region public properties
            //property to set application path
            static public void StopLogger()
            {
                if (m_autoLogEvents != null)
                    if (m_autoLogEvents[EVENT_SHUTDOWN] != null)
                        m_autoLogEvents[EVENT_SHUTDOWN].Set();
            }
    
            static public String ApplicationName
            {
                get { return m_strApplicationName; }
                set { m_strApplicationName = value; }
            }
            
            static public bool ConsoleWrite
            {
                get { return m_bConsoleWrite; }
                set { m_bConsoleWrite = value; }
            }
    
            static public bool ShowTimeZone
            {
                get { return m_bTimezone; }
                set { m_bTimezone = value; }
            }
    
            static public bool ShowDaylightSavings
            {
                get { return m_bDaylightSavings; }
                set { m_bDaylightSavings = value; }
            }
    
            //property to set the max Log size in KB.   1024KB = 1MB = Default
            static public long MaxLogKBSize
            {
                get { return m_lMaxKBLogSize; }
                set
                {
                    m_lMaxKBLogSize = value;
                    //if 0, then unlimmited size, but if less than 1MB, this logger writes to 
                    //fast and need more of a file size to maintain the integrety 
                    //of the file name based on millisecond.
                    if (m_lMaxKBLogSize < 1024 && m_lMaxKBLogSize != 0)
                        m_lMaxKBLogSize = 1024;
                }
            }
    
            //pause logging, so files are released and not written to.  Everything is still queued 
            //during this time, but logging to physical disk will not occur until unpause.
            static public bool PauseLogger
            {
                //The reason I'm using integers instead of bool is because if someone from thread1 pauses 
                //and thread2 also pauses, then I need to make sure thread1 doesn't unpause before thread2
                //is ready.  Nested pauses can bite ya, if we don't use this correctly.
                get
                {
                    if (m_iPauseLogging > 0)
                        return true;
                    else
                        return false;
                }
                set
                {
                    if (value)
                        m_iPauseLogging++;
                    else
                        m_iPauseLogging--;
                }
            }
    
            //property to set the max Log size in KB.   1024KB = 1MB = Default
            static public LOG_TYPE LogLevel
            {
                get { return (LOG_TYPE)m_lLogLevel; }
                set { m_lLogLevel = (int)value; }
            }
    
            //property to set the max Log location.   Logs/ = Default
            static public String LogFolder
            {
                get { return m_szRootLogFolder; }
                set
                {
                    m_szRootLogFolder = value;
                    if (m_szRootLogFolder == null)
                        m_szRootLogFolder = "";
                    if (!m_szRootLogFolder.EndsWith(@"\") && !String.IsNullOrEmpty(m_szRootLogFolder))
                        m_szRootLogFolder = m_szRootLogFolder + @"\";
                }
            }
            #endregion
    
            #region public methods
            //polymorphic trace / debug
            static public String TRACE(String sVar, params object[] args)
            {
                //Example of use:
                //  CLog.TRACE("{2}, {0} {1} is {3} years old", "John", "H", "Doe", 20);
    
                sVar = String.Format(sVar, args);
                TRACE(sVar);
                return sVar;
            }   //TRACE
    
            //polymorphic trace / debug
            static public String TRACE(String sVar)
            {
                //Example of use:
                //  CLog.TRACE("Doe, John H is 20 years old");
    
                if (m_bConsoleWrite)
                    Console.WriteLine(sVar);
    
                WriteLine(LOG_TYPE.LOG_DEBUG, sVar);
                return sVar;
            }   //TRACE
    
            //polymorphic method for logging
            static public bool WriteLine(Exception ex, String szBuffer, params object[] args)
            {
                szBuffer = String.Format(szBuffer, args);
                szBuffer += " - TraceStack: " + ex.StackTrace + ", Source: " + ex.Source + ", Message: " + ex.Message;
    
                //write normal
                return WriteData(LOG_TYPE.LOG_ERR, szBuffer, true, true, "");
            }   //WriteLine
    
            //polymorphic method for logging
            static public bool WriteLine(Exception ex, String szBuffer)
            {
                szBuffer += " - TraceStack: " + ex.StackTrace + ", Source: " + ex.Source + ", Message: " + ex.Message;
                //write normal
                return WriteData(LOG_TYPE.LOG_ERR, szBuffer, true, true, "");
            }   //WriteLine
    
            //polymorphic method for logging
            static public bool WriteLine(Exception ex, String szBuffer, bool bAddDate)
            {
                szBuffer += " - TraceStack: " + ex.StackTrace + ", Source: " + ex.Source + ", Message: " + ex.Message;
                //write normal
                return WriteData(LOG_TYPE.LOG_ERR, szBuffer, bAddDate, true, "");
            }   //WriteLine
    
            //polymorphic method for logging
            static public bool WriteLine(LOG_TYPE enumFileType, String szBuffer, params object[] args)
            {
                //verify log level
                if ((LOG_TYPE)m_lLogLevel < enumFileType)
                    return true;
    
                szBuffer = String.Format(szBuffer, args);
    
                //write normal
                return WriteData(enumFileType, szBuffer, true, true, "");
            }   //WriteLine
    
            //polymorphic method for logging
            static public bool WriteLine(LOG_TYPE enumFileType, String szBuffer)
            {
                //verify log level
                if ((LOG_TYPE)m_lLogLevel < enumFileType)
                    return true;
    
                return WriteData(enumFileType, szBuffer, true, true, "");
            }   //WriteLine
    
            //polymorphic method for logging
            static public bool WriteLine(LOG_TYPE enumFileType, String szBuffer, bool bAddDate)
            {
                //verify log level
                if ((LOG_TYPE)m_lLogLevel < enumFileType)
                    return true;
    
                return WriteData(enumFileType, szBuffer, bAddDate, true, "");
            }   //WriteLine
    
            static public void LogReset(bool bDeleteHistorical)
            /*
             * bDeleteHistorical - delete all files in the folder, not just the ones currently open.
            */
            {
                String strFunc = "CLog::LogReset";
                //setup folder path
                if (!SetupPath())
                {
                    StopLogger();
                    return;
                }
    
                //set default file format
                SetFileFormat();
    
                //stop logging so files can be deleted
                //NOTE: this does not stop the queueing of messages, 
                //only the physical write to harddrive.
                PauseLogger = true;
    
                //finish write, before reset
                while (m_bLogsInUse)
                    Thread.Sleep(100);
    
                FileHandles fh = new FileHandles();
                String strDateTime = DateTime.Now.ToString(m_strFilenameFormat);
    
                //close out open handles
                for (int i = 0; i < m_arrFileHandles.Count; i++)
                {
                    fh = (FileHandles)m_arrFileHandles[i];
                    //if file size is zero, meaning nothing was written, then delete it.
                    fh.twHandle.Close();
                    Thread.Sleep(0);    //cycle cpu
                    try
                    {
                        File.Delete(fh.szFileName);
                    }
                    catch (Exception ex)
                    {
                        WriteLine(ex, "{0}: Error while deleting file: {1}", strFunc, fh.szFileName);
                    }
                }
    
                Thread.Sleep(0);    //cycle cpu
    
                if (bDeleteHistorical)
                {
                    //gather all error files
                    String[] fileEntries = Directory.GetFiles(m_szRootLogFolder, m_strApplicationName + "_" + LOG_ERR_NAME + "*" + LOG_EXTENSION);
                    foreach (String fileName in fileEntries)
                    {
                        try
                        {
                            File.Delete(fileName);  //delete all files in the log folder
                        }
                        catch (Exception ex)
                        {
                            WriteLine(ex, "{0}: Error while deleting file: {1}", strFunc, fh.szFileName);
                        }                    
                    }
    
                    Thread.Sleep(0);  //cycle cpu
    
                    //gather all warning files
                    fileEntries = Directory.GetFiles(m_szRootLogFolder, m_strApplicationName + "_" + LOG_WARN_NAME + "*" + LOG_EXTENSION);
                    foreach (String fileName in fileEntries)
                    {
                        try
                        {
                            File.Delete(fileName);  //delete all files in the log folder
                        }
                        catch (Exception ex)
                        {
                            WriteLine(ex, "{0}: Error while deleting file: {1}", strFunc, fh.szFileName);
                        }
                    }
    
                    Thread.Sleep(0);  //cycle cpu
    
                    //gather all debug files
                    fileEntries = Directory.GetFiles(m_szRootLogFolder, m_strApplicationName + "_" + LOG_DEBUG_NAME + "*" + LOG_EXTENSION);
                    foreach (String fileName in fileEntries)
                    {
                        try
                        {
                            File.Delete(fileName);  //delete all files in the log folder
                        }
                        catch (Exception ex)
                        {
                            WriteLine(ex, "{0}: Error while deleting file: {1}", strFunc, fh.szFileName);
                        }
                    }
                }
    
                //reopen files.
                for (int i = 0; i < m_arrFileHandles.Count; i++)
                {
                    fh = (FileHandles)m_arrFileHandles[i];
                    //if file size is zero, meaning nothing was written, then delete it.
                    fh.szFileName = m_szRootLogFolder + fh.szRootFileName + strDateTime + LOG_EXTENSION;
                    while (File.Exists(fh.szFileName))
                    {
                        Thread.Sleep(100);
                        strDateTime = DateTime.Now.ToString(m_strFilenameFormat);
                        //make new file name, based on new time
                        fh.szFileName = m_szRootLogFolder + fh.szRootFileName + strDateTime + LOG_EXTENSION;
                    }
                    fh.twHandle = new FileStream(fh.szFileName, FileMode.OpenOrCreate);
                    fh.dwFileSize = fh.twHandle.Length;
                    m_arrFileHandles[i] = fh;
                }
    
                //start logging again
                PauseLogger = false;
            }
    
            //thread start for logging..
            static public void StartLogger()
            /*
             * All files will have a date as the "Start Date" for each log.  Based on this date
             * and the modified date, you can tell by looking at the log at a high level, the time
             * frame that the log carries.
            */
            {
                //log startup
                FileHandles fh = new FileHandles();
                String strQueueCount = "";  //debug speed test
    
                //format path
                if (!SetupPath())
                    return;
    
                //set default file format
                SetFileFormat();
    
                //get current date and time, for part of the file name.
                String strDateTime = DateTime.Now.ToString(m_strFilenameFormat);
    
                //open all files and their handles into an arraylist
                //ERROR Logs
                fh.szRootFileName = m_strApplicationName + "_" + LOG_ERR_NAME;
                fh.szFileName = m_szRootLogFolder + fh.szRootFileName + strDateTime + LOG_EXTENSION;
                //make sure file doesn't already exist
                while (File.Exists(fh.szFileName))
                {
                    Thread.Sleep(100);
                    strDateTime = DateTime.Now.ToString(m_strFilenameFormat);
                    //make new file name, based on new time
                    fh.szFileName = m_szRootLogFolder + fh.szRootFileName + strDateTime + LOG_EXTENSION;
                }
                fh.twHandle = new FileStream(fh.szFileName, FileMode.OpenOrCreate);
                fh.dwFileSize = fh.twHandle.Length;
                m_arrFileHandles.Add(fh);
    
                //INFORMATION Logs
                fh.szRootFileName = m_strApplicationName + "_" + LOG_WARN_NAME;
                fh.szFileName = m_szRootLogFolder + fh.szRootFileName + strDateTime + LOG_EXTENSION;
                //make sure file doesn't already exist
                while (File.Exists(fh.szFileName))
                {
                    Thread.Sleep(100);
                    strDateTime = DateTime.Now.ToString(m_strFilenameFormat);
                    //make new file name, based on new time
                    fh.szFileName = m_szRootLogFolder + fh.szRootFileName + strDateTime + LOG_EXTENSION;
                }
                fh.twHandle = new FileStream(fh.szFileName, FileMode.OpenOrCreate);
                fh.dwFileSize = fh.twHandle.Length;
                m_arrFileHandles.Add(fh);
    
                //DEBUG Logs
                fh.szRootFileName = m_strApplicationName + "_" + LOG_DEBUG_NAME;
                fh.szFileName = m_szRootLogFolder + fh.szRootFileName + strDateTime + LOG_EXTENSION;
                //make sure file doesn't already exist
                while (File.Exists(fh.szFileName))
                {
                    Thread.Sleep(100);
                    strDateTime = DateTime.Now.ToString(m_strFilenameFormat);
                    //make new file name, based on new time
                    fh.szFileName = m_szRootLogFolder + fh.szRootFileName + strDateTime + LOG_EXTENSION;
                }
                fh.twHandle = new FileStream(fh.szFileName, FileMode.OpenOrCreate);
                fh.dwFileSize = fh.twHandle.Length;
                m_arrFileHandles.Add(fh);
    
                //create events
                m_autoLogEvents = new AutoResetEvent[]
                {
                    new AutoResetEvent(true),   //EVENT_MESSAGE
                    new AutoResetEvent(false)   //EVENT_SHUTDOWN
                };
    
                String strDateFormat = GetDateFormat();
    
                WriteFull("Logging thead has started", LOG_TYPE.LOG_DEBUG,
                        DateTime.Now.ToString(strDateFormat),
                        true, "");
    
                int iEvent = EVENT_MESSAGE;
    
                //if not EVENT_SHUTDOWN, then stay in the loop
                while (iEvent == EVENT_MESSAGE)
                {
                    //wait for an event to be fired, either shutdown or new log message
                    iEvent = WaitHandle.WaitAny(m_autoLogEvents);
    
                    //let everyone know, we are working
                    m_bLogsInUse = true;
    
                    //I removed the switch case here for shutdown or log event being fired.
                    //I figure there are times that something may be put in the queue at the same time that the event 
                    //for shutdown is fired.   Therefore, there's a very small chance to miss a log.  Removing
                    //the switch allows even during shutdowns, the queue is check to see if data is in it and write 
                    //them before shutdown occurs.
    
                    //if messages in queue and not paused
                    while (m_arrLogQueue.Count > 0 && m_iPauseLogging == 0 && !m_LogFailure)
                    {
                        //create temp array list
                        ArrayList arr = new ArrayList();
                        //lock public array list
                        lock (m_Locker)
                        {
                            //copy to temp
                            arr = m_arrLogQueue;
                            //clear public
                            m_arrLogQueue = new ArrayList();
                        }
    
                        //lets write how many transactions are in the queue, if debug is on.
                        if (m_bDebugSpeed)
                            strQueueCount = "(In Queue:" + arr.Count.ToString() + ") ";
                        else
                            strQueueCount = "";
    
                        int iLoopCount = 0;
    
                        //write each message to disk
                        foreach (TransLog tl in arr)
                        {
                            //keep track of looping
                            iLoopCount++;
    
                            //double check something didn't go wrong..
                            if (tl.AddedDateTime != null)
                                WriteFull(strQueueCount + tl.szBuffer, tl.enumFileType, tl.AddedDateTime,
                                    tl.bAddReturn, tl.szFileName);
    
                            //free up the cpu every once in a while for slower machines.
                            //However, calling Sleep(0) each call slows down the loop, so 
                            //lets call it if there are more than 100 in the queue at 
                            //one given time.
                            if (iLoopCount > 100)
                            {
                                iLoopCount = 0;
                                Thread.Sleep(0);   //cycle the cpu..
                            }
    
                            //if something failed, shut down logger.
                            if (m_LogFailure)
                            {
                                StopLogger();
                                break;
                            }
                        }
                    };
    
                    //lets flush em all to disk
                    for (int i = 0; i < m_arrFileHandles.Count; i++)
                    {
                        fh = (FileHandles)m_arrFileHandles[i];
                        try
                        {
                            //flush to disk
                            fh.twHandle.Flush();
                        }
                        catch
                        {
                            //ignore, we are shutting down..
                        }
                    }
    
                    m_bLogsInUse = false;
                }
    
                strDateFormat = GetDateFormat();
                WriteFull("Logging thead has closed", LOG_TYPE.LOG_DEBUG,
                        DateTime.Now.ToString(strDateFormat),
                        true, "");
    
                //close out open handles
                for (int i = 0; i < m_arrFileHandles.Count; i++)
                {
                    fh = (FileHandles)m_arrFileHandles[i];
                    CloseFile(fh, fh.twHandle.Length);
                }
            }   //StartLogger
    
            //method used by the polymorphic methods, for logging
            static public bool WriteData(LOG_TYPE enumFileType, String szBuffer,
                bool bAddDate, bool bAddReturn, String szFileName)
            {
                //verify log level
                if ((LOG_TYPE)m_lLogLevel < enumFileType)
                    return true;
    
                //failure to write so logging have been turned off.
                if (m_LogFailure)
                    return false;
    
                if (m_bConsoleWrite)
                    Console.WriteLine(szBuffer);
    
                TransLog tl = new TransLog();
                if (bAddDate)
                {
                    String strDateFormat = GetDateFormat();
                    tl.AddedDateTime = DateTime.Now.ToString(strDateFormat);
                }
    
                //set params
                tl.bAddReturn = bAddReturn;
                tl.enumFileType = enumFileType;
                tl.szBuffer = szBuffer;
                tl.szFileName = szFileName;
    
                //add to queue, make sure something isn't deleting while adding
                lock (m_Locker)
                    m_arrLogQueue.Add(tl);
    
                //fire event
                if (m_autoLogEvents != null)
                    m_autoLogEvents[EVENT_MESSAGE].Set();
    
                return true;
            }   //WriteData
            #endregion
    
            #region private methods
            private static void SetFileFormat()
            /*
             *  Setup default file name formats
            */
            {
                if (!String.IsNullOrEmpty(m_strFilenameFormat))
                    return;
    
                m_strFilenameFormat = LOG_DEFAULT_DATE_FORMAT.Replace(" ", "_");
                m_strFilenameFormat = m_strFilenameFormat.Replace(":", "");
                m_strFilenameFormat = m_strFilenameFormat.Replace("-", "");
            }
    
            private static String GetDateFormat()
            /*
            * Based on configuration, we will format the date with TimeZone and Daylight Savings time flag.
            */
            {
                //default format
                String strDateFormat = LOG_DEFAULT_DATE_FORMAT;
                //if show timezone
                if (m_bTimezone)
                {
                    //if show daylight savings time
                    if (m_bDaylightSavings)
                    {
                        //check DST
                        if (DateTime.Now.IsDaylightSavingTime())
                            strDateFormat = "[" + LOG_DEFAULT_DST_FORMAT + ",1] " + LOG_DEFAULT_DATE_FORMAT;
                        else
                            strDateFormat = "[" + LOG_DEFAULT_DST_FORMAT + ",0] " + LOG_DEFAULT_DATE_FORMAT;
                    }
                    else
                        //show only timezone
                        strDateFormat = "[" + LOG_DEFAULT_DST_FORMAT + "] " + LOG_DEFAULT_DATE_FORMAT;
                }
    
                //return value
                return strDateFormat;
            }
    
            private static void CloseFile(FileHandles fh, long lFileSize)
            /*
             * Close out file
            */
            {
                String strFunc = "CLog::CloseFile";
                //if file size is zero, meaning nothing was written, then delete it.
                fh.twHandle.Close();
                if (lFileSize == 0)
                {
                    Thread.Sleep(0);    //cycle cpu
                    try
                    {
                        File.Delete(fh.szFileName);
                    }
                    catch (Exception ex)
                    {
                        WriteLine(ex, "{0}: Error while deleting file: {1}", strFunc, fh.szFileName);
                    }                    
                }
            }
    
            //method used by the polymorphic methods, for logging
            private static bool WriteFull(String szBuffer, LOG_TYPE enumFileType,
                String szAddDate, bool bAddReturn, String szFileName)
            {
                //verify log level
                if ((LOG_TYPE)m_lLogLevel < enumFileType)
                    return true;
                if (m_LogFailure)
                    return false;
    
                try
                {
                    //add date/time, ONLY if requested
                    if (szAddDate != null)
                        if (!String.IsNullOrEmpty(szAddDate))
                            szBuffer = szAddDate + ": " + szBuffer;
    
                    //add carriage return line feed, ONLY if requested
                    if (bAddReturn)
                        szBuffer = szBuffer + "\r\n";
    
                    //format path
                    if (!SetupPath())
                        StopLogger();
    
                    FileHandles fh = (FileHandles)m_arrFileHandles[(int)enumFileType];
                    //check log size, make sure it's not bigger than max size.  
                    //If max size is 0 then there's no limit
                    CheckMaxSize(ref fh);
    
                    //the handle may have been closed and reopened.  Get handle after Check Size.
                    FileStream tw = fh.twHandle;
    
                    ASCIIEncoding encoding = new ASCIIEncoding();
                    if (m_bDebugSpeed)
                        szBuffer = "[WriteTime:" + DateTime.Now.ToString("HH:mm:ss:ffff") + "] " + szBuffer;
    
                    //update file size
                    fh.dwFileSize = fh.dwFileSize + szBuffer.Length;
                    //update array with new info
                    m_arrFileHandles[(int)enumFileType] = fh;
    
                    //encode and write
                    Byte[] base64Encode = encoding.GetBytes(szBuffer);
                    tw.Write(base64Encode, 0, base64Encode.Length);
    
                    return true;
                }
                catch
                {
                    m_LogFailure = true;
                    return false;
                }
            } //WriteFull
    
            private static void CheckMaxSize(ref FileHandles fh)
            {
                if (m_LogFailure)
                    return;
    
                //if set to zero then it's set to unlimited size
                if (m_lMaxKBLogSize > 0)
                {
                    //validate the size isn't already larger than max
                    if (fh.dwFileSize > m_lMaxKBLogSize * 1024) //break m_lMaxKBLogSize down to bytes
                    {
                        //close existing file
                        fh.twHandle.Close();
    
                        //create name for backup file, since it's by 
                        //millisecond, there is no way it currently exists, unless someone 
                        //has the max KBLogSize to 1.
                        String strDateTime = DateTime.Now.ToString(m_strFilenameFormat);
                        fh.szFileName = m_szRootLogFolder + fh.szRootFileName + strDateTime + LOG_EXTENSION;
    
                        try
                        {
                            fh.twHandle = new FileStream(fh.szFileName, FileMode.OpenOrCreate);
                            fh.dwFileSize = fh.twHandle.Length;
                        }
                        catch (Exception e)
                        {
                            //log it to event log, since we failed on move..
                            String strAppPath = Assembly.GetExecutingAssembly().Location.ToString();
                            String strMsg = "Error '" + e.Message + "' in application '" +
                                strAppPath + "' while opening '" + fh.szFileName + "'";
                            CEventlog.Write(EventLogEntryType.Error, "Chizl.AsyncLogger", strMsg,
                                (int)EVENT_ID.ID_CREATEFILEHANDLE);
                            m_LogFailure = true;
                            return;
                        }
                    }
                }
            }   //CheckMaxSize
    
            private static bool SetupPath()
            {
                //only need to setup once..
                if (m_bPathSetup)
                    return true;
    
                //set var 
                m_bPathSetup = true;
    
                if (!m_szRootLogFolder.EndsWith(@"\"))
                    m_szRootLogFolder += @"\";
    
                try
                {
                    //if directory doesnt exist, create it
                    if (!Directory.Exists(m_szRootLogFolder))
                        Directory.CreateDirectory(m_szRootLogFolder);
                }
                catch
                {
                    return false;
                }
    
                return true;
            }   //SetupPath
            #endregion
        }
    
        public class CEventlog
        {
            #region event logging
            //method used by the polymorphic methods, for logging to eventlog
            static public bool Write(String strSource, String strEvent)
            {
                return Write(EventLogEntryType.Information, strSource, strEvent, 0);
            }
    
            //method used by the polymorphic methods, for logging to eventlog
            static public bool Write(EventLogEntryType evtType, String strSource, String strEvent)
            {
                return Write(evtType, strSource, strEvent, 0);
            }
    
            //main method used by the polymorphic methods, for logging to eventlog
            static public bool Write(EventLogEntryType evtType, String strSource, String strEvent, int iEventID)
            {
                //default to application
                String strLog = "Application";
    
                try
                {
                    //if the source does not exist, create it
                    if (!EventLog.SourceExists(strSource))
                        EventLog.CreateEventSource(strSource, strLog);
    
                    //write event
                    EventLog.WriteEntry(strSource, strEvent, evtType, iEventID);
                }
                catch
                {
                    return false;
                }
    
                return true;
            }
            #endregion
        }
    }