[mapguide-commits] r6670 - in branches/2.4/MgDev/Desktop: MgDesktop MgDesktop/Exception MgDesktop/Log MgDesktop/System UnitTest

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Fri May 18 15:39:13 EDT 2012


Author: jng
Date: 2012-05-18 12:39:12 -0700 (Fri, 18 May 2012)
New Revision: 6670

Added:
   branches/2.4/MgDev/Desktop/MgDesktop/Exception/InvalidLogEntryException.cpp
   branches/2.4/MgDev/Desktop/MgDesktop/Exception/InvalidLogEntryException.h
   branches/2.4/MgDev/Desktop/MgDesktop/Log/
   branches/2.4/MgDev/Desktop/MgDesktop/Log/LogDetail.cpp
   branches/2.4/MgDev/Desktop/MgDesktop/Log/LogDetail.h
   branches/2.4/MgDev/Desktop/MgDesktop/Log/LogEntryData.cpp
   branches/2.4/MgDev/Desktop/MgDesktop/Log/LogEntryData.h
   branches/2.4/MgDev/Desktop/MgDesktop/Log/LogManager.cpp
   branches/2.4/MgDev/Desktop/MgDesktop/Log/LogManager.h
   branches/2.4/MgDev/Desktop/MgDesktop/Log/LogThread.cpp
   branches/2.4/MgDev/Desktop/MgDesktop/Log/LogThread.h
   branches/2.4/MgDev/Desktop/MgDesktop/Log/LogType.h
   branches/2.4/MgDev/Desktop/MgDesktop/System/ThreadBase.cpp
   branches/2.4/MgDev/Desktop/MgDesktop/System/ThreadBase.h
   branches/2.4/MgDev/Desktop/UnitTest/TestLogManager.cpp
   branches/2.4/MgDev/Desktop/UnitTest/TestLogManager.h
   branches/2.4/MgDev/Desktop/UnitTest/TestLogManagerThread.cpp
   branches/2.4/MgDev/Desktop/UnitTest/TestLogManagerThread.h
Modified:
   branches/2.4/MgDev/Desktop/MgDesktop/MgDesktop.h
   branches/2.4/MgDev/Desktop/MgDesktop/MgDesktop.vcproj
   branches/2.4/MgDev/Desktop/MgDesktop/MgDesktopBuild.cpp
   branches/2.4/MgDev/Desktop/MgDesktop/Platform.ini
   branches/2.4/MgDev/Desktop/MgDesktop/System/ConfigProperties.cpp
   branches/2.4/MgDev/Desktop/MgDesktop/System/ConfigProperties.h
   branches/2.4/MgDev/Desktop/MgDesktop/System/PlatformInit.cpp
   branches/2.4/MgDev/Desktop/UnitTest/UnitTest.vcproj
   branches/2.4/MgDev/Desktop/UnitTest/main.cpp
Log:
Integrate MapGuide Server logging classes into mg-desktop

Added: branches/2.4/MgDev/Desktop/MgDesktop/Exception/InvalidLogEntryException.cpp
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Exception/InvalidLogEntryException.cpp	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Exception/InvalidLogEntryException.cpp	2012-05-18 19:39:12 UTC (rev 6670)
@@ -0,0 +1,40 @@
+//
+//  Copyright (C) 2004-2011 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#include "MgDesktop.h"
+
+IMPLEMENT_EXCEPTION_DEFAULTS(MgInvalidLogEntryException, MgApplicationException)
+
+///////////////////////////////////////////////////////////////////////////////
+/// \brief
+/// Construct a MgInvalidLogEntryException object.
+///
+MgInvalidLogEntryException::MgInvalidLogEntryException(CREFSTRING methodName,
+    INT32 lineNumber, CREFSTRING fileName, MgStringCollection* whatArguments,
+    CREFSTRING whyMessageId, MgStringCollection* whyArguments) throw() :
+    MgApplicationException(methodName, lineNumber, fileName,
+        whatArguments, whyMessageId, whyArguments)
+{
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/// \brief
+/// Destruct the object.
+///
+MgInvalidLogEntryException::~MgInvalidLogEntryException() throw()
+{
+}

Added: branches/2.4/MgDev/Desktop/MgDesktop/Exception/InvalidLogEntryException.h
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Exception/InvalidLogEntryException.h	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Exception/InvalidLogEntryException.h	2012-05-18 19:39:12 UTC (rev 6670)
@@ -0,0 +1,71 @@
+//
+//  Copyright (C) 2004-2011 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+/// \ingroup Exceptions_Module
+
+#ifndef MG_INVALID_LOG_ENTRY_EXCEPTION_H_
+#define MG_INVALID_LOG_ENTRY_EXCEPTION_H_
+
+///////////////////////////////////////////////////////////////////////////////
+/// \brief
+/// Thrown when a log entry does not correspond with the expected format.
+///
+class MG_DESKTOP_API MgInvalidLogEntryException : public MgApplicationException
+{
+    DECLARE_CLASSNAME(MgInvalidLogEntryException)
+
+    ///////////////////////////////////////////////////////
+
+EXTERNAL_API:
+
+    ///////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Construct a MgInvalidLogEntryException object.
+    ///
+    /// \param methodName
+    /// Name of the method where the exception occurred.
+    /// \param lineNumber
+    /// Line number where the exception occurred.
+    /// \param fileName
+    /// File name where the exception occurred.
+    /// \param whatArguments
+    /// Collection of arguments used to format the message that describes what the exception is.
+    /// \param whyMessageId
+    /// ID of the message that describes why the exception occurs.
+    /// \param whyArguments
+    /// Collection of arguments used to format the message that describes why the exception occurs.
+    ///
+    MgInvalidLogEntryException(CREFSTRING methodName, INT32 lineNumber,
+        CREFSTRING fileName, MgStringCollection* whatArguments,
+        CREFSTRING whyMessageId, MgStringCollection* whyArguments) throw();
+
+    ///////////////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Destructor for a MgInvalidPasswordException object.
+    ///
+    virtual ~MgInvalidLogEntryException() throw();
+
+INTERNAL_API:
+
+    DECLARE_EXCEPTION_DEFAULTS(MgInvalidLogEntryException)
+
+CLASS_ID:
+
+    static const INT32 m_cls_id = MapGuide_Desktop_Exception_MgInvalidLogEntryException;
+};
+
+#endif


Property changes on: branches/2.4/MgDev/Desktop/MgDesktop/Log
___________________________________________________________________
Added: bugtraq:number
   + true

Added: branches/2.4/MgDev/Desktop/MgDesktop/Log/LogDetail.cpp
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Log/LogDetail.cpp	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Log/LogDetail.cpp	2012-05-18 19:39:12 UTC (rev 6670)
@@ -0,0 +1,142 @@
+//
+//  Copyright (C) 2004-2011 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#include "LogDetail.h"
+
+MgLogDetail::MgLogDetail(INT32 serviceNum, INT8 detail, CREFSTRING methodName, REFSTRING errorLogVar)
+: m_errorLogVar(errorLogVar)
+{
+    MgLogManager* logMgr = MgLogManager::GetInstance();
+    m_minDetail = logMgr->GetDetailLevelForService(serviceNum);
+    m_bLoggingActive = logMgr->IsTraceLogEnabled();
+    m_delimiter = logMgr->GetLogDelimiter();
+    m_detail = detail;
+    m_methodName = methodName;
+}
+
+MgLogDetail::~MgLogDetail()
+{
+    Terminate();
+}
+
+void MgLogDetail::AppendName(CREFSTRING paramName)
+{
+    if (m_params.length() > 0)
+    {
+        m_params.append(m_delimiter);
+    }
+    m_params.append(paramName);
+    m_params.append(L"=");
+}
+
+ bool MgLogDetail::ParamsActive()
+ {
+     return m_minDetail > MgLogDetail::Error;
+ }
+
+ bool MgLogDetail::ShouldLog()
+ {
+     return m_detail <= m_minDetail;
+ }
+
+void MgLogDetail::AddResourceIdentifier(CREFSTRING paramName, MgResourceIdentifier* resId)
+{
+
+    if (NULL != resId && ParamsActive())
+    {
+        AppendName(paramName);
+        m_params.append(resId->ToString());
+    }
+}
+
+void MgLogDetail::AddInt64(CREFSTRING paramName, INT64 paramValue)
+{
+    if (ParamsActive())
+    {
+        AppendName(paramName);
+        STRING temp;
+        MgUtil::Int64ToString(paramValue, temp);
+        m_params.append(temp);
+    }
+}
+
+void MgLogDetail::AddInt32(CREFSTRING paramName, INT32 paramValue)
+{
+    if (ParamsActive())
+    {
+        AppendName(paramName);
+        STRING temp;
+        MgUtil::Int32ToString(paramValue, temp);
+        m_params.append(temp);
+    }
+}
+
+void MgLogDetail::AddBool(CREFSTRING paramName, bool paramValue)
+{
+    if (ParamsActive())
+    {
+        AppendName(paramName);
+        m_params.append(paramValue ? L"1" : L"0");
+    }
+}
+
+void MgLogDetail::AddString(CREFSTRING paramName, CREFSTRING paramValue)
+{
+    if (ParamsActive())
+    {
+        AppendName(paramName);
+        m_params.append(paramValue);
+    }
+}
+
+void MgLogDetail::AddObject(CREFSTRING paramName, MgSerializable* object)
+{
+    if (NULL != object && ParamsActive())
+    {
+        AppendName(paramName);
+        m_params.append(object->GetLogString());
+    }
+}
+
+void MgLogDetail::Create()
+{
+    // Always propagate parameters for exception message
+    m_errorLogVar = m_params;
+
+    if (ShouldLog())
+    {
+        STRING tempStr;
+        tempStr.append(L"BGN");
+        tempStr.append(m_delimiter);
+        tempStr.append(m_methodName);
+        tempStr.append(m_delimiter);
+        tempStr.append(m_params);
+        MG_LOG_TRACE_ENTRY(tempStr);
+    }
+}
+
+void MgLogDetail::Terminate()
+{
+    if (ShouldLog())
+    {
+        STRING tempStr;
+        tempStr.append(L"END");
+        tempStr.append(m_delimiter);
+        tempStr.append(m_methodName);
+        MG_LOG_TRACE_ENTRY(tempStr);
+    }
+}

Added: branches/2.4/MgDev/Desktop/MgDesktop/Log/LogDetail.h
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Log/LogDetail.h	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Log/LogDetail.h	2012-05-18 19:39:12 UTC (rev 6670)
@@ -0,0 +1,108 @@
+//
+//  Copyright (C) 2004-2011 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#ifndef MGLOGDETAIL_H_
+#define MGLOGDETAIL_H_
+
+#include "MgDesktop.h"
+#include "LogManager.h"
+
+//
+// MgLogDetail maintains detailed information for both the Trace Log and the Error Log.
+// It also handles writing of the trace log based on information contained in serverconfig.ini
+//
+// [GeneralProperties]
+// LogsDetail = ResourceService:0,FeatureService:1
+//
+// LogsDetail determines the information logged for each service.  See LogDetail enum below
+// for more information.
+//
+// Example:
+// LogsDetail = ResourceService:0,FeatureService:1
+// Only error messages without parameters are logged for Resource Service, and
+// Error messages and warnings with parameters are logged for Feature Service
+//
+class MG_DESKTOP_API MgLogDetail
+{
+    DECLARE_CLASSNAME(MgLogDetail)
+
+public:
+/// Enumerations
+
+    // Errors (exceptions) are logged without method parameters for the specified service
+    // Warnings are not logged for this service
+    // Traces are not logged for this service
+    // Note:  This is the default level of detail.
+    static const INT8 Error = 0;
+
+    // Errors (exceptions) are logged with method parameters for the specified service
+    // Warnings are logged with parameters for this service
+    // Traces are not logged for this service
+    static const INT8 Warning = 1;
+
+    // All Warning detail, plus
+    // Traces with parameters are logged for published Service API calls
+    static const INT8 Trace = 2;
+
+    // All Trace detail, plus
+    // Traces with parameters are logged for internal API calls
+    static const INT8 InternalTrace = 3;
+
+
+/// Constructors/Destructor
+
+public:
+
+    // Defines a log entry for the specified service and detail level.  This entry will only be emitted
+    // into trace log if the serverconfig.ini LogsDetail >= detail
+    MgLogDetail(INT32 serviceType, INT8 detail, CREFSTRING methodName, REFSTRING errorLogVar);
+    virtual ~MgLogDetail();
+
+/// Methods
+
+public:
+
+    void AddResourceIdentifier(CREFSTRING paramName, MgResourceIdentifier* resId);
+    void AddInt64(CREFSTRING paramName, INT64 paramValue);
+    void AddInt32(CREFSTRING paramName, INT32 paramValue);
+    void AddBool(CREFSTRING paramName, bool paramValue);
+    void AddString(CREFSTRING paramName, CREFSTRING paramValue);
+    void AddObject(CREFSTRING paramName, MgSerializable* object);
+    void Create();
+
+private:
+
+    void Terminate();
+    void AppendName(CREFSTRING paramName);
+    bool ParamsActive();
+    bool ShouldLog();
+
+
+/// Data Members
+
+private:
+
+    bool m_bLoggingActive; // Are we writing to trace log?
+    INT8 m_detail; // detail level
+    INT8 m_minDetail; // minimum detail level from config file
+    STRING m_params; // parameter string
+    STRING m_methodName; // method name
+    REFSTRING m_errorLogVar; // error log parameters variable
+    STRING m_delimiter; // log delimiter
+};
+
+#endif

Added: branches/2.4/MgDev/Desktop/MgDesktop/Log/LogEntryData.cpp
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Log/LogEntryData.cpp	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Log/LogEntryData.cpp	2012-05-18 19:39:12 UTC (rev 6670)
@@ -0,0 +1,42 @@
+//
+//  Copyright (C) 2004-2011 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#include "MgDesktop.h"
+#include "LogEntryData.h"
+
+//-------------------------------------------------------------------------
+//  Constructors/Destructors
+//-------------------------------------------------------------------------
+
+///////////////////////////////////////////////////////////////////////////
+//  <summary>
+//  The constructor for the MgLogEntryData object.
+//  </summary>
+MgLogEntryData::MgLogEntryData( enum MgLogType logType, CREFSTRING message, ACE_Log_Priority logPriority ) :
+    m_logType(logType),
+    m_message(message.c_str()),
+    m_logPriority(logPriority)
+{
+};
+
+///////////////////////////////////////////////////////////////////////////
+//  <summary>
+//  The destructor for the MgLogEntryData object.
+//  </summary>
+MgLogEntryData::~MgLogEntryData()
+{
+};

Added: branches/2.4/MgDev/Desktop/MgDesktop/Log/LogEntryData.h
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Log/LogEntryData.h	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Log/LogEntryData.h	2012-05-18 19:39:12 UTC (rev 6670)
@@ -0,0 +1,45 @@
+//
+//  Copyright (C) 2004-2011 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#ifndef MG_LOG_ENTRY_DATA_H_MG
+#define MG_LOG_ENTRY_DATA_H_MG
+
+///////////////////////////////////////////////////////////////////////////
+//  The LogEntryData class encapsulates the data needed by the log thread.
+class MgLogEntryData : public ACE_Data_Block
+{
+    DECLARE_CLASSNAME(MgLogEntryData)
+
+///////////////////////////////////////////////////////////////////////
+///  Constructors/Destructors
+public:
+    MgLogEntryData( enum MgLogType logType, CREFSTRING message, ACE_Log_Priority logPriority );
+    virtual ~MgLogEntryData();
+
+///////////////////////////////////////////////////////////////////////
+///  Accessors
+public:
+    enum MgLogType m_logType;
+    STRING m_message;
+    ACE_Log_Priority m_logPriority;
+
+///////////////////////////////////////////////////////////////////////
+///  Member Variables
+protected:
+};
+
+#endif  //  MG_LOG_ENTRY_DATA_H_MG

Added: branches/2.4/MgDev/Desktop/MgDesktop/Log/LogManager.cpp
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Log/LogManager.cpp	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Log/LogManager.cpp	2012-05-18 19:39:12 UTC (rev 6670)
@@ -0,0 +1,4557 @@
+//
+//  Copyright (C) 2004-2011 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#include "MgDesktop.h"
+#include "LogEntryData.h"
+#include "LogManager.h"
+#include "LogThread.h"
+
+const int MAX_BUF       = 16384;
+const int MAX_LINES     = 512;
+const int SECONDSINDAY  = 86400;
+
+// Process-wide MgResources
+Ptr<MgLogManager> MgLogManager::m_logManager          = (MgLogManager*)NULL;
+
+// Default values
+STRING MgLogManager::m_path                           = L"./";                    // Default path
+INT32 MgLogManager::m_maxLogSize                      = 64;
+STRING MgLogManager::m_delimiter                      = L"\t";
+bool MgLogManager::m_useMaxLogSize                    = false;
+const STRING MgLogManager::DefaultAccessLogFileName         = L"Access.log";
+const STRING MgLogManager::DefaultAdminLogFileName          = L"Admin.log";
+const STRING MgLogManager::DefaultAuthenticationLogFileName = L"Authentication.log";
+const STRING MgLogManager::DefaultErrorLogFileName          = L"Error.log";
+const STRING MgLogManager::DefaultPerformanceLogFileName    = L"Performance.log";
+const STRING MgLogManager::DefaultSessionLogFileName        = L"Session.log";
+const STRING MgLogManager::DefaultTraceLogFileName          = L"Trace.log";
+
+// Log parameters
+const STRING MgLogManager::AverageOpTimeParam   = L"AVERAGEOPTIME";
+const STRING MgLogManager::ClientParam          = L"CLIENT";
+const STRING MgLogManager::ClientIpParam        = L"CLIENTIP";
+const STRING MgLogManager::DurationParam        = L"DURATION";
+const STRING MgLogManager::EndTimeParam         = L"ENDTIME";
+const STRING MgLogManager::ErrorParam           = L"ERROR";
+const STRING MgLogManager::InfoParam            = L"INFO";
+const STRING MgLogManager::OpIdParam            = L"OPID";
+const STRING MgLogManager::OpsFailedParam       = L"OPSFAILED";
+const STRING MgLogManager::OpsProcessedParam    = L"OPSPROCESSED";
+const STRING MgLogManager::OpsReceivedParam     = L"OPSRECEIVED";
+const STRING MgLogManager::StackTraceParam      = L"STACKTRACE";
+const STRING MgLogManager::StartTimeParam       = L"STARTTIME";
+const STRING MgLogManager::UserParam            = L"USER";
+
+// Performance Log parameters
+const STRING MgLogManager::PerformanceAdminOperationsQueueCount  = L"ADMINOPQCOUNT";
+const STRING MgLogManager::PerformanceClientOperationsQueueCount = L"CLIENTOPQCOUNT";
+const STRING MgLogManager::PerformanceSiteOperationsQueueCount   = L"SITEOPQCOUNT";
+const STRING MgLogManager::PerformanceAverageOperationTime       = L"AVGOPTIME";
+const STRING MgLogManager::PerformanceCpuUtilization             = L"CPU";
+const STRING MgLogManager::PerformanceWorkingSet                 = L"WORKINGSET";
+const STRING MgLogManager::PerformanceVirtualMemory              = L"VIRTUALMEMORY";
+const STRING MgLogManager::PerformanceTotalOperationTime         = L"TOTALOPTIME";
+const STRING MgLogManager::PerformanceTotalActiveConnections     = L"TOTALACTIVECONNECTIONS";
+const STRING MgLogManager::PerformanceTotalConnections           = L"TOTALCONNECTIONS";
+const STRING MgLogManager::PerformanceTotalProcessedOperations   = L"TOTALPROCESSEDOP";
+const STRING MgLogManager::PerformanceTotalReceivedOperations    = L"TOTALRECEIVEDOP";
+const STRING MgLogManager::PerformanceUptime                     = L"UPTIME";
+const STRING MgLogManager::PerformanceCacheSize                  = L"CACHESIZE";
+const STRING MgLogManager::PerformanceCacheDroppedEntries        = L"CACHEDROPPEDENTRIES";
+
+// Header line prefix strings
+const STRING MgLogManager::HeaderLine1          = L"# Log Type:";
+const STRING MgLogManager::HeaderLine2          = L"# Log Parameters:";
+
+// Log type strings
+const STRING MgLogManager::AccessLog            = L"Access Log";
+const STRING MgLogManager::AdminLog             = L"Admin Log";
+const STRING MgLogManager::AuthenticationLog    = L"Authentication Log";
+const STRING MgLogManager::ErrorLog             = L"Error Log";
+const STRING MgLogManager::PerformanceLog       = L"Performance Log";
+const STRING MgLogManager::SessionLog           = L"Session Log";
+const STRING MgLogManager::TraceLog             = L"Trace Log";
+const STRING MgLogManager::UnspecifiedLog       = L"Unspecified";
+
+// Log file properties
+const STRING MgLogManager::LogNameProperty      = L"LogNameProperty";
+const STRING MgLogManager::LogTypeProperty      = L"LogTypeProperty";
+const STRING MgLogManager::LogStatusProperty    = L"LogStatusProperty";
+
+// Log status strings
+const STRING MgLogManager::LogStatusActive      = L"Active";
+const STRING MgLogManager::LogStatusArchive     = L"Archive";
+
+// Constructor
+MgLogManager::MgLogManager() :
+    m_outputStream(NULL),
+    m_bAccessLogEnabled(true),
+    m_bAccessLogHeader(false),
+    m_AccessLogFileName(MgLogManager::DefaultAccessLogFileName),
+    m_bAdminLogEnabled(true),
+    m_bAdminLogHeader(false),
+    m_AdminLogFileName(MgLogManager::DefaultAdminLogFileName),
+    m_bAuthenticationLogEnabled(true),
+    m_bAuthenticationLogHeader(false),
+    m_AuthenticationLogFileName(MgLogManager::DefaultAuthenticationLogFileName),
+    m_bErrorLogEnabled(true),
+    m_bErrorLogHeader(false),
+    m_ErrorLogFileName(MgLogManager::DefaultErrorLogFileName),
+    m_bPerformanceLogEnabled(false),
+    m_bPerformanceLogHeader(false),
+    m_PerformanceLogFileName(MgLogManager::DefaultPerformanceLogFileName),
+    m_bSessionLogEnabled(true),
+    m_bSessionLogHeader(false),
+    m_SessionLogFileName(MgLogManager::DefaultSessionLogFileName),
+    m_bTraceLogEnabled(false),      // Disabled by default
+    m_bTraceLogHeader(false),
+    m_TraceLogFileName(MgLogManager::DefaultTraceLogFileName),
+    m_pLogThread(NULL),
+    m_writeCount(0)
+{
+}
+
+// Destructor
+MgLogManager::~MgLogManager()
+{
+    ACE_DEBUG ((LM_DEBUG, ACE_TEXT("(%t) MgLogManager::~MgLogManager()\n")));
+
+    // Close the logs
+    if(m_accessLogStream.is_open())
+    {
+        m_accessLogStream.close();
+    }
+
+    if(m_adminLogStream.is_open())
+    {
+        m_adminLogStream.close();
+    }
+
+    if(m_authenticationLogStream.is_open())
+    {
+        m_authenticationLogStream.close();
+    }
+
+    if(m_errorLogStream.is_open())
+    {
+        m_errorLogStream.close();
+    }
+
+    if(m_performanceLogStream.is_open())
+    {
+        m_performanceLogStream.close();
+    }
+
+    if(m_sessionLogStream.is_open())
+    {
+        m_sessionLogStream.close();
+    }
+
+    if(m_traceLogStream.is_open())
+    {
+        m_traceLogStream.close();
+    }
+
+    delete m_pLogThread;
+    m_pLogThread = NULL;
+}
+
+void MgLogManager::Dispose()
+{
+    delete this;
+}
+
+// Get pointer to a process-wide MgLogManager.
+MgLogManager* MgLogManager::GetInstance()
+{
+    MG_LOGMANAGER_TRY()
+
+    ACE_TRACE ("MgLogManager::GetInstance");
+
+    if (MgLogManager::m_logManager == NULL)
+    {
+        // Perform Double-Checked Locking Optimization.
+        ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, *ACE_Static_Object_Lock::instance (), 0));
+        if (MgLogManager::m_logManager == NULL)
+        {
+            MgLogManager::m_logManager = new MgLogManager;
+        }
+    }
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.GetInstance")
+
+    // To avoid overheads and maintain thread safety,
+    // do not assign this returned static singleton to a Ptr object.
+    return MgLogManager::m_logManager;
+}
+
+// Initialization
+void MgLogManager::Initialize()
+{
+    MG_LOGMANAGER_TRY()
+
+    m_applicationName = MgResources::ServerServiceDisplayName;
+
+    MgConfiguration* pConfiguration = MgConfiguration::GetInstance();
+
+    // Get the logs path
+    pConfiguration->GetStringValue(MgConfigProperties::GeneralPropertiesSection, MgConfigProperties::GeneralPropertyLogsPath, m_path, MgConfigProperties::DefaultGeneralPropertyLogsPath);
+
+    // Check if path ends with a '/' if not, add one if needed
+    MgFileUtil::AppendSlashToEndOfPath(m_path);
+
+    // Try and create the directory. If it already exists this will error and not a problem
+    ACE_OS::mkdir(MG_WCHAR_TO_TCHAR(m_path));
+
+    // Load the configuration properties
+    LoadConfigurationProperties();
+
+    // Create the logging thread
+    m_pLogThread = new MgLogThread(m_threadManager, 1);
+    m_pLogThread->Activate();
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.Initialize")
+}
+
+void MgLogManager::LoadConfigurationProperties()
+{
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex));
+
+    MgConfiguration* pConfiguration = MgConfiguration::GetInstance();
+
+    bool bLogEnabled;
+    STRING logFileName;
+    STRING logParameters;
+    STRING logDetail;
+
+    // Maximum log file size
+    pConfiguration->GetBoolValue(MgConfigProperties::GeneralPropertiesSection, MgConfigProperties::GeneralPropertyMaxLogFileSizeEnabled, m_useMaxLogSize, MgConfigProperties::DefaultGeneralPropertyMaxLogFileSizeEnabled);
+    pConfiguration->GetIntValue(MgConfigProperties::GeneralPropertiesSection, MgConfigProperties::GeneralPropertyMaxLogFileSize, m_maxLogSize, MgConfigProperties::DefaultGeneralPropertyMaxLogFileSize);
+    // Log data delimiter
+    pConfiguration->GetStringValue(MgConfigProperties::GeneralPropertiesSection, MgConfigProperties::GeneralPropertyLogsDelimiter, m_delimiter, MgConfigProperties::DefaultGeneralPropertyLogsDelimiter);
+    TranslateDelimiter();
+
+    // Logs detail level
+    pConfiguration->GetStringValue(MgConfigProperties::GeneralPropertiesSection, MgConfigProperties::GeneralPropertyLogsDetail, logDetail, MgConfigProperties::DefaultGeneralPropertyLogsDetail);
+    //m_logsDetail.resize(MgServerInformation::sm_knMaxNumberServices,0);
+    m_logsDetail.resize(11,0);
+    ParseLogService(MgServiceType::ResourceService, logDetail);
+    ParseLogService(MgServiceType::DrawingService, logDetail);
+    ParseLogService(MgServiceType::FeatureService, logDetail);
+    ParseLogService(MgServiceType::MappingService, logDetail);
+    ParseLogService(MgServiceType::RenderingService, logDetail);
+    ParseLogService(MgServiceType::TileService, logDetail);
+    ParseLogService(MgServiceType::KmlService, logDetail);
+    ParseLogService(MgServiceType::ServerAdminService, logDetail);
+    ParseLogService(MgServiceType::SiteService, logDetail);
+    ParseLogService(MgServiceType::ProfilingService, logDetail);
+
+    // Access Log
+    pConfiguration->GetBoolValue(MgConfigProperties::AccessLogPropertiesSection, MgConfigProperties::AccessLogPropertyEnabled, bLogEnabled, MgConfigProperties::DefaultAccessLogPropertyEnabled);
+    pConfiguration->GetStringValue(MgConfigProperties::AccessLogPropertiesSection, MgConfigProperties::AccessLogPropertyFilename, logFileName, MgConfigProperties::DefaultAccessLogPropertyFilename);
+    pConfiguration->GetStringValue(MgConfigProperties::AccessLogPropertiesSection, MgConfigProperties::AccessLogPropertyParameters, logParameters, MgConfigProperties::DefaultAccessLogPropertyParameters);
+    m_AccessLogParameters = logParameters;
+    m_AccessLogFileName = ValidateLogFileName(logFileName);
+    SetAccessLogEnabled(bLogEnabled);
+
+    // Admin Log
+    pConfiguration->GetBoolValue(MgConfigProperties::AdminLogPropertiesSection, MgConfigProperties::AdminLogPropertyEnabled, bLogEnabled, MgConfigProperties::DefaultAdminLogPropertyEnabled);
+    pConfiguration->GetStringValue(MgConfigProperties::AdminLogPropertiesSection, MgConfigProperties::AdminLogPropertyFilename, logFileName, MgConfigProperties::DefaultAdminLogPropertyFilename);
+    pConfiguration->GetStringValue(MgConfigProperties::AdminLogPropertiesSection, MgConfigProperties::AdminLogPropertyParameters, logParameters, MgConfigProperties::DefaultAdminLogPropertyParameters);
+    m_AdminLogParameters = logParameters;
+    m_AdminLogFileName = ValidateLogFileName(logFileName);
+    SetAdminLogEnabled(bLogEnabled);
+
+    // Authentication Log
+    pConfiguration->GetBoolValue(MgConfigProperties::AuthenticationLogPropertiesSection, MgConfigProperties::AuthenticationLogPropertyEnabled, bLogEnabled, MgConfigProperties::DefaultAuthenticationLogPropertyEnabled);
+    pConfiguration->GetStringValue(MgConfigProperties::AuthenticationLogPropertiesSection, MgConfigProperties::AuthenticationLogPropertyFilename, logFileName, MgConfigProperties::DefaultAuthenticationLogPropertyFilename);
+    pConfiguration->GetStringValue(MgConfigProperties::AuthenticationLogPropertiesSection, MgConfigProperties::AuthenticationLogPropertyParameters, logParameters, MgConfigProperties::DefaultAuthenticationLogPropertyParameters);
+    m_AuthenticationLogParameters = logParameters;
+    m_AuthenticationLogFileName = ValidateLogFileName(logFileName);
+    SetAuthenticationLogEnabled(bLogEnabled);
+
+    // Error Log
+    pConfiguration->GetBoolValue(MgConfigProperties::ErrorLogPropertiesSection, MgConfigProperties::ErrorLogPropertyEnabled, bLogEnabled, MgConfigProperties::DefaultErrorLogPropertyEnabled);
+    pConfiguration->GetStringValue(MgConfigProperties::ErrorLogPropertiesSection, MgConfigProperties::ErrorLogPropertyFilename, logFileName, MgConfigProperties::DefaultErrorLogPropertyFilename);
+    pConfiguration->GetStringValue(MgConfigProperties::ErrorLogPropertiesSection, MgConfigProperties::ErrorLogPropertyParameters, logParameters, MgConfigProperties::DefaultErrorLogPropertyParameters);
+    m_ErrorLogParameters = logParameters;
+    m_ErrorLogFileName = ValidateLogFileName(logFileName);
+    SetErrorLogEnabled(bLogEnabled);
+
+    // Performance Log
+    pConfiguration->GetBoolValue(MgConfigProperties::PerformanceLogPropertiesSection, MgConfigProperties::PerformanceLogPropertyEnabled, bLogEnabled, MgConfigProperties::DefaultPerformanceLogPropertyEnabled);
+    pConfiguration->GetStringValue(MgConfigProperties::PerformanceLogPropertiesSection, MgConfigProperties::PerformanceLogPropertyFilename, logFileName, MgConfigProperties::DefaultPerformanceLogPropertyFilename);
+    pConfiguration->GetStringValue(MgConfigProperties::PerformanceLogPropertiesSection, MgConfigProperties::PerformanceLogPropertyParameters, logParameters, MgConfigProperties::DefaultPerformanceLogPropertyParameters);
+    m_PerformanceLogParameters = logParameters;
+    m_PerformanceLogFileName = ValidateLogFileName(logFileName);
+    SetPerformanceLogEnabled(bLogEnabled);
+
+    // Session Log
+    pConfiguration->GetBoolValue(MgConfigProperties::SessionLogPropertiesSection, MgConfigProperties::SessionLogPropertyEnabled, bLogEnabled, MgConfigProperties::DefaultSessionLogPropertyEnabled);
+    pConfiguration->GetStringValue(MgConfigProperties::SessionLogPropertiesSection, MgConfigProperties::SessionLogPropertyFilename, logFileName, MgConfigProperties::DefaultSessionLogPropertyFilename);
+    pConfiguration->GetStringValue(MgConfigProperties::SessionLogPropertiesSection, MgConfigProperties::SessionLogPropertyParameters, logParameters, MgConfigProperties::DefaultSessionLogPropertyParameters);
+    m_SessionLogParameters = logParameters;
+    m_SessionLogFileName = ValidateLogFileName(logFileName);
+    SetSessionLogEnabled(bLogEnabled);
+
+    // Trace Log
+    pConfiguration->GetBoolValue(MgConfigProperties::TraceLogPropertiesSection, MgConfigProperties::TraceLogPropertyEnabled, bLogEnabled, MgConfigProperties::DefaultTraceLogPropertyEnabled);
+    pConfiguration->GetStringValue(MgConfigProperties::TraceLogPropertiesSection, MgConfigProperties::TraceLogPropertyFilename, logFileName, MgConfigProperties::DefaultTraceLogPropertyFilename);
+    pConfiguration->GetStringValue(MgConfigProperties::TraceLogPropertiesSection, MgConfigProperties::TraceLogPropertyParameters, logParameters, MgConfigProperties::DefaultTraceLogPropertyParameters);
+    m_TraceLogParameters = logParameters;
+    m_TraceLogFileName = ValidateLogFileName(logFileName);
+    SetTraceLogEnabled(bLogEnabled);
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.LoadConfigurationProperties")
+}
+
+STRING MgLogManager::GetLogsPath()
+{
+    return m_path;
+}
+
+STRING MgLogManager::ValidateLogFileName(CREFSTRING filename)
+{
+    if (filename.empty())
+    {
+        throw new MgNullArgumentException(L"MgLogManager.ValidateLogFileName", __LINE__, __WFILE__, NULL, L"", NULL);
+    }
+    if (STRING::npos != filename.find(L"\\") ||
+        STRING::npos != filename.find(L"/"))
+    {
+        // Does not support paths.  Must be a strict filename only.
+        MgStringCollection arguments;
+        arguments.Add(L"1");
+        arguments.Add(filename);
+
+        MgStringCollection whyArguments;
+        whyArguments.Add(L"\\/");
+
+        throw new MgInvalidArgumentException(L"MgLogManager.ValidateLogFileName",
+            __LINE__, __WFILE__, &arguments, L"MgStringContainsReservedCharacters", &whyArguments);
+    }
+
+    return (STRING)filename.c_str();
+}
+
+void MgLogManager::SetAccessLogInfo(bool bEnabled, CREFSTRING filename, CREFSTRING parameters)
+{
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex));
+
+    // Disable existing log in use if there is one
+    DisableLog(mltAccess);
+
+    SetAccessLogParameters(parameters);
+    SetAccessLogFileName(filename);
+    SetAccessLogEnabled(bEnabled);
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.SetAccessLogInfo");
+}
+
+bool MgLogManager::IsAccessLogEnabled()
+{
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, false));
+
+    return m_bAccessLogEnabled;
+}
+
+void MgLogManager::SetAccessLogEnabled(bool bEnabled)
+{
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex));
+
+    m_bAccessLogEnabled = bEnabled;
+    if(m_bAccessLogEnabled)
+    {
+        ValidateLogHeaders(mltAccess);
+        EnableLog(mltAccess);
+    }
+    else
+    {
+        DisableLog(mltAccess);
+    }
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.SetAccessLogEnabled")
+}
+
+STRING MgLogManager::GetAccessLogFileName()
+{
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, STRING(L"")));
+
+    return (STRING)m_AccessLogFileName.c_str();
+}
+
+void MgLogManager::SetAccessLogFileName(CREFSTRING filename)
+{
+    ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex));
+
+    DisableLog(mltAccess);
+    m_AccessLogFileName = ValidateLogFileName(filename);
+    EnableLog(mltAccess);
+}
+
+STRING MgLogManager::GetAccessLogParameters()
+{
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, STRING(L"")));
+
+    return (STRING)m_AccessLogParameters.c_str();
+}
+
+void MgLogManager::SetAccessLogParameters(CREFSTRING parameters)
+{
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex));
+
+    if (0 != parameters.compare(m_AccessLogParameters))
+    {
+        ArchiveLog(mltAccess);
+    }
+    m_AccessLogParameters = parameters.c_str();
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.SetAccessLogParameters")
+}
+
+bool MgLogManager::ClearAccessLog()
+{
+    bool bResult = false;
+
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, false));
+
+    // Disable the log which closes the log for us
+    DisableLog(mltAccess);
+
+    // Get the access log filename and path
+    STRING filename = BuildFileName(m_AccessLogFileName);
+    bResult = RemoveLogFile(filename);
+
+    // Enable the log which opens the log for us
+    EnableLog(mltAccess);
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.ClearAccessLog")
+
+    return bResult;
+}
+
+MgByteReader* MgLogManager::GetAccessLog()
+{
+    Ptr<MgByteReader> byteReader;
+
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, NULL));
+
+    // Disable the log which closes the log for us
+    DisableLog(mltAccess);
+
+    // Get the access log filename and path
+    STRING filename = BuildFileName(m_AccessLogFileName);
+    byteReader = GetLogContents(filename);
+
+    // Enable the log which opens the log for us
+    EnableLog(mltAccess);
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.GetAccessLog")
+
+    return byteReader.Detach();
+}
+
+MgByteReader* MgLogManager::GetAccessLog(INT32 numEntries)
+{
+    Ptr<MgByteReader> byteReader;
+
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, NULL));
+
+    // Disable the log which closes the log for us
+    DisableLog(mltAccess);
+
+    // Get the access log filename and path
+    STRING filename = BuildFileName(m_AccessLogFileName);
+    byteReader = GetLogContents(filename, numEntries);
+
+    // Enable the log which opens the log for us
+    EnableLog(mltAccess);
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.GetAccessLog")
+
+    return byteReader.Detach();
+}
+
+MgByteReader* MgLogManager::GetAccessLog(MgDateTime* fromDate, MgDateTime* toDate)
+{
+    Ptr<MgByteReader> byteReader;
+
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, NULL));
+
+    // Disable the log which closes the log for us
+    DisableLog(mltAccess);
+
+    byteReader = GetLogContents(mltAccess, fromDate, toDate);
+
+    // Enable the log which opens the log for us
+    EnableLog(mltAccess);
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.GetAccessLog")
+
+    return byteReader.Detach();
+}
+
+void MgLogManager::SetAdminLogInfo(bool bEnabled, CREFSTRING filename, CREFSTRING parameters)
+{
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex));
+
+    // Disable existing log in use if there is one
+    DisableLog(mltAdmin);
+
+    SetAdminLogParameters(parameters);
+    SetAdminLogFileName(filename);
+    SetAdminLogEnabled(bEnabled);
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.SetAdminLogInfo");
+}
+
+bool MgLogManager::IsAdminLogEnabled()
+{
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, false));
+
+    return m_bAdminLogEnabled;
+}
+
+void MgLogManager::SetAdminLogEnabled(bool bEnabled)
+{
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex));
+
+    m_bAdminLogEnabled = bEnabled;
+    if(m_bAdminLogEnabled)
+    {
+        ValidateLogHeaders(mltAdmin);
+        EnableLog(mltAdmin);
+    }
+    else
+    {
+        DisableLog(mltAdmin);
+    }
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.SetAdminLogEnabled")
+}
+
+STRING MgLogManager::GetAdminLogFileName()
+{
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, STRING(L"")));
+
+    return (STRING)m_AdminLogFileName.c_str();
+}
+
+void MgLogManager::SetAdminLogFileName(CREFSTRING filename)
+{
+    ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex));
+
+    DisableLog(mltAdmin);
+    m_AdminLogFileName = ValidateLogFileName(filename);
+    EnableLog(mltAdmin);
+}
+
+STRING MgLogManager::GetAdminLogParameters()
+{
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, STRING(L"")));
+
+    return (STRING)m_AdminLogParameters.c_str();
+}
+
+void MgLogManager::SetAdminLogParameters(CREFSTRING parameters)
+{
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex));
+
+    if (0 != parameters.compare(m_AdminLogParameters))
+    {
+        ArchiveLog(mltAdmin);
+    }
+    m_AdminLogParameters = parameters.c_str();
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.SetAdminLogParameters")
+}
+
+bool MgLogManager::ClearAdminLog()
+{
+    bool bResult = false;
+
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, false));
+
+    // Disable the log which closes the log for us
+    DisableLog(mltAdmin);
+
+    // Get the admin log filename and path
+    STRING filename = BuildFileName(m_AdminLogFileName);
+    bResult = RemoveLogFile(filename);
+
+    // Enable the log which opens the log for us
+    EnableLog(mltAdmin);
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.ClearAdminLog")
+
+    return bResult;
+}
+
+MgByteReader* MgLogManager::GetAdminLog()
+{
+    Ptr<MgByteReader> byteReader;
+
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, NULL));
+
+    // Disable the log which closes the log for us
+    DisableLog(mltAdmin);
+
+    // Get the admin log filename and path
+    STRING filename = BuildFileName(m_AdminLogFileName);
+    byteReader = GetLogContents(filename);
+
+    // Enable the log which opens the log for us
+    EnableLog(mltAdmin);
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.GetAdminLog")
+
+    return byteReader.Detach();
+}
+
+MgByteReader* MgLogManager::GetAdminLog(INT32 numEntries)
+{
+    Ptr<MgByteReader> byteReader;
+
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, NULL));
+
+    // Disable the log which closes the log for us
+    DisableLog(mltAdmin);
+
+    // Get the admin log filename and path
+    STRING filename = BuildFileName(m_AdminLogFileName);
+    byteReader = GetLogContents(filename, numEntries);
+
+    // Enable the log which opens the log for us
+    EnableLog(mltAdmin);
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.GetAdminLog")
+
+    return byteReader.Detach();
+}
+
+MgByteReader* MgLogManager::GetAdminLog(MgDateTime* fromDate, MgDateTime* toDate)
+{
+    Ptr<MgByteReader> byteReader;
+
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, NULL));
+
+    // Disable the log which closes the log for us
+    DisableLog(mltAdmin);
+
+    byteReader = GetLogContents(mltAdmin, fromDate, toDate);
+
+    // Enable the log which opens the log for us
+    EnableLog(mltAdmin);
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.GetAdminLog")
+
+    return byteReader.Detach();
+}
+
+void MgLogManager::SetAuthenticationLogInfo(bool bEnabled, CREFSTRING filename, CREFSTRING parameters)
+{
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex));
+
+    // Disable existing log in use if there is one
+    DisableLog(mltAuthentication);
+
+    SetAuthenticationLogParameters(parameters);
+    SetAuthenticationLogFileName(filename);
+    SetAuthenticationLogEnabled(bEnabled);
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.SetAuthenticationLogInfo");
+}
+
+bool MgLogManager::IsAuthenticationLogEnabled()
+{
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, false));
+
+    return m_bAuthenticationLogEnabled;
+}
+
+void MgLogManager::SetAuthenticationLogEnabled(bool bEnabled)
+{
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex));
+
+    m_bAuthenticationLogEnabled = bEnabled;
+    if(m_bAuthenticationLogEnabled)
+    {
+        ValidateLogHeaders(mltAuthentication);
+        EnableLog(mltAuthentication);
+    }
+    else
+    {
+        DisableLog(mltAuthentication);
+    }
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.SetAuthenticationLogEnabled")
+}
+
+STRING MgLogManager::GetAuthenticationLogFileName()
+{
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, STRING(L"")));
+
+    return (STRING)m_AuthenticationLogFileName.c_str();
+}
+
+void MgLogManager::SetAuthenticationLogFileName(CREFSTRING filename)
+{
+    ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex));
+
+    DisableLog(mltAuthentication);
+    m_AuthenticationLogFileName = ValidateLogFileName(filename);
+    EnableLog(mltAuthentication);
+}
+
+STRING MgLogManager::GetAuthenticationLogParameters()
+{
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, STRING(L"")));
+
+    return (STRING)m_AuthenticationLogParameters.c_str();
+}
+
+void MgLogManager::SetAuthenticationLogParameters(CREFSTRING parameters)
+{
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex));
+
+    if (0 != parameters.compare(m_AuthenticationLogParameters))
+    {
+        ArchiveLog(mltAuthentication);
+    }
+    m_AuthenticationLogParameters = parameters.c_str();
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.SetAuthenticationLogParameters")
+}
+
+bool MgLogManager::ClearAuthenticationLog()
+{
+    bool bResult = false;
+
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, false));
+
+    // Disable the log which closes the log for us
+    DisableLog(mltAuthentication);
+
+    // Get the authentication log filename and path
+    STRING filename = BuildFileName(m_AuthenticationLogFileName);
+    bResult = RemoveLogFile(filename);
+
+    // Enable the log which opens the log for us
+    EnableLog(mltAuthentication);
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.ClearAuthenticationLog")
+
+    return bResult;
+}
+
+MgByteReader* MgLogManager::GetAuthenticationLog()
+{
+    Ptr<MgByteReader> byteReader;
+
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, NULL));
+
+    // Disable the log which closes the log for us
+    DisableLog(mltAuthentication);
+
+    // Get the authentication log filename and path
+    STRING filename = BuildFileName(m_AuthenticationLogFileName);
+    byteReader = GetLogContents(filename);
+
+    // Enable the log which opens the log for us
+    EnableLog(mltAuthentication);
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.GetAuthenticationLog")
+
+    return byteReader.Detach();
+}
+
+MgByteReader* MgLogManager::GetAuthenticationLog(INT32 numEntries)
+{
+    Ptr<MgByteReader> byteReader;
+
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, NULL));
+
+    // Disable the log which closes the log for us
+    DisableLog(mltAuthentication);
+
+    // Get the authentication log filename and path
+    STRING filename = BuildFileName(m_AuthenticationLogFileName);
+    byteReader = GetLogContents(filename, numEntries);
+
+    // Enable the log which opens the log for us
+    EnableLog(mltAuthentication);
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.GetAuthenticationLog")
+
+    return byteReader.Detach();
+}
+
+MgByteReader* MgLogManager::GetAuthenticationLog(MgDateTime* fromDate, MgDateTime* toDate)
+{
+    Ptr<MgByteReader> byteReader;
+
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, NULL));
+
+    // Disable the log which closes the log for us
+    DisableLog(mltAuthentication);
+
+    byteReader = GetLogContents(mltAuthentication, fromDate, toDate);
+
+    // Enable the log which opens the log for us
+    EnableLog(mltAuthentication);
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.GetAuthenticationLog")
+
+    return byteReader.Detach();
+}
+
+
+void MgLogManager::SetErrorLogInfo(bool bEnabled, CREFSTRING filename, CREFSTRING parameters)
+{
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex));
+
+    // Disable existing log in use if there is one
+    DisableLog(mltError);
+
+    SetErrorLogParameters(parameters);
+    SetErrorLogFileName(filename);
+    SetErrorLogEnabled(bEnabled);
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.SetErrorLogInfo");
+}
+
+bool MgLogManager::IsErrorLogEnabled()
+{
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, false));
+
+    return m_bErrorLogEnabled;
+}
+
+void MgLogManager::SetErrorLogEnabled(bool bEnabled)
+{
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex));
+
+    m_bErrorLogEnabled = bEnabled;
+    if(m_bErrorLogEnabled)
+    {
+        ValidateLogHeaders(mltError);
+        EnableLog(mltError);
+    }
+    else
+    {
+        DisableLog(mltError);
+    }
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.SetErrorLogEnabled")
+}
+
+STRING MgLogManager::GetErrorLogFileName()
+{
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, STRING(L"")));
+
+    return (STRING)m_ErrorLogFileName.c_str();
+}
+
+void MgLogManager::SetErrorLogFileName(CREFSTRING filename)
+{
+    ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex));
+
+    DisableLog(mltError);
+    m_ErrorLogFileName = ValidateLogFileName(filename);
+    EnableLog(mltError);
+}
+
+STRING MgLogManager::GetErrorLogParameters()
+{
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, STRING(L"")));
+
+    return (STRING)m_ErrorLogParameters.c_str();
+}
+
+void MgLogManager::SetErrorLogParameters(CREFSTRING parameters)
+{
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex));
+
+    if (0 != parameters.compare(m_ErrorLogParameters))
+    {
+        ArchiveLog(mltError);
+    }
+    m_ErrorLogParameters = parameters.c_str();
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.SetErrorLogParameters")
+}
+
+bool MgLogManager::ClearErrorLog()
+{
+    bool bResult = false;
+
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, false));
+
+    // Disable the log which closes the log for us
+    DisableLog(mltError);
+
+    // Get the error log filename and path
+    STRING filename = BuildFileName(m_ErrorLogFileName);
+    bResult = RemoveLogFile(filename);
+
+    // Enable the log which opens the log for us
+    EnableLog(mltError);
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.ClearErrorLog")
+
+    return bResult;
+}
+
+MgByteReader* MgLogManager::GetErrorLog()
+{
+    Ptr<MgByteReader> byteReader;
+
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, NULL));
+
+    // Disable the log which closes the log for us
+    DisableLog(mltError);
+
+    // Get the error log filename and path
+    STRING filename = BuildFileName(m_ErrorLogFileName);
+    byteReader = GetLogContents(filename);
+
+    // Enable the log which opens the log for us
+    EnableLog(mltError);
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.GetErrorLog")
+
+    return byteReader.Detach();
+}
+
+MgByteReader* MgLogManager::GetErrorLog(INT32 numEntries)
+{
+    Ptr<MgByteReader> byteReader;
+
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, NULL));
+
+    // Disable the log which closes the log for us
+    DisableLog(mltError);
+
+    // Get the error log filename and path
+    STRING filename = BuildFileName(m_ErrorLogFileName);
+    byteReader = GetLogContents(filename, numEntries);
+
+    // Enable the log which opens the log for us
+    EnableLog(mltError);
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.GetErrorLog")
+
+    return byteReader.Detach();
+}
+
+MgByteReader* MgLogManager::GetErrorLog(MgDateTime* fromDate, MgDateTime* toDate)
+{
+    Ptr<MgByteReader> byteReader;
+
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, NULL));
+
+    // Disable the log which closes the log for us
+    DisableLog(mltError);
+
+    byteReader = GetLogContents(mltError, fromDate, toDate);
+
+    // Enable the log which opens the log for us
+    EnableLog(mltError);
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.GetErrorLog")
+
+    return byteReader.Detach();
+}
+
+void MgLogManager::SetPerformanceLogInfo(bool bEnabled, CREFSTRING filename, CREFSTRING parameters)
+{
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex));
+
+    // Disable existing log in use if there is one
+    DisableLog(mltError);
+
+    SetPerformanceLogParameters(parameters);
+    SetPerformanceLogFileName(filename);
+    SetPerformanceLogEnabled(bEnabled);
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.SetPerformanceLogInfo");
+}
+
+bool MgLogManager::IsPerformanceLogEnabled()
+{
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, false));
+
+    return m_bPerformanceLogEnabled;
+}
+
+void MgLogManager::SetPerformanceLogEnabled(bool bEnabled)
+{
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex));
+
+    m_bPerformanceLogEnabled = bEnabled;
+    if(m_bPerformanceLogEnabled)
+    {
+        ValidateLogHeaders(mltPerformance);
+        EnableLog(mltPerformance);
+    }
+    else
+    {
+        DisableLog(mltPerformance);
+    }
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.SetPerformanceLogEnabled")
+}
+
+STRING MgLogManager::GetPerformanceLogFileName()
+{
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, STRING(L"")));
+
+    return (STRING)m_PerformanceLogFileName.c_str();
+}
+
+void MgLogManager::SetPerformanceLogFileName(CREFSTRING filename)
+{
+    ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex));
+
+    DisableLog(mltPerformance);
+    m_PerformanceLogFileName = ValidateLogFileName(filename);
+    EnableLog(mltPerformance);
+}
+
+STRING MgLogManager::GetPerformanceLogParameters()
+{
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, STRING(L"")));
+
+    return (STRING)m_PerformanceLogParameters.c_str();
+}
+
+void MgLogManager::SetPerformanceLogParameters(CREFSTRING parameters)
+{
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex));
+
+    if (0 != parameters.compare(m_PerformanceLogParameters))
+    {
+        ArchiveLog(mltPerformance);
+    }
+    m_PerformanceLogParameters = parameters.c_str();
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.SetPerformanceLogParameters")
+}
+
+bool MgLogManager::ClearPerformanceLog()
+{
+    bool bResult = false;
+
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, false));
+
+    // Disable the log which closes the log for us
+    DisableLog(mltPerformance);
+
+    // Get the performance log filename and path
+    STRING filename = BuildFileName(m_PerformanceLogFileName);
+    bResult = RemoveLogFile(filename);
+
+    // Enable the log which opens the log for us
+    EnableLog(mltPerformance);
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.ClearPerformanceLog")
+
+    return bResult;
+}
+
+MgByteReader* MgLogManager::GetPerformanceLog()
+{
+    Ptr<MgByteReader> byteReader;
+
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, NULL));
+
+    // Disable the log which closes the log for us
+    DisableLog(mltPerformance);
+
+    // Get the performance log filename and path
+    STRING filename = BuildFileName(m_PerformanceLogFileName);
+    byteReader = GetLogContents(filename);
+
+    // Enable the log which opens the log for us
+    EnableLog(mltPerformance);
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.GetPerformanceLog")
+
+    return byteReader.Detach();
+}
+
+MgByteReader* MgLogManager::GetPerformanceLog(INT32 numEntries)
+{
+    Ptr<MgByteReader> byteReader;
+
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, NULL));
+
+    // Disable the log which closes the log for us
+    DisableLog(mltPerformance);
+
+    // Get the performance log filename and path
+    STRING filename = BuildFileName(m_PerformanceLogFileName);
+    byteReader = GetLogContents(filename, numEntries);
+
+    // Enable the log which opens the log for us
+    EnableLog(mltPerformance);
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.GetPerformanceLog")
+
+    return byteReader.Detach();
+}
+
+MgByteReader* MgLogManager::GetPerformanceLog(MgDateTime* fromDate, MgDateTime* toDate)
+{
+    Ptr<MgByteReader> byteReader;
+
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, NULL));
+
+    // Disable the log which closes the log for us
+    DisableLog(mltPerformance);
+
+    byteReader = GetLogContents(mltPerformance, fromDate, toDate);
+
+    // Enable the log which opens the log for us
+    EnableLog(mltPerformance);
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.GetPerformanceLog")
+
+    return byteReader.Detach();
+}
+
+void MgLogManager::SetSessionLogInfo(bool bEnabled, CREFSTRING filename, CREFSTRING parameters)
+{
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex));
+
+    // Disable existing log in use if there is one
+    DisableLog(mltSession);
+
+    SetSessionLogParameters(parameters);
+    SetSessionLogFileName(filename);
+    SetSessionLogEnabled(bEnabled);
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.SetSessionLogInfo");
+}
+
+bool MgLogManager::IsSessionLogEnabled()
+{
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, false));
+
+    return m_bSessionLogEnabled;
+}
+
+void MgLogManager::SetSessionLogEnabled(bool bEnabled)
+{
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex));
+
+    m_bSessionLogEnabled = bEnabled;
+    if(m_bSessionLogEnabled)
+    {
+        ValidateLogHeaders(mltSession);
+        EnableLog(mltSession);
+    }
+    else
+    {
+        DisableLog(mltSession);
+    }
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.SetSessionLogEnabled")
+}
+
+STRING MgLogManager::GetSessionLogFileName()
+{
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, STRING(L"")));
+
+    return (STRING)m_SessionLogFileName.c_str();
+}
+
+void MgLogManager::SetSessionLogFileName(CREFSTRING filename)
+{
+    ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex));
+
+    DisableLog(mltSession);
+    m_SessionLogFileName = ValidateLogFileName(filename);
+    EnableLog(mltSession);
+}
+
+STRING MgLogManager::GetSessionLogParameters()
+{
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, STRING(L"")));
+
+    return (STRING)m_SessionLogParameters.c_str();
+}
+
+void MgLogManager::SetSessionLogParameters(CREFSTRING parameters)
+{
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex));
+
+    if (0 != parameters.compare(m_SessionLogParameters))
+    {
+        ArchiveLog(mltSession);
+    }
+    m_SessionLogParameters = parameters.c_str();
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.SetSessionLogParameters")
+}
+
+bool MgLogManager::ClearSessionLog()
+{
+    bool bResult = false;
+
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, false));
+
+    // Disable the log which closes the log for us
+    DisableLog(mltSession);
+
+    // Get the session log filename and path
+    STRING filename = BuildFileName(m_SessionLogFileName);
+    bResult = RemoveLogFile(filename);
+
+    // Enable the log which opens the log for us
+    EnableLog(mltSession);
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.ClearSessionLog")
+
+    return bResult;
+}
+
+MgByteReader* MgLogManager::GetSessionLog()
+{
+    Ptr<MgByteReader> byteReader;
+
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, NULL));
+
+    // Disable the log which closes the log for us
+    DisableLog(mltSession);
+
+    // Get the session log filename and path
+    STRING filename = BuildFileName(m_SessionLogFileName);
+    byteReader = GetLogContents(filename);
+
+    // Enable the log which opens the log for us
+    EnableLog(mltSession);
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.GetSessionLog")
+
+    return byteReader.Detach();
+}
+
+MgByteReader* MgLogManager::GetSessionLog(INT32 numEntries)
+{
+    Ptr<MgByteReader> byteReader;
+
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, NULL));
+
+    // Disable the log which closes the log for us
+    DisableLog(mltSession);
+
+    // Get the session log filename and path
+    STRING filename = BuildFileName(m_SessionLogFileName);
+    byteReader = GetLogContents(filename, numEntries);
+
+    // Enable the log which opens the log for us
+    EnableLog(mltSession);
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.GetSessionLog")
+
+    return byteReader.Detach();
+}
+
+MgByteReader* MgLogManager::GetSessionLog(MgDateTime* fromDate, MgDateTime* toDate)
+{
+    Ptr<MgByteReader> byteReader;
+
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, NULL));
+
+    // Disable the log which closes the log for us
+    DisableLog(mltSession);
+
+    byteReader = GetLogContents(mltSession, fromDate, toDate);
+
+    // Enable the log which opens the log for us
+    EnableLog(mltSession);
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.GetSessionLog")
+
+    return byteReader.Detach();
+}
+
+void MgLogManager::SetTraceLogInfo(bool bEnabled, CREFSTRING filename, CREFSTRING parameters)
+{
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex));
+
+    // Disable existing log in use if there is one
+    DisableLog(mltTrace);
+
+    SetTraceLogParameters(parameters);
+    SetTraceLogFileName(filename);
+    SetTraceLogEnabled(bEnabled);
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.SetTraceLogInfo")
+}
+
+bool MgLogManager::IsTraceLogEnabled()
+{
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, false));
+
+    return m_bTraceLogEnabled;
+}
+
+void MgLogManager::SetTraceLogEnabled(bool bEnabled)
+{
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex));
+
+    m_bTraceLogEnabled = bEnabled;
+    if(m_bTraceLogEnabled)
+    {
+        ValidateLogHeaders(mltTrace);
+        EnableLog(mltTrace);
+    }
+    else
+    {
+        DisableLog(mltTrace);
+    }
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.SetTraceLogEnabled")
+}
+
+STRING MgLogManager::GetTraceLogFileName()
+{
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, STRING(L"")));
+
+    return (STRING)m_TraceLogFileName.c_str();
+}
+
+void MgLogManager::SetTraceLogFileName(CREFSTRING filename)
+{
+    ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex));
+
+    DisableLog(mltTrace);
+    m_TraceLogFileName = ValidateLogFileName(filename);
+    EnableLog(mltTrace);
+}
+
+STRING MgLogManager::GetTraceLogParameters()
+{
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, STRING(L"")));
+
+    return(STRING) m_TraceLogParameters.c_str();
+}
+
+void MgLogManager::SetTraceLogParameters(CREFSTRING parameters)
+{
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex));
+
+    if (0 != parameters.compare(m_TraceLogParameters))
+    {
+        ArchiveLog(mltTrace);
+    }
+    m_TraceLogParameters = parameters.c_str();
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.SetTraceLogParameters")
+}
+
+INT8 MgLogManager::GetDetailLevelForService(INT16 serviceNum)
+{
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, 0));
+
+    return m_logsDetail[serviceNum];
+}
+
+bool MgLogManager::ClearTraceLog()
+{
+    bool bResult = false;
+
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, false));
+
+    // Disable the log which closes the log for us
+    DisableLog(mltTrace);
+
+    // Get the trace log filename and path
+    STRING filename = BuildFileName(m_TraceLogFileName);
+    bResult = RemoveLogFile(filename);
+
+    // Enable the log which opens the log for us
+    EnableLog(mltTrace);
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.ClearTraceLog")
+
+    return bResult;
+}
+
+MgByteReader* MgLogManager::GetTraceLog()
+{
+    Ptr<MgByteReader> byteReader;
+
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, NULL));
+
+    // Disable the log which closes the log for us
+    DisableLog(mltTrace);
+
+    // Get the trace log filename and path
+    STRING filename = BuildFileName(m_TraceLogFileName);
+    byteReader = GetLogContents(filename);
+
+    // Enable the log which opens the log for us
+    EnableLog(mltTrace);
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.GetTraceLog")
+
+    return byteReader.Detach();
+}
+
+MgByteReader* MgLogManager::GetTraceLog(INT32 numEntries)
+{
+    Ptr<MgByteReader> byteReader;
+
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, NULL));
+
+    // Disable the log which closes the log for us
+    DisableLog(mltTrace);
+
+    // Get the trace log filename and path
+    STRING filename = BuildFileName(m_TraceLogFileName);
+    byteReader = GetLogContents(filename, numEntries);
+
+    // Enable the log which opens the log for us
+    EnableLog(mltTrace);
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.GetTraceLog")
+
+    return byteReader.Detach();
+}
+
+MgByteReader* MgLogManager::GetTraceLog(MgDateTime* fromDate, MgDateTime* toDate)
+{
+    Ptr<MgByteReader> byteReader;
+
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, NULL));
+
+    // Disable the log which closes the log for us
+    DisableLog(mltTrace);
+
+    byteReader = GetLogContents(mltTrace, fromDate, toDate);
+
+    // Enable the log which opens the log for us
+    EnableLog(mltTrace);
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.GetTraceLog")
+
+    return byteReader.Detach();
+}
+
+MgByteReader* MgLogManager::GetLogFile( CREFSTRING filename )
+{
+    Ptr<MgByteReader> byteReader;
+
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, NULL));
+
+    enum MgLogType logType = mltSystem; // Assign to log type not associated with a file
+
+    bool bInUse = IsLogFileInUse(filename, logType);
+    if(bInUse)
+    {
+        DisableLog(logType);
+    }
+
+    // Get the trace log filename and path
+    STRING fullPath = BuildFileName(filename);
+    byteReader = GetLogContents(fullPath);
+
+    if(bInUse)
+    {
+        EnableLog(logType);
+    }
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.GetLogFile")
+
+    return byteReader.Detach();
+}
+
+void MgLogManager::LogToSysLog(ACE_Log_Msg* pAce, char* application)
+{
+    ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex));
+
+    pAce->open(ACE_TEXT_CHAR_TO_TCHAR(application), ACE_Log_Msg::SYSLOG, ACE_TEXT_CHAR_TO_TCHAR(application));
+}
+
+void MgLogManager::LogToOStream(ACE_Log_Msg* pAce, ACE_OSTREAM_TYPE* output)
+{
+    ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex));
+
+    m_outputStream = output;
+    pAce->msg_ostream(m_outputStream);
+    pAce->clr_flags(ACE_Log_Msg::STDERR | ACE_Log_Msg::LOGGER | ACE_Log_Msg::SYSLOG);
+    pAce->set_flags(ACE_Log_Msg::OSTREAM);
+}
+
+void MgLogManager::LogToStderr(ACE_Log_Msg* pAce)
+{
+    ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex));
+
+    pAce->clr_flags(ACE_Log_Msg::OSTREAM | ACE_Log_Msg::LOGGER | ACE_Log_Msg::SYSLOG);
+    pAce->set_flags(ACE_Log_Msg::STDERR);
+}
+
+void MgLogManager::LogError(CREFSTRING entry, CREFSTRING client, CREFSTRING clientIp, CREFSTRING userName, CREFSTRING stackTrace)
+{
+    // Errors are always logged to both the error and trace logs if enabled.
+    if(IsErrorLogEnabled())
+    {
+        // Check if this is a startup/shutdown entry
+        if((MgResources::ServerStarted == entry) ||
+           (MgResources::ServerStopped == entry))
+        {
+            LogErrorEntry(entry, client, clientIp, userName, stackTrace, MgResources::Success);
+        }
+        else
+        {
+            LogErrorEntry(entry, client, clientIp, userName, stackTrace, MgResources::Error);
+        }
+    }
+    if(IsTraceLogEnabled())
+    {
+        LogTraceEntry(entry, client, clientIp, userName, stackTrace, MgResources::Error);
+    }
+}
+
+void MgLogManager::LogWarning(INT16 service, CREFSTRING entry, CREFSTRING client, CREFSTRING clientIp, CREFSTRING userName, CREFSTRING stackTrace)
+{
+    // Warnings are only logged if the detail level for the service is high enough.
+    INT8 detailLevel = GetDetailLevelForService(service);
+
+    if (detailLevel >= MgLogDetail::Warning)
+    {
+        // Log entries to both error log and trace log, if applicable
+        if(IsErrorLogEnabled())
+        {
+            LogErrorEntry(entry, client, clientIp, userName, stackTrace, MgResources::Warnings);
+        }
+        if(IsTraceLogEnabled())
+        {
+            LogTraceEntry(entry, client, clientIp, userName, stackTrace, MgResources::Warnings);
+        }
+    }
+}
+
+void MgLogManager::LogSystemEntry(ACE_Log_Priority priority, CREFSTRING entry)
+{
+    QueueLogEntry(mltSystem, entry, priority);
+}
+
+void MgLogManager::LogAccessEntry(CREFSTRING opId, CREFSTRING client, CREFSTRING clientIp, CREFSTRING userName)
+{
+    // Message to be entered into the log
+    STRING logEntry;
+
+    MG_LOGMANAGER_TRY()
+
+    // Current threadid is first parameter
+    AddThreadId(logEntry);
+
+    // Parse parameter string into an MgStringCollection
+    Ptr<MgStringCollection> paramList = MgStringCollection::ParseCollection(
+        GetAccessLogParameters().c_str(), L",");
+
+    // Go through parameter list and add the information appropriately
+    if (paramList != NULL)
+    {
+        INT32 numParams = paramList->GetCount();
+        STRING param;
+
+        for (INT32 i = 0; i < numParams; ++i)
+        {
+            param = paramList->GetItem(i);
+
+            if (MgLogManager::ClientParam == param)
+            {
+                AddClient(logEntry, client);
+            }
+            else if (MgLogManager::ClientIpParam == param)
+            {
+                AddClientIp(logEntry, clientIp);
+            }
+            else if (MgLogManager::UserParam == param)
+            {
+                AddUserName(logEntry, userName);
+            }
+            else if (MgLogManager::OpIdParam == param)
+            {
+                AddOpId(logEntry, opId);
+            }
+        }
+    }
+    else
+    {
+        // No parameters specified
+        // Use default message with just opId
+        AddOpId(logEntry, opId);
+    }
+
+    MG_LOGMANAGER_CATCH(L"MgLogManager.LogAccessEntry")
+
+    if (mgException != NULL)
+    {
+        // Use default message with just opId
+        logEntry.clear();
+        AddOpId(logEntry, opId);
+    }
+
+    QueueLogEntry(mltAccess, logEntry, LM_INFO);
+}
+
+void MgLogManager::LogAdminEntry(CREFSTRING opId, CREFSTRING client, CREFSTRING clientIp, CREFSTRING userName)
+{
+    // Message to be entered into the log
+    STRING logEntry;
+
+    MG_LOGMANAGER_TRY()
+
+    // Parse parameter string into an MgStringCollection
+    Ptr<MgStringCollection> paramList = MgStringCollection::ParseCollection(
+        GetAdminLogParameters().c_str(), L",");
+
+    // Go through parameter list and add the information appropriately
+    if (paramList != NULL)
+    {
+        INT32 numParams = paramList->GetCount();
+        STRING param;
+
+        for (INT32 i = 0; i < numParams; ++i)
+        {
+            param = paramList->GetItem(i);
+
+            if (MgLogManager::ClientParam == param)
+            {
+                AddClient(logEntry, client);
+            }
+            else if (MgLogManager::ClientIpParam == param)
+            {
+                AddClientIp(logEntry, clientIp);
+            }
+            else if (MgLogManager::UserParam == param)
+            {
+                AddUserName(logEntry, userName);
+            }
+            else if (MgLogManager::OpIdParam == param)
+            {
+                AddOpId(logEntry, opId);
+            }
+        }
+    }
+    else
+    {
+        // No parameters specified
+        // Use default message with just opId
+        AddOpId(logEntry, opId);
+    }
+
+    MG_LOGMANAGER_CATCH(L"MgLogManager.LogAdminEntry")
+
+    if (mgException != NULL)
+    {
+        // Use default message with just opId
+        logEntry.clear();
+        AddOpId(logEntry, opId);
+    }
+
+    QueueLogEntry(mltAdmin, logEntry, LM_INFO);
+}
+
+void MgLogManager::LogAuthenticationEntry(CREFSTRING entry, CREFSTRING client, CREFSTRING clientIp, CREFSTRING userName)
+{
+    // Message to be entered into the log
+    STRING logEntry;
+
+    MG_LOGMANAGER_TRY()
+
+    // Parse parameter string into an MgStringCollection
+    Ptr<MgStringCollection> paramList = MgStringCollection::ParseCollection(
+        GetAuthenticationLogParameters().c_str(), L",");
+
+    // Go through parameter list and add the information appropriately
+    if (paramList != NULL)
+    {
+        INT32 numParams = paramList->GetCount();
+        STRING param;
+
+        for (INT32 i = 0; i < numParams; ++i)
+        {
+            param = paramList->GetItem(i);
+
+            if (MgLogManager::ClientParam == param)
+            {
+                AddClient(logEntry, client);
+            }
+            else if (MgLogManager::ClientIpParam == param)
+            {
+                AddClientIp(logEntry, clientIp);
+            }
+            else if (MgLogManager::UserParam == param)
+            {
+                AddUserName(logEntry, userName);
+            }
+        }
+    }
+
+    // Add the given info.
+    AddDelimiter(logEntry);
+    logEntry += entry;
+
+    MG_LOGMANAGER_CATCH(L"MgLogManager.LogAuthenticationEntry")
+
+    if (mgException != NULL)
+    {
+        // Use default message with just the given info.
+        // TODO: Create actual default message when it's known what will go in this log
+        logEntry = entry;
+    }
+
+    QueueLogEntry(mltAuthentication, logEntry, LM_INFO);
+}
+
+void MgLogManager::LogErrorEntry(CREFSTRING entry, CREFSTRING client, CREFSTRING clientIp, CREFSTRING userName, CREFSTRING stackTrace, CREFSTRING type)
+{
+    // Message to be entered into the log
+    STRING logEntry;
+
+    MG_LOGMANAGER_TRY()
+
+    // Current threadid is first parameter
+    AddThreadId(logEntry);
+
+    // Parse parameter string into an MgStringCollection
+    Ptr<MgStringCollection> paramList = MgStringCollection::ParseCollection(
+        GetErrorLogParameters().c_str(), L",");
+
+    // Go through parameter list and add the information appropriately
+    if (paramList != NULL)
+    {
+        INT32 numParams = paramList->GetCount();
+        STRING param;
+
+        for (INT32 i = 0; i < numParams; ++i)
+        {
+            param = paramList->GetItem(i);
+
+            if (MgLogManager::ClientParam == param)
+            {
+                AddClient(logEntry, client);
+            }
+            else if (MgLogManager::ClientIpParam == param)
+            {
+                AddClientIp(logEntry, clientIp);
+            }
+            else if (MgLogManager::UserParam == param)
+            {
+                AddUserName(logEntry, userName);
+            }
+            else if (MgLogManager::ErrorParam == param)
+            {
+                AddError(logEntry, entry, type);
+            }
+            else if (MgLogManager::StackTraceParam == param)
+            {
+                AddStackTrace(logEntry, stackTrace);
+            }
+        }
+    }
+
+    // Add the given info.
+    AddDelimiter(logEntry);
+
+    MG_LOGMANAGER_CATCH(L"MgLogManager.LogErrorEntry")
+
+    if (mgException != NULL)
+    {
+        // Use default message with just the given info.
+        // TODO: Create actual default message when it's known what will go in this log
+        logEntry = entry;
+    }
+
+    QueueLogEntry(mltError, logEntry, LM_ERROR);
+}
+
+void MgLogManager::LogTraceEntry(CREFSTRING entry, CREFSTRING client, CREFSTRING clientIp, CREFSTRING userName, CREFSTRING stackTrace, CREFSTRING type)
+{
+    // Message to be entered into the log
+    STRING logEntry;
+
+    MG_LOGMANAGER_TRY()
+
+    // Current threadid is first parameter
+    AddThreadId(logEntry);
+
+    // Parse parameter string into an MgStringCollection
+    Ptr<MgStringCollection> paramList = MgStringCollection::ParseCollection(
+        GetTraceLogParameters().c_str(), L",");
+
+    // Go through parameter list and add the information appropriately
+    if (paramList != NULL)
+    {
+        INT32 numParams = paramList->GetCount();
+        STRING param;
+
+        for (INT32 i = 0; i < numParams; ++i)
+        {
+            param = paramList->GetItem(i);
+
+            if (MgLogManager::ClientParam == param)
+            {
+                AddClient(logEntry, client);
+            }
+            else if (MgLogManager::ClientIpParam == param)
+            {
+                AddClientIp(logEntry, clientIp);
+            }
+            else if (MgLogManager::UserParam == param)
+            {
+                AddUserName(logEntry, userName);
+            }
+            else if (MgLogManager::InfoParam == param)
+            {
+                if (type.compare(L"") == 0)
+                {
+                    AddInfo(logEntry, entry);
+                }
+                else
+                {
+                    AddError(logEntry, entry, type);
+                }
+             }
+            else if (MgLogManager::StackTraceParam == param)
+            {
+                if (!logEntry.empty())
+                {
+                    AddStackTrace(logEntry, stackTrace);
+                }
+            }
+        }
+    }
+
+    MG_LOGMANAGER_CATCH(L"MgLogManager.LogTraceEntry")
+
+    if (mgException != NULL)
+    {
+        // Use default message with just the given info.
+        // TODO: Create actual default message when it's known what will go in this log
+        logEntry = entry;
+    }
+
+    QueueLogEntry(mltTrace, logEntry, LM_INFO);
+}
+
+void MgLogManager::LogSystemErrorEntry(MgException* except)
+{
+    if (NULL != except)
+    {
+        //MgServerManager* serverManager = MgServerManager::GetInstance();
+        //ACE_ASSERT(NULL != serverManager);
+
+        //STRING locale = serverManager->GetDefaultMessageLocale();
+        STRING locale = MgResources::DefaultMessageLocale;
+        STRING message = except->GetExceptionMessage(locale);
+        STRING details = except->GetDetails(locale);
+        STRING stackTrace = except->GetStackTrace(locale);
+
+        ACE_DEBUG((LM_ERROR, ACE_TEXT("(%t) %W\n"), details.c_str()));
+        MG_LOG_SYSTEM_ENTRY(LM_ERROR, details.c_str());
+        MG_LOG_EXCEPTION_ENTRY(message.c_str(), stackTrace.c_str());
+    }
+}
+
+MgPropertyCollection* MgLogManager::EnumerateLogs()
+{
+    Ptr<MgPropertyCollection> logs;
+    ACE_DIR* directory = NULL;
+
+    MG_LOGMANAGER_TRY()
+
+    logs = new MgPropertyCollection(true, true);
+
+    // Open the logs directory
+    directory = ACE_OS::opendir(MG_WCHAR_TO_TCHAR(m_path));
+    if (directory == NULL)
+    {
+        MgStringCollection arguments;
+        arguments.Add(m_path);
+        throw new MgFileIoException(L"MgLogManager.EnumerateLogs", __LINE__, __WFILE__, &arguments, L"", NULL);
+    }
+
+    dirent* direntry = NULL;
+
+    wstring name;
+    STRING path;
+    int statResult;
+#ifdef _WIN32
+    struct _stat statBuf;
+#else
+    struct stat statBuf;
+#endif
+
+    // Go through the directory entries
+    Ptr<MgStringProperty> pProperty;
+    while ((direntry = ACE_OS::readdir(directory)) != NULL)
+    {
+        name = MG_TCHAR_TO_WCHAR(direntry->d_name);
+        path = m_path + name;
+
+#ifdef _WIN32
+        statResult = ::_wstat(path.c_str(), &statBuf);
+#else
+        statResult = ::stat(MgUtil::WideCharToMultiByte(path).c_str(),
+            &statBuf);
+#endif
+        // Add to list of log files if it is a file and not a folder
+        if (statResult == 0 && (statBuf.st_mode & S_IFREG))
+        {
+            pProperty = new MgStringProperty(MgLogManager::LogNameProperty, name);
+            logs->Add(pProperty);
+
+            // Is the log in use?
+            enum MgLogType logType = mltSystem;
+            bool bInUse = IsLogFileInUse(name, logType);
+            if(bInUse)
+            {
+                DisableLog(logType);
+            }
+
+            // Add the log type
+            wstring type = ReadLogTypeFromLogFile(path);
+            pProperty = new MgStringProperty(MgLogManager::LogTypeProperty, type);
+            logs->Add(pProperty);
+
+            if(bInUse)
+            {
+                EnableLog(logType);
+            }
+
+            // Add the log status
+            wstring status = DetermineLogFileStatus(name, type);
+            pProperty = new MgStringProperty(MgLogManager::LogStatusProperty, status);
+            logs->Add(pProperty);
+        }
+    }
+
+    ACE_OS::closedir(directory);
+
+    MG_LOGMANAGER_CATCH(L"MgLogManager.EnumerateLogs")
+    if (mgException != NULL)
+    {
+        if (directory != NULL)
+        {
+            ACE_OS::closedir(directory);
+        }
+        (*mgException).AddRef();
+        mgException->Raise();
+    }
+
+    return logs.Detach();
+}
+
+
+void MgLogManager::RenameLog(CREFSTRING oldFileName, CREFSTRING newFileName)
+{
+    if (oldFileName.empty() || newFileName.empty())
+    {
+        throw new MgNullArgumentException(L"MgLogManager.RenameLog", __LINE__, __WFILE__, NULL, L"", NULL);
+    }
+
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex));
+
+    enum MgLogType logType = mltSystem;
+    bool bInUse = IsLogFileInUse(oldFileName, logType);
+    if(bInUse)
+    {
+        DisableLog(logType);
+    }
+
+    // Rename the log file
+    MgFileUtil::RenameFile(m_path, oldFileName, newFileName);
+
+    if(bInUse)
+    {
+        EnableLog(logType);
+    }
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.RenameLog")
+}
+
+void MgLogManager::DeleteLog(CREFSTRING fileName)
+{
+    if (fileName.empty())
+    {
+        throw new MgNullArgumentException(L"MgLogManager.DeleteLog", __LINE__, __WFILE__, NULL, L"", NULL);
+    }
+
+    if (STRING::npos != fileName.find(L"\\") ||
+        STRING::npos != fileName.find(L"/"))
+    {
+        MgStringCollection arguments;
+        arguments.Add(L"1");
+        arguments.Add(fileName);
+
+        MgStringCollection whyArguments;
+        whyArguments.Add(L"\\/");
+
+        throw new MgInvalidArgumentException(L"MgLogManager.DeleteLog",
+            __LINE__, __WFILE__, &arguments, L"MgStringContainsReservedCharacters", &whyArguments);
+    }
+
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex));
+
+    enum MgLogType logType = mltSystem;
+    bool bInUse = IsLogFileInUse(fileName, logType);
+    if(bInUse)
+    {
+        DisableLog(logType);
+    }
+
+    MgFileUtil::DeleteFile((STRING)m_path.c_str()+(STRING)fileName.c_str());
+
+    if(bInUse)
+    {
+        EnableLog(logType);
+    }
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.DeleteLog")
+}
+
+void MgLogManager::QueueLogEntry(enum MgLogType logType, CREFSTRING message, ACE_Log_Priority logPriority)
+{
+    // Do NOT queue the log entry if the Log Manager has not been initialized.
+    // This is likely due to problems with the server configuration.
+    if (NULL == m_pLogThread)
+    {
+        return;
+    }
+
+    MG_LOGMANAGER_TRY()
+
+    // We want the log thread to handle the log entry for us
+    MgLogEntryData* led = NULL;
+    ACE_Allocator* allocator = ACE_Allocator::instance();
+    ACE_NEW_MALLOC_NORETURN (led,
+        static_cast<MgLogEntryData*> (allocator->malloc(sizeof(MgLogEntryData))),
+        MgLogEntryData(logType, message, logPriority) );
+
+    //ACE_NEW_NORETURN( led, MgLogEntryData(logType, message, logPriority) );
+
+    ACE_Message_Block* mb;
+    ACE_NEW_NORETURN( mb, ACE_Message_Block( led ) );
+    if(mb)
+    {
+        mb->msg_type(ACE_Message_Block::MB_DATA);
+        int nResult = m_pLogThread->putq(mb);
+        if(nResult == -1)
+        {
+            // Failed to queue the message
+            STRING messageId;
+            MgStringCollection arguments;
+
+            arguments.Add(L"Failed to queue ACE_Message_Block.");
+            messageId = L"MgFormatInnerExceptionMessage";
+
+            MgException* mgException = new MgRuntimeException(L"MgLogManager.QueueLogEntry", __LINE__, __WFILE__, NULL, messageId, &arguments);
+            throw mgException;
+        }
+    }
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.QueueLogEntry")
+}
+
+void MgLogManager::StopLogThread()
+{
+    // Do NOT stop the log thread if the Log Manager has not been initialized.
+    // This is likely due to problems with the server configuration.
+    if (NULL != m_pLogThread)
+    {
+        // Tell the log thread to stop
+        ACE_Message_Block* mb = new ACE_Message_Block(4);
+        if(mb)
+        {
+            mb->msg_type(ACE_Message_Block::MB_STOP);
+            m_pLogThread->putq(mb);
+        }
+
+        // Wait for thread to process STOP
+        m_pLogThread->wait();
+    }
+
+    m_threadManager.wait(0,1);
+    m_threadManager.close();
+}
+
+void MgLogManager::WriteLogMessage(enum MgLogType logType, CREFSTRING message, ACE_Log_Priority logPriority)
+{
+    ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex));
+
+    ACE_Log_Msg* pAce = ACE_Log_Msg::instance();
+
+    // System message gets logged to event log
+    if (logType == mltSystem)
+    {
+        pAce->acquire();
+
+        MG_LOGMANAGER_TRY()
+
+        string appName = MgUtil::WideCharToMultiByte(m_applicationName);
+        wchar_t* messageStr = (wchar_t*) message.c_str();
+
+        LogToSysLog(pAce, (char *)appName.c_str());
+#ifdef _WIN32
+        pAce->log(logPriority, ACE_TEXT("%Z\r\n"), message.c_str()); // WAS %W
+#else
+        pAce->log(logPriority, ACE_TEXT("%Z\n"), messageStr); // WAS %W
+#endif
+        LogToStderr(pAce);
+
+        MG_LOGMANAGER_CATCH(L"MgLogManager.WriteLogMessage")
+
+        if (mgException != NULL)
+        {
+            STRING entry = L"Unable to log system message";
+            LogError(entry, L"", L"", L"");
+        }
+
+        pAce->release();
+    }
+    // All other messages will get logged to their respective files
+    else
+    {
+        std::ofstream* pLogStream = NULL;
+
+        bool bEnabled = false;
+        STRING filename;
+        STRING logTypeName;
+        STRING logParameters;
+
+        switch (logType)
+        {
+        case mltAccess:
+            // Get the access log filename and path
+            filename = BuildFileName(m_AccessLogFileName);
+            logTypeName = MgLogManager::AccessLog;
+            logParameters = GetAccessLogParameters();
+            pLogStream = &m_accessLogStream;
+            bEnabled = m_bAccessLogEnabled;
+            break;
+        case mltAdmin:
+            // Get the admin log filename and path
+            filename = BuildFileName(m_AdminLogFileName);
+            logTypeName = MgLogManager::AdminLog;
+            logParameters = GetAdminLogParameters();
+            pLogStream = &m_adminLogStream;
+            bEnabled = m_bAdminLogEnabled;
+            break;
+        case mltAuthentication:
+            // Get the authentication log filename and path
+            filename = BuildFileName(m_AuthenticationLogFileName);
+            logTypeName = MgLogManager::AuthenticationLog;
+            logParameters = GetAuthenticationLogParameters();
+            pLogStream = &m_authenticationLogStream;
+            bEnabled = m_bAuthenticationLogEnabled;
+            break;
+        case mltError:
+            // Get the error log filename and path
+            filename = BuildFileName(m_ErrorLogFileName);
+            logTypeName = MgLogManager::ErrorLog;
+            logParameters = GetErrorLogParameters();
+            pLogStream = &m_errorLogStream;
+            bEnabled = m_bErrorLogEnabled;
+            break;
+        case mltPerformance:
+            // Get the performance log filename and path
+            filename = BuildFileName(m_PerformanceLogFileName);
+            logTypeName = MgLogManager::PerformanceLog;
+            logParameters = GetPerformanceLogParameters();
+            pLogStream = &m_performanceLogStream;
+            bEnabled = m_bPerformanceLogEnabled;
+            break;
+        case mltSession:
+            // Get the session log filename and path
+            filename = BuildFileName(m_SessionLogFileName);
+            logTypeName = MgLogManager::SessionLog;
+            logParameters = GetSessionLogParameters();
+            pLogStream = &m_sessionLogStream;
+            bEnabled = m_bSessionLogEnabled;
+            break;
+        case mltTrace:
+            // Get the trace log file and path
+            filename = BuildFileName(m_TraceLogFileName);
+            logTypeName = MgLogManager::TraceLog;
+            logParameters = GetTraceLogParameters();
+            pLogStream = &m_traceLogStream;
+            bEnabled = m_bTraceLogEnabled;
+            break;
+        default:
+            {
+                STRING buffer;
+                MgUtil::Int32ToString(logType, buffer);
+
+                MgStringCollection arguments;
+                arguments.Add(L"1");
+                arguments.Add(buffer);
+
+                throw new MgInvalidArgumentException(L"MgLogManager.WriteLogMessage",
+                    __LINE__, __WFILE__, &arguments, L"MgInvalidLogType", NULL);
+            }
+        }
+
+        // Check to see if the log is still open
+        if(bEnabled)
+        {
+            if(pLogStream)
+            {
+                pAce->acquire();
+
+                MG_LOGMANAGER_TRY()
+
+                // This is an expensive check, only do it occasionally
+                // First time, cache all the error log time stamps, then cache is updated when archive is created.
+                if (0 == m_writeCount)
+                {
+                    UpdateLogFilesTimestampCache();
+                }
+
+                // CheckArchiveFrequency for every write
+                m_writeCount++;
+                if (false == CheckArchiveFrequency(logType, filename))
+                {
+                    ArchiveLog(logType);
+                }
+
+                if (!pLogStream->is_open())
+                {
+                    MgStringCollection arguments;
+                    arguments.Add(filename);
+                    throw new MgFileIoException(L"MgLogManager.WriteLogMessage", __LINE__, __WFILE__, &arguments, L"", NULL);
+                }
+
+                LogToOStream(pAce, pLogStream);
+
+                if(!LogHasHeader(logType))
+                {
+                    // Write file header information if the log is empty
+                    bool bLogFileEmpty = true;
+                    bLogFileEmpty =  (MgFileUtil::GetFileSize(filename) ? false : true);
+                    if (bLogFileEmpty)
+                    {
+                        STRING headerLine1 = MgLogManager::HeaderLine1 + L" ";
+                        headerLine1 += logTypeName;
+                        STRING headerLine2 = MgLogManager::HeaderLine2 + L" ";
+                        headerLine2 += logParameters;
+#ifdef _WIN32
+                        pAce->log(logPriority, ACE_TEXT("%W\r\n"), headerLine1.c_str());
+                        pAce->log(logPriority, ACE_TEXT("%W\r\n"), headerLine2.c_str());
+#else
+                        pAce->log(logPriority, ACE_TEXT("%W\n"), headerLine1.c_str());
+                        pAce->log(logPriority, ACE_TEXT("%W\n"), headerLine2.c_str());
+#endif
+                        SetLogHasHeader(logType, true);
+                    }  // end write file header
+                }
+
+                // Get the current time in XML standard format.
+                MgDateTime currTime;
+                if (mltTrace != logType)
+                {
+                    // Generate sub-second timing only for trace log
+                    currTime.SetMicrosecond(0);
+                }
+                STRING logTime = currTime.ToXmlString(false);
+
+#ifdef _WIN32
+                pAce->log(logPriority, ACE_TEXT("<%W> %W\r\n"), logTime.c_str(), message.c_str());
+#else
+                pAce->log(logPriority, ACE_TEXT("<%W> %W\n"), logTime.c_str(), message.c_str());
+#endif
+                pLogStream->flush();
+                LogToStderr(pAce);
+
+                MG_LOGMANAGER_CATCH(L"MgLogManager.WriteLogMessage")
+
+                if (mgException != 0 && logType != mltError)
+                {
+                    STRING entry = L"Unable to log message to " + filename;
+                    LogError(entry, L"", L"", L"");
+                }
+
+                // Check if log size has exceeded the maximum size
+                if (IsMaximumLogSizeEnabled() && IsMaxSizeExceeded(filename))
+                {
+                    // Archive the current log
+                    ArchiveLog(logType);
+                }
+
+                pAce->release();
+            }
+        }
+    } // end else
+}
+
+bool MgLogManager::RemoveLogFile(CREFSTRING filename)
+{
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, false));
+
+    // Does the file exist? If so remove it.
+    int nResult = ACE_OS::unlink(MG_WCHAR_TO_TCHAR(filename));
+    if(nResult == -1)
+    {
+        // Check to see if the error is a result of the file not found.
+        if(ENOENT == errno)
+        {
+            // File not found, so this method was successful as there was no log to remove
+            nResult = 0;
+        }
+    }
+
+    return (nResult == 0) ? true : false;
+}
+
+MgByteReader* MgLogManager::GetLogHeader(enum MgLogType logType)
+{
+    Ptr<MgByteReader> byteReader;
+    byteReader = NULL;
+
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, NULL));
+
+    STRING filename = L"";
+
+    switch(logType)
+    {
+    case mltAccess:
+        filename = BuildFileName(m_AccessLogFileName);
+        break;
+    case mltAdmin:
+        filename = BuildFileName(m_AdminLogFileName);
+        break;
+    case mltAuthentication:
+        filename = BuildFileName(m_AuthenticationLogFileName);
+        break;
+    case mltError:
+        filename = BuildFileName(m_ErrorLogFileName);
+        break;
+    case mltPerformance:
+        filename = BuildFileName(m_PerformanceLogFileName);
+        break;
+    case mltSession:
+        filename = BuildFileName(m_SessionLogFileName);
+        break;
+    case mltTrace:
+        filename = BuildFileName(m_TraceLogFileName);
+        break;
+    default:
+        {
+            STRING buffer;
+            MgUtil::Int32ToString(logType, buffer);
+
+            MgStringCollection arguments;
+            arguments.Add(L"1");
+            arguments.Add(buffer);
+
+            throw new MgInvalidArgumentException(L"MgLogManager.GetLogHeader",
+                __LINE__, __WFILE__, &arguments, L"MgInvalidLogType", NULL);
+        }
+    }
+
+    bool bInUse = IsLogInUse(logType);
+    if(bInUse)
+    {
+        DisableLog(logType);
+    }
+
+    byteReader = GetLogHeader(filename);
+
+    if(bInUse)
+    {
+        EnableLog(logType);
+    }
+
+    MG_LOGMANAGER_CATCH(L"MgLogManager.GetLogHeader")
+
+    return byteReader.Detach();
+}
+
+MgByteReader* MgLogManager::GetLogHeader(CREFSTRING filename)
+{
+    Ptr<MgByteReader> byteReader;
+    byteReader = NULL;
+    FILE* pReadFile = NULL;
+    string contents = "";
+
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, NULL));
+
+    pReadFile = ACE_OS::fopen(MG_WCHAR_TO_TCHAR(filename), ACE_TEXT("rb"));
+
+    if (pReadFile != NULL)
+    {
+        const int size = 2048;
+        char buffer[2048] = {0};
+
+        ACE_OS::fread(buffer, sizeof(char), size-1, pReadFile);
+        contents = buffer;
+
+        ACE_OS::fclose(pReadFile);
+    }
+
+    byteReader = MgUtil::GetByteReader(contents);
+
+    MG_LOGMANAGER_CATCH(L"MgLogManager.GetLogHeader")
+    if (mgException != NULL)
+    {
+        if (pReadFile != NULL)
+        {
+            ACE_OS::fclose(pReadFile);
+        }
+        (*mgException).AddRef();
+        mgException->Raise();
+    }
+
+    return byteReader.Detach();
+}
+
+MgByteReader* MgLogManager::GetLogContents(CREFSTRING filename)
+{
+    Ptr<MgByteReader> byteReader;
+    byteReader = NULL;
+    FILE* pReadFile = NULL;
+    string contents = "";
+
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, NULL));
+
+    pReadFile = ACE_OS::fopen(MG_WCHAR_TO_TCHAR(filename), ACE_TEXT("rb"));
+
+    if (pReadFile != NULL)
+    {
+        ACE_OS::fseek(pReadFile, 0, SEEK_END);
+        INT32 length = ACE_OS::ftell(pReadFile);
+        ACE_OS::fseek(pReadFile, 0, SEEK_SET);
+
+        //TODO: do we need a maximum size restriction?
+        char* buffer = new char[length+1];
+
+        if (buffer == NULL)
+        {
+            ACE_OS::fclose(pReadFile);
+            throw new MgOutOfMemoryException(L"MgLogManager.GetLogContents", __LINE__, __WFILE__, NULL, L"", NULL);
+        }
+
+        // Clear buffer
+        memset(buffer, 0, (length+1)*sizeof(char));
+
+        ACE_OS::fread(buffer, sizeof(char), length*sizeof(char), pReadFile);
+        contents = buffer;
+
+        // Clean up buffer
+        delete [] buffer;
+        buffer = NULL;
+
+        ACE_OS::fclose(pReadFile);
+    }
+
+    byteReader = MgUtil::GetByteReader(contents);
+
+    MG_LOGMANAGER_CATCH(L"MgLogManager.GetLogContents")
+    if (mgException != NULL)
+    {
+        if (pReadFile != NULL)
+        {
+            ACE_OS::fclose(pReadFile);
+        }
+        (*mgException).AddRef();
+        mgException->Raise();
+    }
+
+    return byteReader.Detach();
+}
+
+MgByteReader* MgLogManager::GetLogContents(CREFSTRING filename, INT32 numEntries)
+{
+    Ptr<MgByteReader> byteReader;
+    byteReader = NULL;
+    FILE* pReadFile = NULL;
+    Ptr<MgByteSource> byteSource;
+    byteSource = NULL;
+    string contents = "";
+
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, NULL));
+
+    if (numEntries < 0)
+    {
+        throw new  MgArgumentOutOfRangeException(L"MgLogManager.GetLogContents", __LINE__, __WFILE__, NULL, L"", NULL);
+    }
+
+    INT32 lastPos;      // Keeps track of the position in the file
+    INT32 numNewLines;  // Keep track of the number of entries found so far
+    char buffer[MAX_BUF+1];
+    bool bReadMore;
+
+    pReadFile = ACE_OS::fopen(MG_WCHAR_TO_TCHAR(filename), ACE_TEXT("rb"));
+    if (pReadFile != NULL)
+    {
+        ACE_OS::fseek(pReadFile, 0, SEEK_END);
+        lastPos = ACE_OS::ftell(pReadFile);
+
+        INT32 loopCount = 1;
+        numNewLines = 0;
+        bReadMore = true;
+
+        bool lookForNewLine = false;
+        INT32 strPos = 0;
+
+        while (bReadMore)
+        {
+            // Clear buffer
+            memset(buffer, 0, (MAX_BUF+1)*sizeof(char));
+
+            // Place file pointer to fill an array with MAX_BUF characters of file starting from
+            // the end of the file.
+            if (lastPos > MAX_BUF)
+            {
+                ACE_OS::fseek(pReadFile, -(loopCount*MAX_BUF), SEEK_END);
+                lastPos = ACE_OS::ftell(pReadFile);
+                ACE_OS::fread(buffer, sizeof(char), MAX_BUF*sizeof(char), pReadFile);
+
+                // Search through file backwards to count entries
+                // Each entry starts with a '<' after a new line
+                for (strPos = MAX_BUF; strPos >= 0; strPos--)
+                {
+                    if (lookForNewLine && '\n' == buffer[strPos])
+                    {
+                        numNewLines++;
+                    }
+                    lookForNewLine = false;
+
+                    if ('<' == buffer[strPos])
+                    {
+                        lookForNewLine = true;
+                    }
+                    // found the number of entries wanted
+                    if (numNewLines == numEntries)
+                    {
+                        bReadMore = false;
+                        break;
+                    }
+                }
+            }
+            // Place file pointer at beginning of file and fill the buffer with as
+            // much as needed.  Also ensure that each part of the file is not read more than
+            // once.
+            else
+            {
+                ACE_OS::fseek(pReadFile, 0, SEEK_SET);
+                ACE_OS::fread(buffer, sizeof(char), lastPos*sizeof(char), pReadFile);
+
+                for (strPos = lastPos; strPos >= 0; strPos--)
+                {
+                    if (lookForNewLine && '\n' == buffer[strPos])
+                    {
+                        numNewLines++;
+                    }
+                    lookForNewLine = false;
+
+                    if ('<' == buffer[strPos])
+                    {
+                        lookForNewLine = true;
+                    }
+                    // found the number of entries wanted
+                    if (numNewLines == numEntries)
+                    {
+                        break;
+                    }
+                }
+
+                // set readmore to false since there is nothing left to read
+                bReadMore = false;
+            }
+
+            contents = &buffer[++strPos] + contents;
+            loopCount++;
+        }
+        ACE_OS::fclose(pReadFile);
+    }
+
+    byteReader = MgUtil::GetByteReader(contents);
+
+    MG_LOGMANAGER_CATCH(L"MgLogManager.GetLogContents")
+    if (mgException != NULL)
+    {
+        if (pReadFile != NULL)
+        {
+            ACE_OS::fclose(pReadFile);
+        }
+        (*mgException).AddRef();
+        mgException->Raise();
+    }
+
+    return byteReader.Detach();
+}
+
+MgByteReader* MgLogManager::GetLogContents(enum MgLogType logType, MgDateTime* fromDate, MgDateTime* toDate)
+{
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, NULL));
+
+    if (fromDate == NULL || toDate == NULL)
+    {
+        throw new MgNullArgumentException(L"MgLogManager.GetLogContents", __LINE__, __WFILE__, NULL, L"", NULL);
+    }
+
+    if (*fromDate > *toDate)
+    {
+        MgStringCollection arguments;
+        arguments.Add(L"2");
+        arguments.Add(fromDate->ToString());
+
+        throw new MgInvalidArgumentException(L"MgLogManager.GetLogContents",
+            __LINE__, __WFILE__, &arguments, L"MgInvalidFromDate", NULL);
+    }
+
+    if (IsMoreThan24HourDiff(fromDate, toDate))
+    {
+        MgStringCollection arguments;
+        arguments.Add(L"2");
+        arguments.Add(fromDate->ToString());
+        arguments.Add(L"3");
+        arguments.Add(toDate->ToString());
+
+        throw new MgInvalidArgumentException(L"MgLogManager.GetLogContents",
+            __LINE__, __WFILE__, &arguments, L"MgInvalidDateDifference", NULL);
+    }
+
+    Ptr<MgByteReader> byteReader;
+    byteReader = NULL;
+    FILE* pReadFile = NULL;
+    string contents = "";
+
+    MG_LOGMANAGER_TRY()
+
+    Ptr<MgStringCollection> filenames;
+    filenames = NULL;
+    Ptr<MgStringCollection> entries;
+    entries = NULL;
+
+    STRING currentFilename;
+
+    // Get the potential file names
+    filenames = DeterminePotentialFileNames(logType, fromDate, toDate);
+    if (filenames->GetCount() < 1)
+    {
+        MgStringCollection arguments;
+        arguments.Add(L"2");
+        arguments.Add(fromDate->ToString());
+        arguments.Add(L"3");
+        arguments.Add(toDate->ToString());
+
+        throw new MgInvalidArgumentException(L"MgLogManager.GetLogContents",
+             __LINE__, __WFILE__, &arguments, L"MgFailedToGetFileNameForDates", NULL);
+    }
+
+    entries = new MgStringCollection();
+    if (entries == NULL)
+    {
+        throw new MgOutOfMemoryException(L"MgLogManager.GetLogContents", __LINE__, __WFILE__, NULL, L"", NULL);
+    }
+
+    bool fromDateFound = false;
+    bool toDateFound = false;
+
+    INT32 fromLine = 0;
+    INT32 toLine = 0;
+    INT32 i = 0;
+    INT32 j = 0;
+
+    char buffer[MAX_BUF+1];
+    string logEntry = "";                // current entry read from file
+    STRING wEntry = L"";
+
+    INT32 nSearchedFiles = 0;
+    while (nSearchedFiles < filenames->GetCount())
+    {
+        currentFilename = filenames->GetItem(nSearchedFiles);
+        nSearchedFiles++;   // increment the number of searched files
+
+        pReadFile = ACE_OS::fopen(MG_WCHAR_TO_TCHAR(currentFilename), ACE_TEXT("rb"));
+        if (pReadFile != NULL)
+        {
+            INT32 nNumRead = 0;
+
+            // Keep reading lines from the file in a chunk until no more to read or
+            // both dates have been found
+            bool bReadMore = true;
+            while (bReadMore)
+            {
+                // Clear buffer
+                memset(buffer, 0, (MAX_BUF+1)*sizeof(char));
+                entries->Clear();
+
+                fromLine = 0;
+                toLine = 0;
+
+                size_t charsRead = ACE_OS::fread(buffer, sizeof(char), MAX_BUF*sizeof(char), pReadFile);
+                if (charsRead < MAX_BUF)
+                {
+                    bReadMore = false;
+                    nNumRead = (INT32)charsRead;
+                }
+                else
+                {
+                    nNumRead = MAX_BUF;
+                }
+
+                char* entryBegin = buffer;
+                for (i = 0; i < nNumRead; i++)
+                {
+                    if (i == 0)
+                    {
+                        if (logEntry.size() > 0 && logEntry[logEntry.size()-1] == '\n' && buffer[i] == '<')
+                        {
+                            wEntry = MgUtil::MultiByteToWideChar(logEntry);
+                            logEntry.erase();
+                            entries->Add(wEntry);
+                        }
+                    }
+                    else if (buffer[i-1] == '\n' && buffer[i] == '<')
+                    {
+                        char tmp = buffer[i];
+                        buffer[i] = '\0';
+
+                        logEntry += entryBegin;
+                        wEntry = MgUtil::MultiByteToWideChar(logEntry);
+                        logEntry.erase();
+
+                        // Skip over the header entry if it is present.  Header lines start with the '#' character.
+                        if (wEntry.find_first_of('#') != 0)
+                        {
+                            entries->Add(wEntry);
+                        }
+
+                        buffer[i] = tmp;
+                        entryBegin = buffer + i;
+                    }
+                }
+                logEntry += entryBegin;
+
+                if (!bReadMore)
+                {
+                    wEntry = MgUtil::MultiByteToWideChar(logEntry);
+                    logEntry = "";
+                    entries->Add(wEntry);
+                }
+
+                if (entries->GetCount() != 0)
+                {
+                    // fromDate hasn't been found yet so we must search for it
+                    if (!fromDateFound)
+                    {
+                        fromLine = SearchClosestDateAfter(entries, fromDate);
+                        if (fromLine != -1)
+                        {
+                            fromDateFound = true;
+                        }
+                    }
+
+                    // fromDate has been found so we must search for the toDate now
+                    if (fromDateFound && !toDateFound)
+                    {
+                        toLine = SearchClosestDateBefore(entries, toDate);
+                        if (toLine == -1)
+                        {
+                            toDateFound = true;
+                        }
+                    }
+
+                    if (fromLine != -1 && toLine != -1)
+                    {
+                        // Put this chunk into the content string.
+                        for (j = fromLine; j <= toLine; j++)
+                        {
+                            contents += MgUtil::WideCharToMultiByte(entries->GetItem(j));
+                        }
+                    }
+                }
+
+                // Both dates have been found so we can now stop
+                if (toDateFound && fromDateFound)
+                {
+                    bReadMore = false;
+                }
+            } // End of file reading while loop
+
+            ACE_OS::fclose(pReadFile);
+        } // End if file open
+
+        // Both dates have been found so we can now stop
+        if (toDateFound && fromDateFound)
+        {
+            break;
+        }
+    } // End of file selecting while loop
+
+    // Put string into the byteReader that will be sent back
+    byteReader = MgUtil::GetByteReader(contents);
+
+    MG_LOGMANAGER_CATCH(L"MgLogManager.GetLogContents");
+    if (mgException != NULL)
+    {
+        if (pReadFile != NULL)
+        {
+            ACE_OS::fclose(pReadFile);
+        }
+        (*mgException).AddRef();
+        mgException->Raise();
+    }
+
+    return byteReader.Detach();
+}
+
+MgStringCollection* MgLogManager::DeterminePotentialFileNames(enum MgLogType logType, MgDateTime* fromDate, MgDateTime* toDate)
+{
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, NULL));
+
+    Ptr<MgStringCollection> filenames;
+
+    filenames = new MgStringCollection();
+
+    if (filenames == NULL)
+    {
+        throw new MgOutOfMemoryException(L"MgLogManager.GetLogContents", __LINE__, __WFILE__, NULL, L"", NULL);
+    }
+
+    STRING rawFilename;
+
+    // Determine the possible filenames that the logs might have
+    switch (logType)
+    {
+    case mltAccess:
+        rawFilename = m_AccessLogFileName;
+        break;
+    case mltAdmin:
+        rawFilename = m_AdminLogFileName;
+        break;
+    case mltAuthentication:
+        rawFilename = m_AuthenticationLogFileName;
+        break;
+    case mltError:
+        // Get the error log filename and path
+        rawFilename = m_ErrorLogFileName;
+        break;
+    case mltPerformance:
+        rawFilename = m_PerformanceLogFileName;
+        break;
+    case mltSession:
+        rawFilename = m_SessionLogFileName;
+        break;
+    case mltTrace:
+        rawFilename = m_TraceLogFileName;
+        break;
+    default:
+        {
+            STRING buffer;
+            MgUtil::Int32ToString(logType, buffer);
+
+            MgStringCollection arguments;
+            arguments.Add(L"1");
+            arguments.Add(buffer);
+
+            throw new MgInvalidArgumentException(L"MgLogManager.DeterminePotentialFileNames",
+                __LINE__, __WFILE__, &arguments, L"MgInvalidLogType", NULL);
+        }
+    }
+
+    // Name is static so can be used directly
+    if (rawFilename.find_first_of(L'%') == string::npos)
+    {
+        filenames->Add(m_path + rawFilename);
+    }
+    // Name is dynamic so there may be up to two files that contain the
+    // entriest requested.
+    else
+    {
+        STRING filename = BuildFileNameFromDateTime(rawFilename, fromDate);
+        filenames->Add(filename);
+
+        // Request spans across multiple days so more than one file may be needed
+        INT8 day1 = fromDate->GetDay();
+        INT8 day2 = toDate->GetDay();
+        if (day1 != day2 && rawFilename.find(L"%d", 0) != string::npos)
+        {
+            filename = BuildFileNameFromDateTime(rawFilename, toDate);
+            filenames->Add(filename);
+        }
+    } // End of file name determination
+
+    return filenames.Detach();
+}
+
+STRING MgLogManager::BuildFileName(CREFSTRING filename)
+{
+    STRING newFilename = filename.c_str();
+
+    newFilename = RemoveArchiveFrequencySpecifier(newFilename);
+
+    return ((STRING)m_path.c_str() + (STRING)newFilename.c_str());
+}
+
+STRING MgLogManager::BuildFileNameFromDateTime(CREFSTRING filename, MgDateTime* date)
+{
+    STRING newFilename = filename.c_str();
+    STRING replacer;
+    wchar_t buff[3];
+
+    // replace %y with last 2 digits of year
+    INT16 year = date->GetYear();
+    year %= 100;
+    ACE_OS::itoa(year, buff, 10);
+    replacer = buff;
+    if (year < 10)
+    {
+        replacer = L'0' + replacer;
+    }
+    else
+    {
+        replacer = buff;
+    }
+    newFilename = MgUtil::ReplaceString(newFilename, L"%y", replacer.c_str());
+
+    // replace %m with month
+    INT8 month = date->GetMonth();
+    ACE_OS::itoa(month, buff, 10);
+    replacer = buff;
+    if (month < 10)
+    {
+        replacer = L'0' + replacer;
+    }
+    else
+    {
+        replacer = buff;
+    }
+    newFilename = MgUtil::ReplaceString(newFilename, L"%m", replacer.c_str());
+
+    // replace %d with day
+    INT8 day = date->GetDay();
+    ACE_OS::itoa(day, buff, 10);
+    replacer = buff;
+    if (month < 10)
+    {
+        replacer = L'0' + replacer;
+    }
+    else
+    {
+        replacer = buff;
+    }
+    newFilename = MgUtil::ReplaceString(newFilename, L"%d", replacer.c_str());
+
+    return ((STRING)m_path.c_str() + (STRING)newFilename.c_str());
+}
+
+bool MgLogManager::IsMoreThan24HourDiff(MgDateTime* fromDate, MgDateTime* toDate)
+{
+    bool result = false;
+    double timeDiff = ACE_OS::difftime(toDate->ToTimeValue(), fromDate->ToTimeValue());
+
+    if (abs((int)timeDiff) > SECONDSINDAY)
+    {
+        result = true;
+    }
+    else if (abs((int)timeDiff) == SECONDSINDAY)
+    {
+        if (abs(toDate->GetMicrosecond() - fromDate->GetMicrosecond()) > 0)
+        {
+            result = true;
+        }
+        else
+        {
+            result = false;
+        }
+    }
+
+    return result;
+}
+
+INT32 MgLogManager::SearchClosestDateAfter(MgStringCollection* lines, MgDateTime* searchDate)
+{
+    INT32 result = -1;
+
+    if (lines == NULL || searchDate == NULL)
+    {
+        throw new MgNullArgumentException(L"MgLogManager.SearchClosestDateAfter", __LINE__, __WFILE__, NULL, L"", NULL);
+    }
+
+    Ptr<MgDateTime> dateTime;
+
+    MG_LOGMANAGER_TRY()
+
+    // If nothing is in the collection, the date cannot be found
+    if (lines->GetCount() > 0)
+    {
+        INT32 start = 0;
+        INT32 end = lines->GetCount() - 1;
+        INT32 key = start + (end-start)/2;
+        bool keepGoing = true;
+
+        while (keepGoing)
+        {
+            if (start == end)
+            {
+                keepGoing = false;
+            }
+
+            dateTime = GetDateTimeFromEntry(lines->GetItem(key));
+
+            if(dateTime)
+            {
+                // Found date
+                if (*dateTime == *searchDate)
+                {
+                    keepGoing = false;
+                }
+                else if (*dateTime < *searchDate)
+                {
+                    start = key + 1;
+                }
+                else
+                {
+                    end = key;
+                }
+
+                key = start + (end-start)/2;
+            }
+        }
+
+        if(dateTime)
+        {
+            // Check to ensure that a date after was actually found
+            if (*dateTime >= *searchDate)
+            {
+                // check to ensure that there are no previous equal entries in date
+                Ptr<MgDateTime> dateTime2;
+                if (key > 0)
+                {
+                    dateTime2 = GetDateTimeFromEntry(lines->GetItem(key-1));
+                    while (*dateTime == *dateTime2)
+                    {
+                        key--;
+                        if (key == 0)
+                        {
+                            break;
+                        }
+                        dateTime2 = GetDateTimeFromEntry(lines->GetItem(key-1));
+                    }
+                }
+                result = key;
+            }
+        }
+    }
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.SearchClosestDateAfter");
+
+    return result;
+}
+
+INT32 MgLogManager::SearchClosestDateBefore(MgStringCollection* lines, MgDateTime* searchDate)
+{
+    INT32 result = -1;
+
+    if (lines == NULL || searchDate == NULL)
+    {
+        throw new MgNullArgumentException(L"MgLogManager.SearchClosestDateBefore", __LINE__, __WFILE__, NULL, L"", NULL);
+    }
+
+    Ptr<MgDateTime> dateTime;
+
+    MG_LOGMANAGER_TRY()
+
+    // If nothing is in the collection, the date cannot be found
+    if (lines->GetCount() > 0)
+    {
+        INT32 start = 0;
+        INT32 end = lines->GetCount() - 1;
+
+        INT32 key = end - (end-start)/2;
+        bool keepGoing = true;
+
+        while (keepGoing)
+        {
+            if (start == end)
+            {
+                keepGoing = false;
+            }
+
+            dateTime = GetDateTimeFromEntry(lines->GetItem(key));
+
+            if(dateTime)
+            {
+                // Found date
+                if (*dateTime == *searchDate)
+                {
+                    keepGoing = false;
+                }
+                else if (*dateTime < *searchDate)
+                {
+                    start = key;
+                }
+                else
+                {
+                    end = key - 1;
+                }
+
+                key = end - (end-start)/2;
+            }
+        }
+
+        if(dateTime)
+        {
+            // Check to ensure that a date before was actually found
+            if (*dateTime <= *searchDate)
+            {
+                // Check to ensure that the next entries are not equal in date
+                Ptr<MgDateTime> dateTime2;
+                if (key < (lines->GetCount() - 1))
+                {
+                    dateTime2 = GetDateTimeFromEntry(lines->GetItem(key+1));
+                    while (*dateTime == *dateTime2)
+                    {
+                        key++;
+                        if (key == (lines->GetCount() - 1))
+                        {
+                            break;
+                        }
+                        dateTime2 = GetDateTimeFromEntry(lines->GetItem(key+1));
+                    }
+                }
+                result = key;
+            }
+        }
+    }
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.SearchClosestDateBefore");
+
+    return result;
+}
+
+MgDateTime* MgLogManager::GetDateTimeFromEntry(CREFSTRING entry)
+{
+    Ptr<MgDateTime> dateTime;
+
+    MG_LOGMANAGER_TRY()
+
+    if(entry.size() == 0)
+    {
+        return NULL;
+    }
+
+    // Each entry starts with the log time that conforms to XML standard and
+    // is enclosed by angle brackets, i.e. <CCYY-MM-DDThh:mm:ss>
+    if (entry.find_first_of(L'<') != 0  || entry.find_first_of(L'>') != 20)
+    {
+        throw new MgInvalidLogEntryException(
+            L"MgLogManager.GetDateTimeFromEntry",
+            __LINE__, __WFILE__, NULL, L"", NULL);
+    }
+
+    string logTime;
+    MgUtil::WideCharToMultiByte(entry.substr(1, 19), logTime);
+    dateTime = new MgDateTime(logTime);
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.GetDateTimeFromEntry");
+
+    return dateTime.Detach();
+}
+
+void MgLogManager::AddDateTime(REFSTRING entry, const MgDateTime& value)
+{
+    AddDelimiter(entry);
+    entry += const_cast<MgDateTime&>(value).ToXmlString(false);
+}
+
+void MgLogManager::AddDouble(REFSTRING entry, double value)
+{
+    STRING buffer;
+
+    AddDelimiter(entry);
+    MgUtil::DoubleToString(value, buffer);
+    entry += buffer;
+}
+
+void MgLogManager::AddInt32(REFSTRING entry, INT32 value)
+{
+    STRING buffer;
+
+    AddDelimiter(entry);
+    MgUtil::Int32ToString(value, buffer);
+    entry += buffer;
+}
+
+void MgLogManager::AddString(REFSTRING entry, CREFSTRING value)
+{
+    AddDelimiter(entry);
+    entry += value.c_str();
+}
+
+void MgLogManager::AddClient(REFSTRING entry, CREFSTRING client)
+{
+    AddDelimiter(entry);
+    entry += client.c_str();
+}
+
+void MgLogManager::AddClientIp(REFSTRING entry, CREFSTRING clientIp)
+{
+    AddDelimiter(entry);
+    entry += clientIp.c_str();
+}
+
+void MgLogManager::AddError(REFSTRING entry, CREFSTRING error, CREFSTRING type)
+{
+#ifdef _WIN32
+    entry += L"\r\n " + type + L": ";
+#else
+    entry += L"\n " + type + L": ";
+#endif
+
+    size_t size = error.size();
+
+    if (size > 0)
+    {
+        STRING str = error.c_str();
+
+        // Get rid of extra \n at the end of the stack trace
+        if (str[size-1] == L'\n')
+        {
+            str.erase((size-1), 1);
+        }
+
+        // Make it look "pretty"
+#ifdef _WIN32
+        // Windows uses \r\n for a new line
+        str = MgUtil::ReplaceString(str, L"\n", L"\r\n        ");
+        entry += str;
+#else
+        // Linux just uses \n for a new line
+        str = MgUtil::ReplaceString(str, L"\n", L"\n        ");
+        entry += str;
+#endif
+    }
+
+}
+
+void MgLogManager::AddStackTrace(REFSTRING entry, CREFSTRING stackTrace)
+{
+    // Do not log empty stack traces
+    if (stackTrace.empty())
+    {
+        return;
+    }
+
+#ifdef _WIN32
+    entry += L"\r\n " + MgResources::StackTrace + L":";
+#else
+    entry += L"\n " + MgResources::StackTrace + L":";
+#endif
+
+    size_t size = stackTrace.size();
+
+    if (size > 0)
+    {
+        STRING trace = stackTrace.c_str();
+
+        // Get rid of extra \n at the end of the stack trace
+        if (trace[size-1] == L'\n')
+        {
+            trace.erase((size-1), 1);
+        }
+
+        // Make it look "pretty"
+#ifdef _WIN32
+        // Windows uses \r\n for a new line
+        trace = MgUtil::ReplaceString(trace, L"\n", L"\r\n  ");
+        entry += L"\r\n  " + trace;
+#else
+        // Linux just uses \n for a new line
+        trace = MgUtil::ReplaceString(trace, L"\n", L"\n  ");
+        entry += L"\n  " + trace;
+#endif
+    }
+}
+
+void MgLogManager::AddInfo(REFSTRING entry, CREFSTRING info)
+{
+    AddDelimiter(entry);
+    entry += info.c_str();
+}
+
+void MgLogManager::AddOpId(REFSTRING entry, CREFSTRING opId)
+{
+    AddDelimiter(entry);
+    entry += MgUtil::EncodeXss(opId);
+}
+
+void MgLogManager::AddThreadId(REFSTRING entry)
+{
+    AddDelimiter(entry);
+
+    ACE_thread_t threadId = ACE_OS::thr_self();
+    STRING threadString;
+    MgUtil::Int32ToString(threadId, threadString);
+    entry += threadString;
+}
+
+void MgLogManager::AddUserName(REFSTRING entry, CREFSTRING userName)
+{
+    AddDelimiter(entry);
+    entry += userName.c_str();
+}
+
+bool MgLogManager::IsMaxSizeExceeded(CREFSTRING logFileName)
+{
+    bool bMaxSizeReached = false;
+
+    INT64 nFileSize = MgFileUtil::GetFileSize(logFileName);
+
+    if (nFileSize >= (MgLogManager::m_maxLogSize * 1024))
+    {
+        bMaxSizeReached = true;
+    }
+
+    return bMaxSizeReached;
+}
+
+void MgLogManager::ArchiveLog(enum MgLogType logType)
+{
+    ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex));
+
+    STRING logFileName = L"";
+    std::ofstream* pLogStream = NULL;
+
+    switch(logType)
+    {
+        case mltAccess:
+            logFileName = BuildFileName(m_AccessLogFileName);
+            pLogStream = &m_accessLogStream;
+            break;
+        case mltAdmin:
+            logFileName = BuildFileName(m_AdminLogFileName);
+            pLogStream = &m_adminLogStream;
+            break;
+        case mltAuthentication:
+            logFileName = BuildFileName(m_AuthenticationLogFileName);
+            pLogStream = &m_authenticationLogStream;
+            break;
+        case mltError:
+            logFileName = BuildFileName(m_ErrorLogFileName);
+            pLogStream = &m_errorLogStream;
+            break;
+        case mltPerformance:
+            logFileName = BuildFileName(m_PerformanceLogFileName);
+            pLogStream = &m_performanceLogStream;
+            break;
+        case mltSession:
+            logFileName = BuildFileName(m_SessionLogFileName);
+            pLogStream = &m_sessionLogStream;
+            break;
+        case mltTrace:
+            logFileName = BuildFileName(m_TraceLogFileName);
+            pLogStream = &m_traceLogStream;
+            break;
+        default:
+            {
+                STRING buffer;
+                MgUtil::Int32ToString(logType, buffer);
+
+                MgStringCollection arguments;
+                arguments.Add(L"1");
+                arguments.Add(buffer);
+
+                throw new MgInvalidArgumentException(L"MgLogManager.ArchiveLog",
+                    __LINE__, __WFILE__, &arguments, L"MgInvalidLogType", NULL);
+            }
+    }
+
+    if (MgFileUtil::PathnameExists(logFileName))
+    {
+        if(pLogStream)
+        {
+            // Is the stream open?
+            if(pLogStream->is_open())
+            {
+                // Close the log file
+                pLogStream->close();
+            }
+        }
+
+        // The archived named will be the current filename suffixed with the current date of the archive + a unique ID
+        STRING archiveName = L"";
+
+        // Cache the current extension
+        size_t index = logFileName.rfind(L".");
+        STRING logFileExt = L"";
+        logFileExt = logFileName.substr(index);
+
+        archiveName.clear();
+        archiveName = logFileName.substr(0, index);
+
+        // Add the date and time suffix to the archive name.
+        ACE_Date_Time date_time;
+        INT32 year = (INT32)date_time.year();
+        INT32 month = (INT32)date_time.month();
+        INT32 day = (INT32)date_time.day();
+
+        STRING uniqueId;
+        MgUtil::GenerateUuid(uniqueId);
+
+        STRING strYear;
+        STRING strMonth;
+        STRING strDay;
+        MgUtil::Int32ToString(year, strYear);
+        MgUtil::Int32ToString(month, strMonth);
+        MgUtil::Int32ToString(day, strDay);
+
+        archiveName.append(L"_");
+        archiveName.append(strYear);
+        archiveName.append(L"-");
+        archiveName.append(strMonth);
+        archiveName.append(L"-");
+        archiveName.append(strDay);
+        archiveName.append(L"_");
+        archiveName.append(uniqueId);
+        archiveName.append(logFileExt);
+
+        // Create the archive
+        MgFileUtil::RenameFile(logFileName, archiveName);
+
+        if(pLogStream)
+        {
+            // Open the new log file
+            pLogStream->open(MgUtil::WideCharToMultiByte(logFileName).c_str(), ios::out | ios::app | ios::binary);
+
+            SetLogHasHeader(logType, false);
+        }
+
+        UpdateLogFilesTimestampCache();
+    }
+}
+
+// If the parameters in the header do not match the current logging parameters, the log is archived
+// so that new log will be created based on the current logging parameters.
+//
+void MgLogManager::ValidateLogHeaders(enum MgLogType logType)
+{
+    ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex));
+
+    switch(logType)
+    {
+       case mltAccess:
+            // Check Access Log
+            if (!ValidateAccessLogHeader())
+            {
+                ArchiveLog(logType);
+            }
+            break;
+        case mltAdmin:
+            // Check Admin Log
+            if (!ValidateAdminLogHeader())
+            {
+                ArchiveLog(logType);
+            }
+            break;
+        case mltAuthentication:
+            // Check Authentication Log
+            if (!ValidateAuthenticationLogHeader())
+            {
+                ArchiveLog(logType);
+            }
+            break;
+        case mltError:
+            // Check Error Log
+            if (!ValidateErrorLogHeader())
+            {
+                ArchiveLog(logType);
+            }
+            break;
+        case mltPerformance:
+            // Check Performance Log
+            if (!ValidatePerformanceLogHeader())
+            {
+                ArchiveLog(logType);
+            }
+            break;
+        case mltSession:
+            // Check Session Log
+            if (!ValidateSessionLogHeader())
+            {
+                ArchiveLog(logType);
+            }
+            break;
+        case mltTrace:
+            // Check Trace Log
+            if (!ValidateTraceLogHeader())
+            {
+                ArchiveLog(logType);
+            }
+            break;
+        default:
+            {
+                STRING buffer;
+                MgUtil::Int32ToString(logType, buffer);
+
+                MgStringCollection arguments;
+                arguments.Add(L"1");
+                arguments.Add(buffer);
+
+                throw new MgInvalidArgumentException(L"MgLogManager.ValidateLogHeaders",
+                    __LINE__, __WFILE__, &arguments, L"MgInvalidLogType", NULL);
+            }
+    }
+}
+
+bool MgLogManager::ValidateAccessLogHeader()
+{
+    bool bValid = false;
+
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, false));
+
+    // Compare the log file parameters list with the current logging parameters
+    STRING logFileParameters = ReadParametersFromLogFile(mltAccess);
+    STRING currentLogParams = GetAccessLogParameters();
+    if (0 == logFileParameters.compare(currentLogParams))
+    {
+        bValid = true;
+    }
+
+    MG_LOGMANAGER_CATCH(L"MgLogManager.ValidateAccessLogHeader")
+
+    return bValid;
+}
+
+bool MgLogManager::ValidateAdminLogHeader()
+{
+    bool bValid = false;
+
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, false));
+
+    // Compare the log file parameters list with the current logging parameters
+    STRING logFileParameters = ReadParametersFromLogFile(mltAdmin);
+    STRING currentLogParams = GetAdminLogParameters();
+    if (0 == logFileParameters.compare(currentLogParams))
+    {
+        bValid = true;
+    }
+
+    MG_LOGMANAGER_CATCH(L"MgLogManager.ValidateAdminLogHeader")
+
+    return bValid;
+}
+
+bool MgLogManager::ValidateAuthenticationLogHeader()
+{
+    bool bValid = false;
+
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, false));
+
+    // Compare the log file parameters list with the current logging parameters
+    STRING logFileParameters = ReadParametersFromLogFile(mltAuthentication);
+    STRING currentLogParams = GetAuthenticationLogParameters();
+    if (0 == logFileParameters.compare(currentLogParams))
+    {
+        bValid = true;
+    }
+
+    MG_LOGMANAGER_CATCH(L"MgLogManager.ValidateAuthenticationLogHeader")
+
+    return bValid;
+}
+
+bool MgLogManager::ValidateErrorLogHeader()
+{
+    bool bValid = false;
+
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, false));
+
+    // Compare the log file parameters list with the current logging parameters
+    STRING logFileParameters = ReadParametersFromLogFile(mltError);
+    STRING currentLogParams = GetErrorLogParameters();
+    if (0 == logFileParameters.compare(currentLogParams))
+    {
+        bValid = true;
+    }
+
+    MG_LOGMANAGER_CATCH(L"MgLogManager.ValidateErrorLogHeader")
+
+    return bValid;
+}
+
+bool MgLogManager::ValidatePerformanceLogHeader()
+{
+    bool bValid = false;
+
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, false));
+
+    // Compare the log file parameters list with the current logging parameters
+    STRING logFileParameters = ReadParametersFromLogFile(mltPerformance);
+    STRING currentLogParams = GetPerformanceLogParameters();
+    if (0 == logFileParameters.compare(currentLogParams))
+    {
+        bValid = true;
+    }
+
+    MG_LOGMANAGER_CATCH(L"MgLogManager.ValidatePerformanceLogHeader")
+
+    return bValid;
+}
+
+bool MgLogManager::ValidateSessionLogHeader()
+{
+    bool bValid = false;
+
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, false));
+
+    // Compare the log file parameters list with the current logging parameters
+    STRING logFileParameters = ReadParametersFromLogFile(mltSession);
+    STRING currentLogParams = GetSessionLogParameters();
+    if (0 == logFileParameters.compare(currentLogParams))
+    {
+        bValid = true;
+    }
+
+    MG_LOGMANAGER_CATCH(L"MgLogManager.ValidateSessionLogHeader")
+
+    return bValid;
+}
+
+bool MgLogManager::ValidateTraceLogHeader()
+{
+    bool bValid = false;
+
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, false));
+
+    // Compare the log file parameters list with the current logging parameters
+    STRING logFileParameters = ReadParametersFromLogFile(mltTrace);
+    STRING currentLogParams = GetTraceLogParameters();
+    if (0 == logFileParameters.compare(currentLogParams))
+    {
+        bValid = true;
+    }
+
+    MG_LOGMANAGER_CATCH(L"MgLogManager.ValidateTraceLogHeader")
+
+    return bValid;
+}
+
+STRING MgLogManager::ReadParametersFromLogFile(enum MgLogType logType)
+{
+    STRING logParameters = L"";
+
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, NULL));
+
+    Ptr<MgByteReader> bytes;
+    bytes = GetLogHeader(logType);
+
+    if (NULL != bytes.p && bytes->GetLength() > 0)
+    {
+        char buffer[4096] = {0};
+        bytes->Read((BYTE_ARRAY_OUT)&buffer, 4095);
+        string strBuffer;
+        strBuffer.assign(buffer);
+
+        // Find the second line in the log
+        size_t startLine2 = strBuffer.find("\n") + 1;
+        size_t endLine2 = strBuffer.find("\n", startLine2);
+        if (0 != startLine2)
+        {
+            string strLineBuf = strBuffer.substr(startLine2, endLine2 - startLine2);
+
+            // Check if there is a carriage return (\r) at the end of the line
+            size_t endLineBuf = strLineBuf.rfind("\r");
+            string strLine2 = strLineBuf.substr(0, endLineBuf);
+
+            // Attempt to extract the parameters list
+            string strHeaderPrefix = MgUtil::WideCharToMultiByte(MgLogManager::HeaderLine2);
+            if (0 == strLine2.compare(0, strHeaderPrefix.length(), strHeaderPrefix))
+            {
+                // The prefix for the header line is OK.  Now lets get the parameters
+                string strParams = strLine2.substr(strHeaderPrefix.length() + 1);
+                logParameters = MgUtil::MultiByteToWideChar(strParams);
+
+                SetLogHasHeader(logType, true);
+            }
+        }
+    }
+    else
+    {
+        // The file was empty so the parameters have not been written yet
+        SetLogHasHeader(logType, false);
+
+        switch (logType)
+        {
+        case mltAccess:
+            logParameters = m_AccessLogParameters;
+            break;
+        case mltAdmin:
+            logParameters = m_AdminLogParameters;
+            break;
+        case mltAuthentication:
+            logParameters = m_AuthenticationLogParameters;
+            break;
+        case mltError:
+            logParameters = m_ErrorLogParameters;
+            break;
+        case mltPerformance:
+            logParameters = m_PerformanceLogParameters;
+            break;
+        case mltSession:
+            logParameters = m_SessionLogParameters;
+            break;
+        case mltTrace:
+            logParameters = m_TraceLogParameters;
+            break;
+        default:
+            break;
+        }
+    }
+
+    MG_LOGMANAGER_CATCH(L"MgLogManager.ReadParametersFromLogFile")
+
+    return logParameters;
+}
+
+STRING MgLogManager::ReadLogTypeFromLogFile(CREFSTRING logFilename)
+{
+    STRING logType = MgLogManager::UnspecifiedLog;
+
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, NULL));
+
+    Ptr<MgByteReader> bytes;
+    bytes = GetLogHeader(logFilename);
+
+    char buffer[4096] = {0};
+    bytes->Read((BYTE_ARRAY_OUT)&buffer, 4095);
+    string contents;
+    contents.assign(buffer);
+
+    if (contents.size() > 0)
+    {
+        // Find the first line in the log
+        size_t startLine1 = 0;
+        size_t endLine1 = contents.find("\n");
+        if (0 != endLine1)
+        {
+            string strLineBuf = contents.substr(startLine1, endLine1);
+
+            // Check if there is a carriage return (\r) at the end of the line
+            size_t endLineBuf = strLineBuf.rfind("\r");
+            string strLine1 = strLineBuf.substr(0, endLineBuf);
+
+            // Attempt to extract the log type
+            string strHeaderPrefix = MgUtil::WideCharToMultiByte(MgLogManager::HeaderLine1);
+            if (0 == strLine1.compare(0, strHeaderPrefix.length(), strHeaderPrefix))
+            {
+                // The prefix for the header line is OK.  Now lets get the type
+                string strType = strLine1.substr(strHeaderPrefix.length() + 1);
+                logType = MgUtil::MultiByteToWideChar(strType);
+            }
+        }
+    }
+
+    MG_LOGMANAGER_CATCH(L"MgLogManager.ReadLogTypeFromLogFile")
+
+    return logType;
+}
+
+STRING MgLogManager::DetermineLogFileStatus(CREFSTRING logFilename, CREFSTRING logFileType)
+{
+    STRING logStatus = L"";
+
+    MG_LOGMANAGER_TRY()
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, NULL));
+
+    STRING currentLogName = L"";
+
+    // Get the name being used for the current log
+    if (0 == logFileType.compare(MgLogManager::AccessLog))
+    {
+        currentLogName = GetAccessLogFileName();
+    }
+    else if (0 == logFileType.compare(MgLogManager::AdminLog))
+    {
+        currentLogName = GetAdminLogFileName();
+    }
+    else if (0 == logFileType.compare(MgLogManager::AuthenticationLog))
+    {
+        currentLogName = GetAuthenticationLogFileName();
+    }
+    else if (0 == logFileType.compare(MgLogManager::ErrorLog))
+    {
+        currentLogName = GetErrorLogFileName();
+    }
+    else if (0 == logFileType.compare(MgLogManager::PerformanceLog))
+    {
+        currentLogName = GetPerformanceLogFileName();
+    }
+    else if (0 == logFileType.compare(MgLogManager::SessionLog))
+    {
+        currentLogName= GetSessionLogFileName();
+    }
+    else if (0 == logFileType.compare(MgLogManager::TraceLog))
+    {
+        currentLogName = GetTraceLogFileName();
+    }
+    else if (0 == logFileType.compare(MgLogManager::UnspecifiedLog))
+    {
+        // The log type is unspecified.  This is most likely an
+        // archived log because the header information is not found.
+        //
+        // Nothing to do here, because the log status will be set to "Archive".
+    }
+    else
+    {
+        MgStringCollection arguments;
+        arguments.Add(L"2");
+        arguments.Add(logFileType);
+
+        throw new MgInvalidArgumentException(L"MgLogManager.DetermineLogFileStatus",
+            __LINE__, __WFILE__, &arguments, L"MgInvalidLogType", NULL);
+    }
+
+    currentLogName = RemoveArchiveFrequencySpecifier(currentLogName);
+
+    // Compare the current log name with the filename to determine its status.
+    if (0 == logFilename.compare(currentLogName))
+    {
+        logStatus = MgLogManager::LogStatusActive;
+    }
+    else
+    {
+        logStatus = MgLogManager::LogStatusArchive;
+    }
+
+    MG_LOGMANAGER_CATCH_AND_THROW(L"MgLogManager.DetermineLogFileStatus")
+
+    return logStatus;
+}
+
+void MgLogManager::AddDelimiter(REFSTRING entry)
+{
+    entry += m_delimiter;
+}
+
+// Check if the delimiter is any one of the reserved characters ( \t \r \n \f \v ).
+// If found, it will need to be translated to actually write the character.
+void MgLogManager::TranslateDelimiter()
+{
+    if (0 == m_delimiter.compare(0, 2, L"\\t"))
+    {
+        m_delimiter = '\t';
+    }
+    else if (0 == m_delimiter.compare(0, 2, L"\\r"))
+    {
+        m_delimiter = '\r';
+    }
+    else if (0 == m_delimiter.compare(0, 2, L"\\n"))
+    {
+        m_delimiter = '\n';
+    }
+    else if (0 == m_delimiter.compare(0, 2, L"\\f"))
+    {
+        m_delimiter = '\f';
+    }
+    else if (0 == m_delimiter.compare(0, 2, L"\\v"))
+    {
+        m_delimiter = '\v';
+    }
+}
+
+void MgLogManager::SetMaximumLogSize(INT32 size)
+{
+    m_maxLogSize = size;
+}
+
+void MgLogManager::SetLogDelimiter(CREFSTRING delimiter)
+{
+    ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex));
+
+    m_delimiter = delimiter;
+}
+
+STRING MgLogManager::GetLogDelimiter()
+{
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, STRING(L"")));
+
+    return m_delimiter;
+}
+
+void MgLogManager::EnableMaximumLogSize(bool useMaxSize)
+{
+    m_useMaxLogSize = useMaxSize;
+}
+
+bool MgLogManager::IsMaximumLogSizeEnabled()
+{
+    return m_useMaxLogSize;
+}
+
+bool MgLogManager::CheckArchiveFrequency(enum MgLogType logType, CREFSTRING logFilename)
+{
+    bool bCurrentLog = true;
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, false));
+
+    // Get the frequency specifier from the filename, and the filetimestamp from the cache
+    STRING rawFilename;
+    MgDateTime logTimestamp;
+
+    switch (logType)
+    {
+    case mltAccess:
+        rawFilename = m_AccessLogFileName;
+        logTimestamp = m_cacheAccessLogTimestamp;
+        break;
+    case mltAdmin:
+        rawFilename = m_AdminLogFileName;
+        logTimestamp = m_cacheAdminLogTimestamp;
+        break;
+    case mltAuthentication:
+        rawFilename = m_AuthenticationLogFileName;
+        logTimestamp = m_cacheAuthenticationLogTimestamp;
+        break;
+    case mltError:
+        rawFilename = m_ErrorLogFileName;
+        logTimestamp = m_cacheErrorLogTimestamp;
+        break;
+    case mltPerformance:
+        rawFilename = m_PerformanceLogFileName;
+        logTimestamp = m_cachePerformanceLogTimestamp;
+        break;
+    case mltSession:
+        rawFilename = m_SessionLogFileName;
+        logTimestamp = m_cacheSessionLogTimestamp;
+        break;
+    case mltTrace:
+        rawFilename = m_TraceLogFileName;
+        logTimestamp = m_cacheTraceLogTimestamp;
+        break;
+    default:
+        {
+            STRING buffer;
+            MgUtil::Int32ToString(logType, buffer);
+
+            MgStringCollection arguments;
+            arguments.Add(L"1");
+            arguments.Add(buffer);
+
+            throw new MgInvalidArgumentException(L"MgLogManager.CheckArchiveFrequency",
+                __LINE__, __WFILE__, &arguments, L"MgInvalidLogType", NULL);
+        }
+    }
+
+    STRING specifier;
+    STRING::size_type specifierIndex = rawFilename.find_first_of(L'%');
+    if (specifierIndex != string::npos)
+    {
+        specifier = rawFilename[specifierIndex + 1];
+    }
+
+
+    // Compare the timestamp to the current time
+    MgDateTime currentTime;
+
+    // If the frequency boundary has been crossed, the file needs to be archived
+    if (specifier == L"d")
+    {
+        if ( logTimestamp < currentTime )
+        {
+            if ( logTimestamp.GetDay() != currentTime.GetDay() )
+            {
+                bCurrentLog = false;
+            }
+        }
+    }
+    else if (specifier == L"m")
+    {
+        if ( logTimestamp.GetYear() <= currentTime.GetYear() )
+        {
+            if (logTimestamp.GetMonth() != currentTime.GetMonth())
+            {
+                bCurrentLog = false;
+            }
+        }
+    }
+    else if (specifier == L"y")
+    {
+        if ( logTimestamp.GetYear() < currentTime.GetYear() )
+        {
+            bCurrentLog = false;
+        }
+    }
+
+    return bCurrentLog;
+}
+
+STRING MgLogManager::RemoveArchiveFrequencySpecifier(CREFSTRING logFilename)
+{
+    STRING newFileName;
+
+    // Remove the archive frequency specifier from the filename, if it is present
+    newFileName = MgUtil::ReplaceString(logFilename, L"%y", L"");     // NOXLATE
+    newFileName = MgUtil::ReplaceString(newFileName, L"%m", L"");     // NOXLATE
+    newFileName = MgUtil::ReplaceString(newFileName, L"%d", L"");     // NOXLATE
+
+    return newFileName;
+}
+
+bool MgLogManager::IsLogFileInUse(CREFSTRING filename, enum MgLogType& logType)
+{
+    bool bResult = false;
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, false));
+
+    logType = mltSystem; // Assign to log type not associated with a file
+
+    // Check if the filename matches any of the log filenames in use
+    if(filename.compare(m_AccessLogFileName) == 0)
+    {
+        // Match
+        logType = mltAccess;
+    }
+    else if(filename.compare(m_AdminLogFileName) == 0)
+    {
+        // Match
+        logType = mltAdmin;
+    }
+    else if(filename.compare(m_AuthenticationLogFileName) == 0)
+    {
+        // Match
+        logType = mltAuthentication;
+    }
+    else if(filename.compare(m_ErrorLogFileName) == 0)
+    {
+        // Match
+        logType = mltError;
+    }
+    else if(filename.compare(m_PerformanceLogFileName) == 0)
+    {
+        // Match
+        logType = mltPerformance;
+    }
+    else if(filename.compare(m_SessionLogFileName) == 0)
+    {
+        // Match
+        logType = mltSession;
+    }
+    else if(filename.compare(m_TraceLogFileName) == 0)
+    {
+        // Match
+        logType = mltTrace;
+    }
+
+    // Was there a match?
+    if(mltSystem != logType)
+    {
+        bResult = IsLogInUse(logType);
+    }
+
+    return bResult;
+}
+
+bool MgLogManager::IsLogInUse(enum MgLogType& logType)
+{
+    bool bResult = false;
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, false));
+
+    switch(logType)
+    {
+        case mltAccess:
+            bResult = m_bAccessLogEnabled;
+            break;
+        case mltAdmin:
+            bResult = m_bAdminLogEnabled;
+            break;
+        case mltAuthentication:
+            bResult = m_bAuthenticationLogEnabled;
+            break;
+        case mltError:
+            bResult = m_bErrorLogEnabled;
+            break;
+        case mltPerformance:
+            bResult = m_bPerformanceLogEnabled;
+            break;
+        case mltSession:
+            bResult = m_bSessionLogEnabled;
+            break;
+        case mltTrace:
+            bResult = m_bTraceLogEnabled;
+            break;
+        default:
+            break;
+    }
+
+    return bResult;
+}
+
+void MgLogManager::DisableLog(enum MgLogType logType)
+{
+    ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex));
+
+    switch(logType)
+    {
+        case mltAccess:
+            if(m_accessLogStream.is_open())
+            {
+                // Close the file
+                m_accessLogStream.close();
+            }
+            break;
+        case mltAdmin:
+            if(m_adminLogStream.is_open())
+            {
+                // Close the file
+                m_adminLogStream.close();
+            }
+            break;
+        case mltAuthentication:
+            if(m_authenticationLogStream.is_open())
+            {
+                // Close the file
+                m_authenticationLogStream.close();
+            }
+            break;
+        case mltError:
+            if(m_errorLogStream.is_open())
+            {
+                // Close the file
+                m_errorLogStream.close();
+            }
+            break;
+        case mltPerformance:
+            if(m_performanceLogStream.is_open())
+            {
+                // Close the file
+                m_performanceLogStream.close();
+            }
+            break;
+        case mltSession:
+            if(m_sessionLogStream.is_open())
+            {
+                // Close the file
+                m_sessionLogStream.close();
+            }
+            break;
+        case mltTrace:
+            if(m_traceLogStream.is_open())
+            {
+                // Close the file
+                m_traceLogStream.close();
+            }
+            break;
+        default:
+            break;
+    }
+}
+
+void MgLogManager::EnableLog(enum MgLogType logType)
+{
+    ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex));
+
+    switch(logType)
+    {
+        case mltAccess:
+            if(!m_accessLogStream.is_open())
+            {
+                // Open the file
+                STRING filename = BuildFileName(m_AccessLogFileName);
+                m_accessLogStream.open(MgUtil::WideCharToMultiByte(filename).c_str(), ios::out | ios::app | ios::binary);
+            }
+            break;
+        case mltAdmin:
+            if(!m_adminLogStream.is_open())
+            {
+                // Open the file
+                STRING filename = BuildFileName(m_AdminLogFileName);
+                m_adminLogStream.open(MgUtil::WideCharToMultiByte(filename).c_str(), ios::out | ios::app | ios::binary);
+            }
+            break;
+        case mltAuthentication:
+            if(!m_authenticationLogStream.is_open())
+            {
+                // Open the file
+                STRING filename = BuildFileName(m_AuthenticationLogFileName);
+                m_authenticationLogStream.open(MgUtil::WideCharToMultiByte(filename).c_str(), ios::out | ios::app | ios::binary);
+            }
+            break;
+        case mltError:
+            if(!m_errorLogStream.is_open())
+            {
+                // Open the file
+                STRING filename = BuildFileName(m_ErrorLogFileName);
+                m_errorLogStream.open(MgUtil::WideCharToMultiByte(filename).c_str(), ios::out | ios::app | ios::binary);
+            }
+            break;
+        case mltPerformance:
+            if(!m_performanceLogStream.is_open())
+            {
+                // Open the file
+                STRING filename = BuildFileName(m_PerformanceLogFileName);
+                m_performanceLogStream.open(MgUtil::WideCharToMultiByte(filename).c_str(), ios::out | ios::app | ios::binary);
+            }
+            break;
+        case mltSession:
+            if(!m_sessionLogStream.is_open())
+            {
+                // Open the file
+                STRING filename = BuildFileName(m_SessionLogFileName);
+                m_sessionLogStream.open(MgUtil::WideCharToMultiByte(filename).c_str(), ios::out | ios::app | ios::binary);
+            }
+            break;
+        case mltTrace:
+            if(!m_traceLogStream.is_open())
+            {
+                // Open the file
+                STRING filename = BuildFileName(m_TraceLogFileName);
+                m_traceLogStream.open(MgUtil::WideCharToMultiByte(filename).c_str(), ios::out | ios::app | ios::binary);
+            }
+            break;
+        default:
+            break;
+    }
+
+    SetLogHasHeader(logType, false);
+}
+
+void MgLogManager::SetLogHasHeader(enum MgLogType logType, bool bHeader)
+{
+    ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex));
+
+    switch(logType)
+    {
+        case mltAccess:
+            m_bAccessLogHeader = bHeader;
+            break;
+        case mltAdmin:
+            m_bAdminLogHeader = bHeader;
+            break;
+        case mltAuthentication:
+            m_bAuthenticationLogHeader = bHeader;
+            break;
+        case mltError:
+            m_bErrorLogHeader = bHeader;
+            break;
+        case mltPerformance:
+            m_bPerformanceLogHeader = bHeader;
+            break;
+        case mltSession:
+            m_bSessionLogHeader = bHeader;
+            break;
+        case mltTrace:
+            m_bTraceLogHeader = bHeader;
+            break;
+        default:
+            break;
+    }
+}
+
+bool MgLogManager::LogHasHeader(enum MgLogType logType)
+{
+    bool bResult = false;
+
+    ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, m_mutex, false));
+
+    switch(logType)
+    {
+        case mltAccess:
+            bResult = m_bAccessLogHeader;
+            break;
+        case mltAdmin:
+            bResult = m_bAdminLogHeader;
+            break;
+        case mltAuthentication:
+            bResult = m_bAuthenticationLogHeader;
+            break;
+        case mltError:
+            bResult = m_bErrorLogHeader;
+            break;
+        case mltPerformance:
+            bResult = m_bPerformanceLogHeader;
+            break;
+        case mltSession:
+            bResult = m_bSessionLogHeader;
+            break;
+        case mltTrace:
+            bResult = m_bTraceLogHeader;
+            break;
+        default:
+            break;
+    }
+
+    return bResult;
+}
+
+void MgLogManager::UpdateLogFilesTimestampCache()
+{
+    // mltAccess:
+    if (IsAccessLogEnabled())
+    {
+        STRING accessLogFileName = BuildFileName(m_AccessLogFileName);
+        if (MgFileUtil::PathnameExists(accessLogFileName))
+        {
+            m_cacheAccessLogTimestamp = MgFileUtil::GetFileModificationTime(accessLogFileName);
+        }
+    }
+
+    // mltAdmin:
+    if (IsAdminLogEnabled())
+    {
+        STRING adminLogFileName = BuildFileName(m_AdminLogFileName);
+        if (IsAdminLogEnabled() && MgFileUtil::PathnameExists(adminLogFileName))
+        {
+            m_cacheAdminLogTimestamp = MgFileUtil::GetFileModificationTime(adminLogFileName);
+        }
+    }
+
+    // mltAuthentication:
+    if (IsAuthenticationLogEnabled())
+    {
+        STRING authenticationLogFileName = BuildFileName(m_AuthenticationLogFileName);
+        if (MgFileUtil::PathnameExists(authenticationLogFileName))
+        {
+            m_cacheAuthenticationLogTimestamp = MgFileUtil::GetFileModificationTime(authenticationLogFileName);
+        }
+    }
+
+    // mltError:
+    if (IsErrorLogEnabled())
+    {
+        STRING errorLogFileName = BuildFileName(m_ErrorLogFileName);
+        if (MgFileUtil::PathnameExists(errorLogFileName))
+        {
+            m_cacheErrorLogTimestamp = MgFileUtil::GetFileModificationTime(errorLogFileName);
+        }
+    }
+
+    // mltPerformance:
+    if (IsPerformanceLogEnabled())
+    {
+        STRING performanceLogFileName = BuildFileName(m_PerformanceLogFileName);
+        if (MgFileUtil::PathnameExists(performanceLogFileName))
+        {
+            m_cachePerformanceLogTimestamp = MgFileUtil::GetFileModificationTime(performanceLogFileName);
+        }
+    }
+
+    // mltSession:
+    if (IsSessionLogEnabled())
+    {
+        STRING sessionLogFileName = BuildFileName(m_SessionLogFileName);
+        if (MgFileUtil::PathnameExists(sessionLogFileName))
+        {
+            m_cacheSessionLogTimestamp = MgFileUtil::GetFileModificationTime(sessionLogFileName);
+        }
+    }
+
+    // mltTrace:
+    if (IsTraceLogEnabled())
+    {
+        STRING traceLogFileName = BuildFileName(m_TraceLogFileName);
+        if (MgFileUtil::PathnameExists(traceLogFileName))
+        {
+            m_cacheTraceLogTimestamp = MgFileUtil::GetFileModificationTime(traceLogFileName);
+        }
+    }
+}
+
+void MgLogManager::ParseLogService(INT16 serviceType, CREFSTRING configString)
+{
+    STRING serviceString;
+    switch (serviceType)
+    {
+    case MgServiceType::ResourceService:
+        serviceString = MgResources::ResourceService;
+        break;
+    case MgServiceType::DrawingService:
+        serviceString = MgResources::DrawingService;
+        break;
+    case MgServiceType::FeatureService:
+        serviceString = MgResources::FeatureService;
+        break;
+    case MgServiceType::MappingService:
+        serviceString = MgResources::MappingService;
+        break;
+    case MgServiceType::RenderingService:
+        serviceString = MgResources::RenderingService;
+        break;
+    case MgServiceType::TileService:
+        serviceString = MgResources::TileService;
+        break;
+    case MgServiceType::KmlService:
+        serviceString = MgResources::KmlService;
+        break;
+    case MgServiceType::ServerAdminService:
+        serviceString = MgResources::ServerAdminService;
+        break;
+    case MgServiceType::SiteService:
+        serviceString = MgResources::SiteService;
+        break;
+    case MgServiceType::ProfilingService:
+        serviceString = MgResources::ProfilingService;
+        break;
+    default:
+        break;
+    }
+
+    if (!serviceString.empty())
+    {
+        STRING::size_type pos = configString.find(serviceString);
+        if (pos != configString.npos)
+        {
+            pos = configString.find(L":",pos);
+            m_logsDetail[serviceType] = (INT8) MgUtil::StringToInt32(configString.substr(pos+1,1));
+        }
+    }
+}

Added: branches/2.4/MgDev/Desktop/MgDesktop/Log/LogManager.h
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Log/LogManager.h	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Log/LogManager.h	2012-05-18 19:39:12 UTC (rev 6670)
@@ -0,0 +1,573 @@
+//
+//  Copyright (C) 2004-2011 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#ifndef MG_LOG_MANAGER_H_
+#define MG_LOG_MANAGER_H_
+
+// Undefine conflicting macros on Linux only.
+#ifndef _WIN32
+#undef min
+#undef max
+#endif
+
+#include <fstream>
+//#include "ServerManager.h"
+//#include "SessionManager.h"
+#include "LogType.h"
+//#include "SessionInfo.h"
+//#include "Connection.h"
+
+class MgLogThread;
+
+///////////////////////////////////////////////////////////////////////////////
+/// Mg Log Manager try/catch/throw macros.
+///
+#define MG_LOGMANAGER_TRY()                                                   \
+    MG_TRY()                                                                  \
+
+#define MG_LOGMANAGER_CATCH(methodName)                                       \
+    MG_CATCH(methodName)                                                      \
+
+#define MG_LOGMANAGER_THROW()                                                 \
+    MG_THROW()                                                                \
+
+#define MG_LOGMANAGER_CATCH_AND_THROW(methodName)                             \
+    MG_CATCH_AND_THROW(methodName)                                            \
+
+#define MG_LOG_SYSTEM_ENTRY(Priority, Entry) \
+  do { \
+    MgLogManager* pMan = MgLogManager::GetInstance(); \
+    pMan->LogSystemEntry(Priority, Entry); \
+  } while (0)
+
+//TODO: Log macros need session information such as client ID, version etc.
+#define MG_LOG_ACCESS_ENTRY(Entry, Client, ClientIp, UserName) \
+  do { \
+    MgLogManager* pMan = MgLogManager::GetInstance(); \
+    if(pMan->IsAccessLogEnabled()) \
+    { \
+        pMan->LogAccessEntry(Entry, Client, ClientIp, UserName); \
+    } \
+  } while (0)
+
+#define MG_LOG_ADMIN_ENTRY(Entry, Client, ClientIp, UserName) \
+  do { \
+    MgLogManager* pMan = MgLogManager::GetInstance(); \
+    if(pMan->IsAdminLogEnabled()) \
+    { \
+        pMan->LogAdminEntry(Entry, Client, ClientIp, UserName); \
+    } \
+  } while (0)
+
+#define MG_LOG_AUTHENTICATION_ENTRY(Entry) \
+  do { \
+    MgLogManager* pMan = MgLogManager::GetInstance(); \
+    if(pMan->IsAuthenticationLogEnabled()) \
+    { \
+        MG_CONNECTION_INFO \
+        pMan->LogAuthenticationEntry(Entry, connInfoClient.c_str(), connInfoClientIp.c_str(), connInfoUserName.c_str()); \
+    } \
+  } while (0)
+
+#define MG_LOG_ERROR_ENTRY(Entry) \
+  do { \
+    MgLogManager* pMan = MgLogManager::GetInstance(); \
+    if(pMan->IsErrorLogEnabled()) \
+    { \
+        MG_CONNECTION_INFO \
+        pMan->LogError(Entry, connInfoClient.c_str(), connInfoClientIp.c_str(), connInfoUserName.c_str()); \
+    } \
+  } while (0)
+
+#define MG_LOG_EXCEPTION_ENTRY(Entry, StackTrace) \
+  do { \
+    MgLogManager* pMan = MgLogManager::GetInstance(); \
+    if(pMan->IsErrorLogEnabled()) \
+    { \
+        MG_CONNECTION_INFO \
+        pMan->LogError(Entry, connInfoClient.c_str(), connInfoClientIp.c_str(), connInfoUserName.c_str(), StackTrace); \
+    } \
+  } while (0)
+
+#define MG_LOG_WARNING_ENTRY(Service, Entry, StackTrace) \
+  do { \
+    MgLogManager* pMan = MgLogManager::GetInstance(); \
+    MG_CONNECTION_INFO \
+    pMan->LogWarning(Service, Entry, connInfoClient.c_str(), connInfoClientIp.c_str(), connInfoUserName.c_str(), StackTrace); \
+  } while (0)
+
+#define MG_LOG_TRACE_ENTRY(Entry) \
+  do { \
+    MgLogManager* pMan = MgLogManager::GetInstance(); \
+    if(pMan->IsTraceLogEnabled()) \
+    { \
+        MG_CONNECTION_INFO \
+        pMan->LogTraceEntry(Entry, connInfoClient.c_str(), connInfoClientIp.c_str(), connInfoUserName.c_str()); \
+    } \
+  } while (0)
+
+#define MG_LOG_OPERATION_MESSAGE(Operation) \
+    wchar_t bufferConversion[255]; \
+    bufferConversion[0] = 0; \
+    STRING operationMessage = Operation; \
+    MG_CONNECTION_INFO
+
+#define MG_LOG_OPERATION_MESSAGE_INIT(Version, Arguments) \
+    operationMessage += L"."; \
+    INT32 tempVersion = (Version & 0x00ff0000) >> 16; \
+    ACE_OS::itoa(tempVersion, bufferConversion, 10); \
+    operationMessage += bufferConversion; \
+    operationMessage += L"."; \
+    tempVersion = (Version & 0x0000ff00) >> 8; \
+    ACE_OS::itoa(tempVersion, bufferConversion, 10); \
+    operationMessage += bufferConversion; \
+    operationMessage += L"."; \
+    tempVersion = (Version & 0x000000ff); \
+    ACE_OS::itoa(tempVersion, bufferConversion, 10); \
+    operationMessage += bufferConversion; \
+    operationMessage += L":"; \
+    ACE_OS::itoa(Arguments, bufferConversion, 10); \
+    operationMessage += bufferConversion;
+
+#define MG_LOG_OPERATION_MESSAGE_PARAMETERS_START() \
+    operationMessage += L"(";
+
+#define MG_LOG_OPERATION_MESSAGE_PARAMETERS_END() \
+    operationMessage += L") ";
+
+#define MG_LOG_OPERATION_MESSAGE_ADD_STRING(Text) \
+    operationMessage += Text;
+
+#define MG_LOG_OPERATION_MESSAGE_ADD_SEPARATOR() \
+    operationMessage += L",";
+
+#define MG_LOG_OPERATION_MESSAGE_ADD_INT32(Integer) \
+    ACE_OS::itoa(Integer, bufferConversion, 10); \
+    operationMessage += bufferConversion;
+
+#define MG_LOG_OPERATION_MESSAGE_ADD_DOUBLE(Double) \
+    ACE_OS::sprintf(bufferConversion, L"%g", Double); \
+    operationMessage += bufferConversion;
+
+#define MG_LOG_OPERATION_MESSAGE_ADD_BOOL(Boolean) \
+    if(Boolean == true) \
+    { \
+        operationMessage += L"true"; \
+    } \
+    else \
+    { \
+        operationMessage += L"false"; \
+    }
+
+#ifdef _DEBUG
+#define MG_LOG_OPERATION_MESSAGE_ACCESS_ENTRY() \
+    ACE_DEBUG((LM_DEBUG, ACE_TEXT("  (%t) %W\n"), operationMessage.c_str())); \
+    MG_LOG_ACCESS_ENTRY(operationMessage.c_str(), connInfoClient.c_str(), connInfoClientIp.c_str(), connInfoUserName.c_str());
+#else
+#define MG_LOG_OPERATION_MESSAGE_ACCESS_ENTRY() \
+    MG_LOG_ACCESS_ENTRY(operationMessage.c_str(), connInfoClient.c_str(), connInfoClientIp.c_str(), connInfoUserName.c_str());
+#endif
+
+#ifdef _DEBUG
+#define MG_LOG_OPERATION_MESSAGE_ADMIN_ENTRY() \
+    ACE_DEBUG((LM_DEBUG, ACE_TEXT("  (%t) %W\n"), operationMessage.c_str())); \
+    MG_LOG_ADMIN_ENTRY(operationMessage.c_str(), connInfoClient.c_str(), connInfoClientIp.c_str(), connInfoUserName.c_str());
+#else
+#define MG_LOG_OPERATION_MESSAGE_ADMIN_ENTRY() \
+    MG_LOG_ADMIN_ENTRY(operationMessage.c_str(), connInfoClient.c_str(), connInfoClientIp.c_str(), connInfoUserName.c_str());
+#endif
+
+
+#define MG_CONNECTION_INFO \
+    STRING connInfoClient = L""; \
+    STRING connInfoClientIp = L""; \
+    STRING connInfoUserName = L""; 
+
+class MG_DESKTOP_API MgLogManager : public MgGuardDisposable
+{
+    DECLARE_CLASSNAME(MgLogManager)
+
+public:
+    virtual ~MgLogManager();
+
+    virtual void Dispose();
+
+    static MgLogManager* GetInstance();
+    void Initialize();
+    void LoadConfigurationProperties();
+    STRING GetLogsPath();
+    void SetMaximumLogSize(INT32 size);
+    void SetLogDelimiter(CREFSTRING delimiter);
+    STRING GetLogDelimiter();
+    void EnableMaximumLogSize(bool useMaxSize);
+    bool IsMaximumLogSizeEnabled();
+
+
+    // Logging mechanism for errors and warnings
+    void LogError(CREFSTRING entry, CREFSTRING client, CREFSTRING clientIp, CREFSTRING userName, CREFSTRING stackTrace = L"");
+    void LogWarning(INT16 service, CREFSTRING entry, CREFSTRING client, CREFSTRING clientIp, CREFSTRING userName, CREFSTRING stackTrace = L"");
+
+    // Log file entry methods
+    void LogSystemEntry(ACE_Log_Priority priority, CREFSTRING entry);
+    void LogAccessEntry(CREFSTRING opId, CREFSTRING client, CREFSTRING clientIp, CREFSTRING userName);
+    void LogAdminEntry(CREFSTRING opId, CREFSTRING client, CREFSTRING clientIp, CREFSTRING userName);
+    void LogAuthenticationEntry(CREFSTRING entry, CREFSTRING client, CREFSTRING clientIp, CREFSTRING userName);
+    void LogErrorEntry(CREFSTRING entry, CREFSTRING client, CREFSTRING clientIp, CREFSTRING userName, CREFSTRING stackTrace, CREFSTRING type);
+    void LogTraceEntry(CREFSTRING entry, CREFSTRING client, CREFSTRING clientIp, CREFSTRING userName, CREFSTRING stackTrace = L"", CREFSTRING type = L"");
+    void LogSystemErrorEntry(MgException* except);
+
+    // Access log methods
+    void SetAccessLogInfo(bool bEnabled, CREFSTRING filename, CREFSTRING parameters);
+    bool IsAccessLogEnabled();
+    void SetAccessLogEnabled(bool bEnabled);
+    STRING GetAccessLogFileName();
+    void SetAccessLogFileName(CREFSTRING filename);
+    STRING GetAccessLogParameters();
+    void SetAccessLogParameters(CREFSTRING parameters);
+    bool ClearAccessLog();
+    MgByteReader* GetAccessLog();
+    MgByteReader* GetAccessLog(INT32 numEntries);
+    MgByteReader* GetAccessLog(MgDateTime* fromDate, MgDateTime* toDate);
+
+    // Admin log methods
+    void SetAdminLogInfo(bool bEnabled, CREFSTRING filename, CREFSTRING parameters);
+    bool IsAdminLogEnabled();
+    void SetAdminLogEnabled(bool bEnabled);
+    STRING GetAdminLogFileName();
+    void SetAdminLogFileName(CREFSTRING filename);
+    STRING GetAdminLogParameters();
+    void SetAdminLogParameters(CREFSTRING parameters);
+    bool ClearAdminLog();
+    MgByteReader* GetAdminLog();
+    MgByteReader* GetAdminLog(INT32 numEntries);
+    MgByteReader* GetAdminLog(MgDateTime* fromDate, MgDateTime* toDate);
+
+    // Authentication log methods
+    void SetAuthenticationLogInfo(bool bEnabled, CREFSTRING filename, CREFSTRING parameters);
+    bool IsAuthenticationLogEnabled();
+    void SetAuthenticationLogEnabled(bool bEnabled);
+    STRING GetAuthenticationLogFileName();
+    void SetAuthenticationLogFileName(CREFSTRING filename);
+    STRING GetAuthenticationLogParameters();
+    void SetAuthenticationLogParameters(CREFSTRING parameters);
+    bool ClearAuthenticationLog();
+    MgByteReader* GetAuthenticationLog();
+    MgByteReader* GetAuthenticationLog(INT32 numEntries);
+    MgByteReader* GetAuthenticationLog(MgDateTime* fromDate, MgDateTime* toDate);
+
+    // Error log methods
+    void SetErrorLogInfo(bool bEnabled, CREFSTRING filename, CREFSTRING parameters);
+    bool IsErrorLogEnabled();
+    void SetErrorLogEnabled(bool bEnabled);
+    STRING GetErrorLogFileName();
+    void SetErrorLogFileName(CREFSTRING filename);
+    STRING GetErrorLogParameters();
+    void SetErrorLogParameters(CREFSTRING parameters);
+    bool ClearErrorLog();
+    MgByteReader* GetErrorLog();
+    MgByteReader* GetErrorLog(INT32 numEntries);
+    MgByteReader* GetErrorLog(MgDateTime* fromDate, MgDateTime* toDate);
+
+    // Performance log methods
+    void SetPerformanceLogInfo(bool bEnabled, CREFSTRING filename, CREFSTRING parameters);
+    bool IsPerformanceLogEnabled();
+    void SetPerformanceLogEnabled(bool bEnabled);
+    STRING GetPerformanceLogFileName();
+    void SetPerformanceLogFileName(CREFSTRING filename);
+    STRING GetPerformanceLogParameters();
+    void SetPerformanceLogParameters(CREFSTRING parameters);
+    bool ClearPerformanceLog();
+    MgByteReader* GetPerformanceLog();
+    MgByteReader* GetPerformanceLog(INT32 numEntries);
+    MgByteReader* GetPerformanceLog(MgDateTime* fromDate, MgDateTime* toDate);
+
+    // Session log methods
+    void SetSessionLogInfo(bool bEnabled, CREFSTRING filename, CREFSTRING parameters);
+    bool IsSessionLogEnabled();
+    void SetSessionLogEnabled(bool bEnabled);
+    STRING GetSessionLogFileName();
+    void SetSessionLogFileName(CREFSTRING filename);
+    STRING GetSessionLogParameters();
+    void SetSessionLogParameters(CREFSTRING parameters);
+    bool ClearSessionLog();
+    MgByteReader* GetSessionLog();
+    MgByteReader* GetSessionLog(INT32 numEntries);
+    MgByteReader* GetSessionLog(MgDateTime* fromDate, MgDateTime* toDate);
+
+    // Trace log methods
+    void SetTraceLogInfo(bool bEnabled, CREFSTRING filename, CREFSTRING parameters);
+    bool IsTraceLogEnabled();
+    void SetTraceLogEnabled(bool bEnabled);
+    STRING GetTraceLogFileName();
+    void SetTraceLogFileName(CREFSTRING filename);
+    STRING GetTraceLogParameters();
+    void SetTraceLogParameters(CREFSTRING parameters);
+    INT8 GetDetailLevelForService(INT16 serviceNum);
+    bool ClearTraceLog();
+    MgByteReader* GetTraceLog();
+    MgByteReader* GetTraceLog(INT32 numEntries);
+    MgByteReader* GetTraceLog(MgDateTime* fromDate, MgDateTime* toDate);
+
+    MgPropertyCollection* EnumerateLogs();
+    void RenameLog(CREFSTRING oldFileName, CREFSTRING newFileName);
+    void DeleteLog(CREFSTRING fileName);
+    MgByteReader* GetLogFile(CREFSTRING filename);
+
+    static const STRING DefaultAccessLogFileName;
+    static const STRING DefaultAdminLogFileName;
+    static const STRING DefaultAuthenticationLogFileName;
+    static const STRING DefaultErrorLogFileName;
+    static const STRING DefaultPerformanceLogFileName;
+    static const STRING DefaultSessionLogFileName;
+    static const STRING DefaultTraceLogFileName;
+
+    // Write the log message to the file
+    void WriteLogMessage(enum MgLogType logType, CREFSTRING message, ACE_Log_Priority logPriority);
+
+    void StopLogThread();
+
+private:
+    // Constructor
+    MgLogManager();
+
+    static Ptr<MgLogManager> m_logManager;
+    static STRING m_path;
+    static INT32 m_maxLogSize;
+    static STRING m_delimiter;
+    std::vector<INT8> m_logsDetail;
+    static bool m_useMaxLogSize;
+
+    // Strings that represent the parameters that are used in the configuration file
+    static const STRING AverageOpTimeParam;
+    static const STRING ClientParam;
+    static const STRING ClientIpParam;
+    static const STRING DurationParam;
+    static const STRING EndTimeParam;
+    static const STRING ErrorParam;
+    static const STRING InfoParam;
+    static const STRING OpIdParam;
+    static const STRING OpsFailedParam;
+    static const STRING OpsProcessedParam;
+    static const STRING OpsReceivedParam;
+    static const STRING StackTraceParam;
+    static const STRING StartTimeParam;
+    static const STRING UserParam;
+
+    // Strings that represent the parameters that are used for the performance log
+    static const STRING PerformanceAdminOperationsQueueCount;
+    static const STRING PerformanceClientOperationsQueueCount;
+    static const STRING PerformanceSiteOperationsQueueCount;
+    static const STRING PerformanceAverageOperationTime;
+    static const STRING PerformanceCpuUtilization;
+    static const STRING PerformanceWorkingSet;
+    static const STRING PerformanceVirtualMemory;
+    static const STRING PerformanceTotalOperationTime;
+    static const STRING PerformanceTotalActiveConnections;
+    static const STRING PerformanceTotalConnections;
+    static const STRING PerformanceTotalProcessedOperations;
+    static const STRING PerformanceTotalReceivedOperations;
+    static const STRING PerformanceUptime;
+    static const STRING PerformanceCacheSize;
+    static const STRING PerformanceCacheDroppedEntries;
+
+    // Strings that represent the prefix of the header lines in the log files
+    static const STRING HeaderLine1;
+    static const STRING HeaderLine2;
+
+    // Log type strings
+    static const STRING AccessLog;
+    static const STRING AdminLog;
+    static const STRING AuthenticationLog;
+    static const STRING ErrorLog;
+    static const STRING PerformanceLog;
+    static const STRING SessionLog;
+    static const STRING TraceLog;
+    static const STRING UnspecifiedLog;
+
+    // Log file properties
+    static const STRING LogNameProperty;
+    static const STRING LogTypeProperty;
+    static const STRING LogStatusProperty;
+
+    // Log status strings
+    static const STRING LogStatusActive;
+    static const STRING LogStatusArchive;
+
+    STRING m_applicationName;
+
+    std::ofstream m_accessLogStream;
+    std::ofstream m_adminLogStream;
+    std::ofstream m_authenticationLogStream;
+    std::ofstream m_errorLogStream;
+    std::ofstream m_performanceLogStream;
+    std::ofstream m_sessionLogStream;
+    std::ofstream m_traceLogStream;
+    ACE_OSTREAM_TYPE* m_outputStream;
+
+    // ACE wrapper methods to log to the appropriate stream
+    void LogToSysLog(ACE_Log_Msg* pAce, char* application);
+    void LogToOStream(ACE_Log_Msg* pAce, ACE_OSTREAM_TYPE* output);
+    void LogToStderr(ACE_Log_Msg* pAce);
+
+    // Queue the log message
+    void QueueLogEntry(enum MgLogType logType, CREFSTRING message, ACE_Log_Priority logPriority);
+
+    // remove the specified log file
+    bool RemoveLogFile(CREFSTRING filename);
+
+    // Get the contents of the specified log
+    MgByteReader* GetLogHeader(enum MgLogType logType);
+    MgByteReader* GetLogHeader(CREFSTRING filename);
+    MgByteReader* GetLogContents(CREFSTRING filename);
+    MgByteReader* GetLogContents(CREFSTRING filename, INT32 numEntries);
+    MgByteReader* GetLogContents(enum MgLogType logType, MgDateTime* fromDate, MgDateTime* toDate);
+
+    // Replace %y %m and %d in the filename with the year month and day
+    STRING BuildFileName(CREFSTRING filename);
+    STRING BuildFileNameFromDateTime(CREFSTRING filename, MgDateTime* date);
+    MgStringCollection* DeterminePotentialFileNames(enum MgLogType logType, MgDateTime* fromDate, MgDateTime* toDate);
+
+    // Searches for the date that's closest to the date specified in the log entries
+    INT32 SearchClosestDateAfter(MgStringCollection* lines, MgDateTime* date);
+    INT32 SearchClosestDateBefore(MgStringCollection* lines, MgDateTime* date);
+
+    // Extracts the date from a log entry and returns a MgDateTime object
+    MgDateTime* GetDateTimeFromEntry(CREFSTRING entry);
+
+    // Compares two MgDateTimes to see if they are more than 24 hours apart
+    bool IsMoreThan24HourDiff(MgDateTime* date1, MgDateTime* date2);
+
+    // Helper methods.
+    void AddDateTime(REFSTRING entry, const MgDateTime& value);
+    void AddDouble(REFSTRING entry, double value);
+    void AddInt32(REFSTRING entry, INT32 value);
+    void AddString(REFSTRING entry, CREFSTRING value);
+
+    // Add the parameter specified in the configuration file to the log entry
+    void AddClient(REFSTRING entry, CREFSTRING client);
+    void AddClientIp(REFSTRING entry, CREFSTRING clientIp);
+    void AddError(REFSTRING entry, CREFSTRING error, CREFSTRING type);
+    void AddInfo(REFSTRING entry, CREFSTRING info);
+    void AddOpId(REFSTRING entry, CREFSTRING opId);
+    void AddStackTrace(REFSTRING entry, CREFSTRING stackTrace);
+    void AddThreadId(REFSTRING entry);
+    void AddUserName(REFSTRING entry, CREFSTRING userName);
+
+    // Check if the log file has reached the maximum size
+    bool IsMaxSizeExceeded(CREFSTRING logFilename);
+
+    // Create an archive of the specified log
+    void ArchiveLog(enum MgLogType logType);
+
+    // Check if existing log files contain valid header information
+    void ValidateLogHeaders(enum MgLogType logType);
+    bool ValidateAccessLogHeader();
+    bool ValidateAdminLogHeader();
+    bool ValidateAuthenticationLogHeader();
+    bool ValidateErrorLogHeader();
+    bool ValidatePerformanceLogHeader();
+    bool ValidateSessionLogHeader();
+    bool ValidateTraceLogHeader();
+
+    // Helper function to retrive the first header line the logs
+    STRING ReadLogTypeFromLogFile(CREFSTRING logFilename);
+
+    // Helper function to retrieve the second header line in the logs
+    STRING ReadParametersFromLogFile(enum MgLogType logType);
+
+    // Helper function to identify if a log is an archived or currently active
+    STRING DetermineLogFileStatus(CREFSTRING logFilename, CREFSTRING logFileType);
+
+    void AddDelimiter(REFSTRING entry);
+    void TranslateDelimiter();
+
+    void ParseLogService(INT16 serviceType, CREFSTRING configString);
+
+    // Helper function to determine and archive should be created based on the specified archive frequency
+    bool CheckArchiveFrequency(enum MgLogType logType, CREFSTRING logFilename);
+
+    // Helper function to remove the archive frequency specifier from the filename
+    STRING RemoveArchiveFrequencySpecifier(CREFSTRING logFilename);
+
+    STRING ValidateLogFileName(CREFSTRING filename);
+
+    bool IsLogFileInUse(CREFSTRING filename, enum MgLogType& logType);
+    bool IsLogInUse(enum MgLogType& logType);
+    void EnableLog(enum MgLogType logType);
+    void DisableLog(enum MgLogType logType);
+    void SetLogHasHeader(enum MgLogType logType, bool bHeader);
+    bool LogHasHeader(enum MgLogType logType);
+
+    void UpdateLogFilesTimestampCache();
+
+    // Access Log
+    bool m_bAccessLogEnabled;
+    bool m_bAccessLogHeader;
+    STRING m_AccessLogFileName;
+    STRING m_AccessLogParameters;
+
+    // Admin Log
+    bool m_bAdminLogEnabled;
+    bool m_bAdminLogHeader;
+    STRING m_AdminLogFileName;
+    STRING m_AdminLogParameters;
+
+    // Authentication Log
+    bool m_bAuthenticationLogEnabled;
+    bool m_bAuthenticationLogHeader;
+    STRING m_AuthenticationLogFileName;
+    STRING m_AuthenticationLogParameters;
+
+    // Error Log
+    bool m_bErrorLogEnabled;
+    bool m_bErrorLogHeader;
+    STRING m_ErrorLogFileName;
+    STRING m_ErrorLogParameters;
+
+    // Performance Log
+    bool m_bPerformanceLogEnabled;
+    bool m_bPerformanceLogHeader;
+    STRING m_PerformanceLogFileName;
+    STRING m_PerformanceLogParameters;
+
+    // Session Log
+    bool m_bSessionLogEnabled;
+    bool m_bSessionLogHeader;
+    STRING m_SessionLogFileName;
+    STRING m_SessionLogParameters;
+
+    // Trace Log
+    bool m_bTraceLogEnabled;
+    bool m_bTraceLogHeader;
+    STRING m_TraceLogFileName;
+    STRING m_TraceLogParameters;
+
+    ACE_Recursive_Thread_Mutex m_mutex;
+    ACE_Thread_Manager m_threadManager;
+    MgLogThread* m_pLogThread;
+    INT64 m_writeCount;
+
+    MgDateTime m_cacheAccessLogTimestamp;
+    MgDateTime m_cacheAdminLogTimestamp;
+    MgDateTime m_cacheAuthenticationLogTimestamp;
+    MgDateTime m_cacheErrorLogTimestamp;
+    MgDateTime m_cachePerformanceLogTimestamp;
+    MgDateTime m_cacheSessionLogTimestamp;
+    MgDateTime m_cacheTraceLogTimestamp;
+};
+
+#endif

Added: branches/2.4/MgDev/Desktop/MgDesktop/Log/LogThread.cpp
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Log/LogThread.cpp	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Log/LogThread.cpp	2012-05-18 19:39:12 UTC (rev 6670)
@@ -0,0 +1,195 @@
+//
+//  Copyright (C) 2004-2011 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#include "MgDesktop.h"
+#include "LogThread.h"
+#include "LogEntryData.h"
+//#include "ServerManager.h"
+#include "LogManager.h"
+
+//////////////////////////////////////////////////////////////////
+/// <summary>
+/// Constructor
+/// </summary>
+MgLogThread::MgLogThread(ACE_Thread_Manager &tm, INT32 nThreads) :
+    MgThreadBase(tm, nThreads)
+{
+    m_bActive = true;
+}
+
+//////////////////////////////////////////////////////////////////
+/// <summary>
+/// ACE_Task method
+/// </summary>
+int MgLogThread::svc()
+{
+    INT32 nResult = 0;
+
+    Ptr<MgException> mgException;
+    try
+    {
+        MgLogManager* pLogManager = MgLogManager::GetInstance();
+
+        while (m_bActive)
+        {
+//            ACE_DEBUG ((LM_DEBUG, ACE_TEXT("(%t) MgLogThread::svc() Ready\n")));
+
+            ACE_Message_Block* messageBlock = NULL;
+
+            nResult = getq(messageBlock);
+            if(nResult == -1)
+            {
+                INT32 nError = ACE_OS::last_error();
+
+                if(nError == EINTR)
+                {
+                    ACE_DEBUG ((LM_DEBUG, ACE_TEXT("  (%t) Interrupted while waiting for message\n")));
+                    ACE_DEBUG ((LM_DEBUG, ACE_TEXT("  (%t) MgLogThread - Exiting thread\n")));
+                    return 0;
+                }
+                else
+                {
+                    // There was an error
+                    ACE_DEBUG ((LM_DEBUG, ACE_TEXT("  (%t) MgLogThread - Exiting thread\n")));
+                    ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT("%p\n"), ACE_TEXT("MgLogThread::svc()")), -1);
+                }
+            }
+
+            if(messageBlock)
+            {
+                if(messageBlock->msg_type() == ACE_Message_Block::MB_STOP)
+                {
+                    m_bActive = false;
+
+                    ACE_Message_Block* mb = new ACE_Message_Block(4);
+                    if(mb)
+                    {
+                        mb->msg_type(ACE_Message_Block::MB_STOP);
+                        putq(mb);
+                    }
+                }
+                else if(messageBlock->msg_type() == ACE_Message_Block::MB_DATA)
+                {
+                    // Get the function
+                    MgLogEntryData* led = (MgLogEntryData*)messageBlock->data_block();
+                    if(led)
+                    {
+                        Ptr<MgException> mgException;
+                        try
+                        {
+                            pLogManager->WriteLogMessage(led->m_logType, led->m_message, led->m_logPriority);
+                        }
+                        catch(MgException* e)
+                        {
+                            //MgServerManager* pServerManager = MgServerManager::GetInstance();
+                            //STRING locale = pServerManager->GetDefaultMessageLocale();
+                            STRING locale = MgResources::DefaultMessageLocale;
+                            ACE_DEBUG ((LM_ERROR, ACE_TEXT("(%t) %W\n"), e->GetDetails(locale).c_str()));
+                            MG_LOG_EXCEPTION_ENTRY(e->GetExceptionMessage(locale).c_str(), e->GetStackTrace(locale).c_str());
+
+                            SAFE_RELEASE(e);
+                        }
+                        catch(FdoException* e)
+                        {
+                            STRING messageId;
+                            MgStringCollection arguments;
+                            wchar_t* buf = (wchar_t*)e->GetExceptionMessage();
+
+                            if (NULL != buf)
+                            {
+                                messageId = L"MgFormatInnerExceptionMessage";
+                                arguments.Add(buf);
+                            }
+
+                            //MgServerManager* pServerManager = MgServerManager::GetInstance();
+                            //STRING locale = pServerManager->GetDefaultMessageLocale();
+                            STRING locale = MgResources::DefaultMessageLocale;
+                            mgException = new MgFdoException(L"MgLogThread.svc", __LINE__, __WFILE__, NULL, messageId, &arguments);
+                            ACE_DEBUG ((LM_ERROR, ACE_TEXT("(%t) %W\n"), mgException->GetDetails(locale).c_str()));
+                            MG_LOG_EXCEPTION_ENTRY(mgException->GetExceptionMessage(locale).c_str(), mgException->GetStackTrace(locale).c_str());
+
+                            FDO_SAFE_RELEASE(e);
+                        }
+                        catch (exception& e)
+                        {
+                            //MgServerManager* pServerManager = MgServerManager::GetInstance();
+                            //STRING locale = pServerManager->GetDefaultMessageLocale();
+                            STRING locale = MgResources::DefaultMessageLocale;
+
+                            mgException = MgSystemException::Create(e, L"MgLogThread.svc", __LINE__, __WFILE__);
+                            ACE_DEBUG ((LM_ERROR, ACE_TEXT("(%t) %W\n"), mgException->GetDetails(locale).c_str()));
+                            MG_LOG_EXCEPTION_ENTRY(mgException->GetExceptionMessage(locale).c_str(), mgException->GetStackTrace(locale).c_str());
+                        }
+                        catch(...)
+                        {
+                            //MgServerManager* pServerManager = MgServerManager::GetInstance();
+                            //STRING locale = pServerManager->GetDefaultMessageLocale();
+                            STRING locale = MgResources::DefaultMessageLocale;
+                            mgException = new MgUnclassifiedException(L"MgLogThread.svc", __LINE__, __WFILE__, NULL, L"", NULL);
+                            ACE_DEBUG ((LM_ERROR, ACE_TEXT("(%t) %W\n"), mgException->GetDetails(locale).c_str()));
+                            MG_LOG_EXCEPTION_ENTRY(mgException->GetExceptionMessage(locale).c_str(), mgException->GetStackTrace(locale).c_str());
+                        }
+                    }
+                }
+
+                //  Cleanup message block
+                messageBlock->release();
+                messageBlock = NULL;
+            }
+        }
+    }
+    catch (MgException* e)
+    {
+        //MgServerManager* pServerManager = MgServerManager::GetInstance();
+        //STRING locale = pServerManager->GetDefaultMessageLocale();
+        STRING locale = MgResources::DefaultMessageLocale;
+
+        ACE_DEBUG ((LM_ERROR, ACE_TEXT("(%t) %W\n"), e->GetDetails(locale).c_str()));
+        MG_LOG_EXCEPTION_ENTRY(e->GetExceptionMessage(locale).c_str(), e->GetStackTrace(locale).c_str());
+
+        SAFE_RELEASE(e);
+
+        nResult = -1;
+    }
+    catch (exception& e)
+    {
+        //MgServerManager* pServerManager = MgServerManager::GetInstance();
+        //STRING locale = pServerManager->GetDefaultMessageLocale();
+        STRING locale = MgResources::DefaultMessageLocale;
+
+        mgException = MgSystemException::Create(e, L"MgLogThread.svc", __LINE__, __WFILE__);
+        ACE_DEBUG ((LM_ERROR, ACE_TEXT("(%t) %W\n"), mgException->GetDetails(locale).c_str()));
+        MG_LOG_EXCEPTION_ENTRY(mgException->GetExceptionMessage(locale).c_str(), mgException->GetStackTrace(locale).c_str());
+
+        nResult = -1;
+    }
+    catch (...)
+    {
+        //MgServerManager* pServerManager = MgServerManager::GetInstance();
+        //STRING locale = pServerManager->GetDefaultMessageLocale();
+        STRING locale = MgResources::DefaultMessageLocale;
+
+        mgException = new MgUnclassifiedException(L"MgLogThread.svc", __LINE__, __WFILE__, NULL, L"", NULL);
+        ACE_DEBUG ((LM_ERROR, ACE_TEXT("(%t) %W\n"), mgException->GetDetails(locale).c_str()));
+        MG_LOG_EXCEPTION_ENTRY(mgException->GetExceptionMessage(locale).c_str(), mgException->GetStackTrace(locale).c_str());
+
+        nResult = -1;
+    }
+
+    ACE_DEBUG ((LM_DEBUG, ACE_TEXT("(%t) MgLogThread - Exiting thread\n")));
+    return nResult;
+}

Added: branches/2.4/MgDev/Desktop/MgDesktop/Log/LogThread.h
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Log/LogThread.h	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Log/LogThread.h	2012-05-18 19:39:12 UTC (rev 6670)
@@ -0,0 +1,45 @@
+//
+//  Copyright (C) 2004-2011 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#ifndef MG_LOG_THREAD_H
+#define MG_LOG_THREAD_H
+
+#include "MgDesktop.h"
+#include "System/ThreadBase.h"
+
+class MgLogThread : public MgThreadBase
+{
+    DECLARE_CLASSNAME(MgLogThread)
+
+    ///////////////////////////////////////////////////////
+    /// Methods
+public:
+    MgLogThread(ACE_Thread_Manager &tm, INT32 nThreads);
+
+    // ACE_Task methods
+    virtual int svc();
+
+    // Class methods
+private:
+
+    ///////////////////////////////////////////////////////
+    /// Member data
+private:
+    bool m_bActive;
+};
+
+#endif

Added: branches/2.4/MgDev/Desktop/MgDesktop/Log/LogType.h
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Log/LogType.h	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Log/LogType.h	2012-05-18 19:39:12 UTC (rev 6670)
@@ -0,0 +1,33 @@
+//
+//  Copyright (C) 2004-2011 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#ifndef MGLOGTYPE_H
+#define MGLOGTYPE_H
+
+enum MgLogType
+{
+    mltSystem,
+    mltAccess,
+    mltAdmin,
+    mltAuthentication,
+    mltError,
+    mltSession,
+    mltTrace,
+    mltPerformance
+};
+
+#endif

Modified: branches/2.4/MgDev/Desktop/MgDesktop/MgDesktop.h
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/MgDesktop.h	2012-05-18 15:54:57 UTC (rev 6669)
+++ branches/2.4/MgDev/Desktop/MgDesktop/MgDesktop.h	2012-05-18 19:39:12 UTC (rev 6670)
@@ -32,6 +32,7 @@
 #include "Exception/InvalidDwfPackageException.h"
 #include "Exception/InvalidDwfSectionException.h"
 #include "Exception/InvalidFeatureSourceException.h"
+#include "Exception/InvalidLogEntryException.h"
 #include "Exception/InvalidPrintLayoutFontSizeUnitsException.h"
 #include "Exception/InvalidPrintLayoutPositionUnitsException.h"
 #include "Exception/InvalidPrintLayoutSizeUnitsException.h"
@@ -75,10 +76,6 @@
 #define NOT_IMPLEMENTED(method) \
 	throw new MgNotImplementedException(method, __LINE__, __WFILE__, NULL, L"", NULL)
 
-//Stub for now
-#define MG_LOG_TRACE_ENTRY(method)
-#define MG_LOG_ERROR_ENTRY(message)
-
 //Uncomment to debug memory leaks. This is the header for Visual Leak Detector
 //See: http://vld.codeplex.com for download and setup
 #ifdef _WIN32

Modified: branches/2.4/MgDev/Desktop/MgDesktop/MgDesktop.vcproj
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/MgDesktop.vcproj	2012-05-18 15:54:57 UTC (rev 6669)
+++ branches/2.4/MgDev/Desktop/MgDesktop/MgDesktop.vcproj	2012-05-18 19:39:12 UTC (rev 6670)
@@ -1804,6 +1804,42 @@
 				</FileConfiguration>
 			</File>
 			<File
+				RelativePath=".\Exception\InvalidLogEntryException.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug|x64"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|x64"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+			</File>
+			<File
 				RelativePath=".\Exception\InvalidPrintLayoutFontSizeUnitsException.cpp"
 				>
 				<FileConfiguration
@@ -2056,6 +2092,150 @@
 				</FileConfiguration>
 			</File>
 			<File
+				RelativePath=".\Log\LogDetail.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug|x64"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|x64"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath=".\Log\LogEntryData.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug|x64"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|x64"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath=".\Log\LogManager.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug|x64"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|x64"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath=".\Log\LogThread.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug|x64"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|x64"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+			</File>
+			<File
 				RelativePath=".\MapLayer\Map.cpp"
 				>
 				<FileConfiguration
@@ -3284,6 +3464,42 @@
 				</FileConfiguration>
 			</File>
 			<File
+				RelativePath=".\System\ThreadBase.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug|x64"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|x64"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+			</File>
+			<File
 				RelativePath=".\Services\Tile\TileCache.cpp"
 				>
 				<FileConfiguration
@@ -3902,6 +4118,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\Exception\InvalidLogEntryException.h"
+				>
+			</File>
+			<File
 				RelativePath=".\Exception\InvalidPrintLayoutFontSizeUnitsException.h"
 				>
 			</File>
@@ -3930,6 +4150,26 @@
 				>
 			</File>
 			<File
+				RelativePath=".\Log\LogDetail.h"
+				>
+			</File>
+			<File
+				RelativePath=".\Log\LogEntryData.h"
+				>
+			</File>
+			<File
+				RelativePath=".\Log\LogManager.h"
+				>
+			</File>
+			<File
+				RelativePath=".\Log\LogThread.h"
+				>
+			</File>
+			<File
+				RelativePath=".\Log\LogType.h"
+				>
+			</File>
+			<File
 				RelativePath=".\MapLayer\Map.h"
 				>
 			</File>
@@ -4098,6 +4338,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\System\ThreadBase.h"
+				>
+			</File>
+			<File
 				RelativePath=".\Services\Tile\TileCache.h"
 				>
 			</File>

Modified: branches/2.4/MgDev/Desktop/MgDesktop/MgDesktopBuild.cpp
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/MgDesktopBuild.cpp	2012-05-18 15:54:57 UTC (rev 6669)
+++ branches/2.4/MgDev/Desktop/MgDesktop/MgDesktopBuild.cpp	2012-05-18 19:39:12 UTC (rev 6670)
@@ -1,6 +1,7 @@
 #include "System/ConfigProperties.cpp"
 #include "System/PlatformInit.cpp"
 #include "System/TimerUtil.cpp"
+#include "System/ThreadBase.cpp"
 
 #include "Exception/AliasNotFoundException.cpp"
 #include "Exception/ConnectionFailedException.cpp"
@@ -11,12 +12,18 @@
 #include "Exception/InvalidDwfPackageException.cpp"
 #include "Exception/InvalidDwfSectionException.cpp"
 #include "Exception/InvalidFeatureSourceException.cpp"
+#include "Exception/InvalidLogEntryException.cpp"
 #include "Exception/InvalidPrintLayoutFontSizeUnitsException.cpp"
 #include "Exception/InvalidPrintLayoutPositionUnitsException.cpp"
 #include "Exception/InvalidPrintLayoutSizeUnitsException.cpp"
 #include "Exception/ParameterNotFoundException.cpp"
 #include "Exception/StylizeLayerFailedException.cpp"
 
+#include "Log/LogDetail.cpp"
+#include "Log/LogEntryData.cpp"
+#include "Log/LogManager.cpp"
+#include "Log/LogThread.cpp"
+
 #include "MapLayer/Layer.cpp"
 #include "MapLayer/Map.cpp"
 #include "MapLayer/Selection.cpp"

Modified: branches/2.4/MgDev/Desktop/MgDesktop/Platform.ini
===================================================================
(Binary files differ)

Modified: branches/2.4/MgDev/Desktop/MgDesktop/System/ConfigProperties.cpp
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/System/ConfigProperties.cpp	2012-05-18 15:54:57 UTC (rev 6669)
+++ branches/2.4/MgDev/Desktop/MgDesktop/System/ConfigProperties.cpp	2012-05-18 19:39:12 UTC (rev 6670)
@@ -135,6 +135,16 @@
 const STRING MgConfigProperties::DefaultGeneralPropertyRenderer                             = L"GD";
 const STRING MgConfigProperties::GeneralPropertyPreCacheMaps                                = L"PreCacheMaps";
 const STRING MgConfigProperties::DefaultGeneralPropertyPreCacheMaps                         = L"";
+const STRING MgConfigProperties::GeneralPropertyLogsDelimiter                               = L"LogsDelimiter";
+const STRING MgConfigProperties::DefaultGeneralPropertyLogsDelimiter                        = L"\t";
+const STRING MgConfigProperties::GeneralPropertyLogsDetail                                  = L"LogsDetail";
+const STRING MgConfigProperties::DefaultGeneralPropertyLogsDetail                           = L"";
+const STRING MgConfigProperties::GeneralPropertyLogsPath                                    = L"LogsPath";
+const STRING MgConfigProperties::DefaultGeneralPropertyLogsPath                             = L"Logs/";
+const STRING MgConfigProperties::GeneralPropertyMaxLogFileSize                              = L"MaxLogFileSize";
+const INT32  MgConfigProperties::DefaultGeneralPropertyMaxLogFileSize                       = 1024;
+const STRING MgConfigProperties::GeneralPropertyMaxLogFileSizeEnabled                       = L"MaxLogFileSizeEnabled";
+const bool   MgConfigProperties::DefaultGeneralPropertyMaxLogFileSizeEnabled                = false;
 
 // ******************************************************************
 // Drawing Service Properties
@@ -287,6 +297,85 @@
 const STRING MgConfigProperties::TileServicePropertyImageFormat                             = L"ImageFormat";
 const STRING MgConfigProperties::DefaultTileServicePropertyImageFormat                      = L"PNG";
 
+// ******************************************************************
+// Access Log Properties
+// ******************************************************************
+const STRING MgConfigProperties::AccessLogPropertiesSection                                 = L"AccessLogProperties";
+const STRING MgConfigProperties::AccessLogPropertyEnabled                                   = L"Enabled";
+const bool   MgConfigProperties::DefaultAccessLogPropertyEnabled                            = true;
+const STRING MgConfigProperties::AccessLogPropertyFilename                                  = L"Filename";
+const STRING MgConfigProperties::DefaultAccessLogPropertyFilename                           = L"Access.log";
+const STRING MgConfigProperties::AccessLogPropertyParameters                                = L"Parameters";
+const STRING MgConfigProperties::DefaultAccessLogPropertyParameters                         = L"";
+
+// ******************************************************************
+// Admin Log Properties
+// ******************************************************************
+const STRING MgConfigProperties::AdminLogPropertiesSection                                  = L"AdminLogProperties";
+const STRING MgConfigProperties::AdminLogPropertyEnabled                                    = L"Enabled";
+const bool   MgConfigProperties::DefaultAdminLogPropertyEnabled                             = true;
+const STRING MgConfigProperties::AdminLogPropertyFilename                                   = L"Filename";
+const STRING MgConfigProperties::DefaultAdminLogPropertyFilename                            = L"Admin.log";
+const STRING MgConfigProperties::AdminLogPropertyParameters                                 = L"Parameters";
+const STRING MgConfigProperties::DefaultAdminLogPropertyParameters                          = L"";
+
+// ******************************************************************
+// Authentication Log Properties
+// ******************************************************************
+const STRING MgConfigProperties::AuthenticationLogPropertiesSection                         = L"AuthenticationLogProperties";
+const STRING MgConfigProperties::AuthenticationLogPropertyEnabled                           = L"Enabled";
+const bool   MgConfigProperties::DefaultAuthenticationLogPropertyEnabled                    = true;
+const STRING MgConfigProperties::AuthenticationLogPropertyFilename                          = L"Filename";
+const STRING MgConfigProperties::DefaultAuthenticationLogPropertyFilename                   = L"Authentication.log";
+const STRING MgConfigProperties::AuthenticationLogPropertyParameters                        = L"Parameters";
+const STRING MgConfigProperties::DefaultAuthenticationLogPropertyParameters                 = L"";
+
+// ******************************************************************
+// Error Log Properties
+// ******************************************************************
+const STRING MgConfigProperties::ErrorLogPropertiesSection                                  = L"ErrorLogProperties";
+const STRING MgConfigProperties::ErrorLogPropertyEnabled                                    = L"Enabled";
+const bool   MgConfigProperties::DefaultErrorLogPropertyEnabled                             = true;
+const STRING MgConfigProperties::ErrorLogPropertyFilename                                   = L"Filename";
+const STRING MgConfigProperties::DefaultErrorLogPropertyFilename                            = L"Error.log";
+const STRING MgConfigProperties::ErrorLogPropertyParameters                                 = L"Parameters";
+const STRING MgConfigProperties::DefaultErrorLogPropertyParameters                          = L"";
+
+// ******************************************************************
+// Performance Log Properties
+// ******************************************************************
+const STRING MgConfigProperties::PerformanceLogPropertiesSection                            = L"PerformanceLogProperties";
+const STRING MgConfigProperties::PerformanceLogPropertyEnabled                              = L"Enabled";
+const bool   MgConfigProperties::DefaultPerformanceLogPropertyEnabled                       = false;
+const STRING MgConfigProperties::PerformanceLogPropertyFilename                             = L"Filename";
+const STRING MgConfigProperties::DefaultPerformanceLogPropertyFilename                      = L"Performance.log";
+const STRING MgConfigProperties::PerformanceLogPropertyParameters                           = L"Parameters";
+const STRING MgConfigProperties::DefaultPerformanceLogPropertyParameters                    = L"";
+const STRING MgConfigProperties::PerformanceLogPropertyInterval                             = L"Interval";
+const INT32  MgConfigProperties::DefaultPerformanceLogPropertyInterval                      = 300;
+
+// ******************************************************************
+// Session Log Properties
+// ******************************************************************
+const STRING MgConfigProperties::SessionLogPropertiesSection                                = L"SessionLogProperties";
+const STRING MgConfigProperties::SessionLogPropertyEnabled                                  = L"Enabled";
+const bool   MgConfigProperties::DefaultSessionLogPropertyEnabled                           = false;
+const STRING MgConfigProperties::SessionLogPropertyFilename                                 = L"Filename";
+const STRING MgConfigProperties::DefaultSessionLogPropertyFilename                          = L"Session.log";
+const STRING MgConfigProperties::SessionLogPropertyParameters                               = L"Parameters";
+const STRING MgConfigProperties::DefaultSessionLogPropertyParameters                        = L"";
+
+// ******************************************************************
+// Trace Log Properties
+// ******************************************************************
+const STRING MgConfigProperties::TraceLogPropertiesSection                                  = L"TraceLogProperties";
+const STRING MgConfigProperties::TraceLogPropertyEnabled                                    = L"Enabled";
+const bool   MgConfigProperties::DefaultTraceLogPropertyEnabled                             = false;
+const STRING MgConfigProperties::TraceLogPropertyFilename                                   = L"Filename";
+const STRING MgConfigProperties::DefaultTraceLogPropertyFilename                            = L"Trace.log";
+const STRING MgConfigProperties::TraceLogPropertyParameters                                 = L"Parameters";
+const STRING MgConfigProperties::DefaultTraceLogPropertyParameters                          = L"";
+
 ///////////////////////////////////////////////////////////////////////////////
 /// Common Configuration Validation Information Maps
 ///
@@ -390,3 +479,60 @@
     { MgConfigProperties::TileServicePropertyImageFormat                            , MgPropertyType::String    , 2                                     , 4                                     , L""                                       },
     { L""                                                                           , 0                         , 0.0                                   , 0.0                                   , L""                                       }
 };
+
+const MgConfigValidationInfo MgConfigProperties::sm_cviAccessLogProperties[] =
+{
+    { MgConfigProperties::AccessLogPropertyEnabled                                  , MgPropertyType::Boolean   , 0                                     , 1                                     , L""                                       },
+    { MgConfigProperties::AccessLogPropertyFilename                                 , MgPropertyType::String    , MG_CONFIG_MIN_FILE_NAME_LENGTH        , MG_CONFIG_MAX_FILE_NAME_LENGTH        , MG_CONFIG_FILE_NAME_RESERVED_CHARACTERS   },
+    { MgConfigProperties::AccessLogPropertyParameters                               , MgPropertyType::String    , MG_CONFIG_MIN_LOG_PARAMETERS_LENGTH   , MG_CONFIG_MAX_LOG_PARAMETERS_LENGTH   , L""                                       },
+    { L""                                                                           , 0                         , 0.0                                   , 0.0                                   , L""                                       }
+};
+
+const MgConfigValidationInfo MgConfigProperties::sm_cviAdminLogProperties[] =
+{
+    { MgConfigProperties::AdminLogPropertyEnabled                                   , MgPropertyType::Boolean   , 0                                     , 1                                     , L""                                       },
+    { MgConfigProperties::AdminLogPropertyFilename                                  , MgPropertyType::String    , MG_CONFIG_MIN_FILE_NAME_LENGTH        , MG_CONFIG_MAX_FILE_NAME_LENGTH        , MG_CONFIG_FILE_NAME_RESERVED_CHARACTERS   },
+    { MgConfigProperties::AdminLogPropertyParameters                                , MgPropertyType::String    , MG_CONFIG_MIN_LOG_PARAMETERS_LENGTH   , MG_CONFIG_MAX_LOG_PARAMETERS_LENGTH   , L""                                       },
+    { L""                                                                           , 0                         , 0.0                                   , 0.0                                   , L""                                       }
+};
+
+const MgConfigValidationInfo MgConfigProperties::sm_cviAuthenticationLogProperties[] =
+{
+    { MgConfigProperties::AuthenticationLogPropertyEnabled                          , MgPropertyType::Boolean   , 0                                     , 1                                     , L""                                       },
+    { MgConfigProperties::AuthenticationLogPropertyFilename                         , MgPropertyType::String    , MG_CONFIG_MIN_FILE_NAME_LENGTH        , MG_CONFIG_MAX_FILE_NAME_LENGTH        , MG_CONFIG_FILE_NAME_RESERVED_CHARACTERS   },
+    { MgConfigProperties::AuthenticationLogPropertyParameters                       , MgPropertyType::String    , MG_CONFIG_MIN_LOG_PARAMETERS_LENGTH   , MG_CONFIG_MAX_LOG_PARAMETERS_LENGTH   , L""                                       },
+    { L""                                                                           , 0                         , 0.0                                   , 0.0                                   , L""                                       }
+};
+
+const MgConfigValidationInfo MgConfigProperties::sm_cviErrorLogProperties[] =
+{
+    { MgConfigProperties::ErrorLogPropertyEnabled                                   , MgPropertyType::Boolean   , 0                                     , 1                                     , L""                                       },
+    { MgConfigProperties::ErrorLogPropertyFilename                                  , MgPropertyType::String    , MG_CONFIG_MIN_FILE_NAME_LENGTH        , MG_CONFIG_MAX_FILE_NAME_LENGTH        , MG_CONFIG_FILE_NAME_RESERVED_CHARACTERS   },
+    { MgConfigProperties::ErrorLogPropertyParameters                                , MgPropertyType::String    , MG_CONFIG_MIN_LOG_PARAMETERS_LENGTH   , MG_CONFIG_MAX_LOG_PARAMETERS_LENGTH   , L""                                       },
+    { L""                                                                           , 0                         , 0.0                                   , 0.0                                   , L""                                       }
+};
+
+const MgConfigValidationInfo MgConfigProperties::sm_cviPerformanceLogProperties[] =
+{
+    { MgConfigProperties::PerformanceLogPropertyEnabled                             , MgPropertyType::Boolean   , 0                                     , 1                                     , L""                                       },
+    { MgConfigProperties::PerformanceLogPropertyFilename                            , MgPropertyType::String    , MG_CONFIG_MIN_FILE_NAME_LENGTH        , MG_CONFIG_MAX_FILE_NAME_LENGTH        , MG_CONFIG_FILE_NAME_RESERVED_CHARACTERS   },
+    { MgConfigProperties::PerformanceLogPropertyParameters                          , MgPropertyType::String    , MG_CONFIG_MIN_LOG_PARAMETERS_LENGTH   , MG_CONFIG_MAX_LOG_PARAMETERS_LENGTH   , L""                                       },
+    { MgConfigProperties::PerformanceLogPropertyInterval                            , MgPropertyType::Int32     , 0                                     , 60000                                 , L""                                       },
+    { L""                                                                           , 0                         , 0.0                                   , 0.0                                   , L""                                       }
+};
+
+const MgConfigValidationInfo MgConfigProperties::sm_cviSessionLogProperties[] =
+{
+    { MgConfigProperties::SessionLogPropertyEnabled                                 , MgPropertyType::Boolean   , 0                                     , 1                                     , L""                                       },
+    { MgConfigProperties::SessionLogPropertyFilename                                , MgPropertyType::String    , MG_CONFIG_MIN_FILE_NAME_LENGTH        , MG_CONFIG_MAX_FILE_NAME_LENGTH        , MG_CONFIG_FILE_NAME_RESERVED_CHARACTERS   },
+    { MgConfigProperties::SessionLogPropertyParameters                              , MgPropertyType::String    , MG_CONFIG_MIN_LOG_PARAMETERS_LENGTH   , MG_CONFIG_MAX_LOG_PARAMETERS_LENGTH   , L""                                       },
+    { L""                                                                           , 0                         , 0.0                                   , 0.0                                   , L""                                       }
+};
+
+const MgConfigValidationInfo MgConfigProperties::sm_cviTraceLogProperties[] =
+{
+    { MgConfigProperties::TraceLogPropertyEnabled                                   , MgPropertyType::Boolean   , 0                                     , 1                                     , L""                                       },
+    { MgConfigProperties::TraceLogPropertyFilename                                  , MgPropertyType::String    , MG_CONFIG_MIN_FILE_NAME_LENGTH        , MG_CONFIG_MAX_FILE_NAME_LENGTH        , MG_CONFIG_FILE_NAME_RESERVED_CHARACTERS   },
+    { MgConfigProperties::TraceLogPropertyParameters                                , MgPropertyType::String    , MG_CONFIG_MIN_LOG_PARAMETERS_LENGTH   , MG_CONFIG_MAX_LOG_PARAMETERS_LENGTH   , L""                                       },
+    { L""                                                                           , 0                         , 0.0                                   , 0.0                                   , L""                                       }
+};
\ No newline at end of file

Modified: branches/2.4/MgDev/Desktop/MgDesktop/System/ConfigProperties.h
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/System/ConfigProperties.h	2012-05-18 15:54:57 UTC (rev 6669)
+++ branches/2.4/MgDev/Desktop/MgDesktop/System/ConfigProperties.h	2012-05-18 19:39:12 UTC (rev 6670)
@@ -75,6 +75,26 @@
     static const STRING GeneralPropertyPreCacheMaps;                    /// value("PreCacheMaps")
     static const STRING DefaultGeneralPropertyPreCacheMaps;             /// value("")
 
+    /// Sets the field delimiter in the logs
+    static const STRING GeneralPropertyLogsDelimiter;                   /// value("LogsDelimiter")
+    static const STRING DefaultGeneralPropertyLogsDelimiter;            /// value("\t")
+
+    /// Log detail level for services
+    static const STRING GeneralPropertyLogsDetail;                      /// value("LogsDetail")
+    static const STRING DefaultGeneralPropertyLogsDetail;               /// value("")
+
+    /// Root folder for server's log files
+    static const STRING GeneralPropertyLogsPath;                        /// value("LogsPath")
+    static const STRING DefaultGeneralPropertyLogsPath;                 /// value("Logs/")
+
+    /// Sets the maximum log file size (in kilobytes)
+    static const STRING GeneralPropertyMaxLogFileSize;                  /// value("MaxLogFileSize")
+    static const INT32 DefaultGeneralPropertyMaxLogFileSize;            /// value(64)
+
+    /// Specifies whether the maximum log size restriction is enabled
+    static const STRING GeneralPropertyMaxLogFileSizeEnabled;           /// value("MaxLogFileSizeEnabled")
+    static const bool DefaultGeneralPropertyMaxLogFileSizeEnabled;      /// value(false)
+
 EXTERNAL_API:
 
     /// DRAWING SERVICE PROPERTIES SECTION -------------------------------------------------------------------------------
@@ -335,6 +355,275 @@
     static const STRING TileServicePropertyTiledMapCacheSize;           /// value("TiledMapCacheSize")
     static const INT32 DefaultTileServicePropertyTiledMapCacheSize;     /// value(10)
 
+EXTERNAL_API:
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// The remaining properties are log properties.  For each type of log, there is a "Parameters" property.
+    /// These parameters may be used to customize a log and are listed below.  Note that not
+    /// all of the parameters may be used with a particular log.  See the list of valid
+    /// parameters for each log type below. The Parameters string is a list of
+    /// comma-delimited parameter names.  Each log type has a different set of possible
+    /// parameters.
+    ///
+    /// <table border="1" class="RuledTable">
+    ///    <tr>
+    ///        <th>Parameter</th>
+    ///        <th>Description</th>
+    ///    </tr>
+    ///    <tr>
+    ///        <td>ALL</td>
+    ///        <td>Activates all valid parameters for log.</td>
+    ///    </tr>
+    ///    <tr>
+    ///        <td>AKEY</td>
+    ///        <td>Access Key used by the map layer.</td>
+    ///    </tr>
+    ///    <tr>
+    ///        <td>CLIENT</td>
+    ///        <td>The client and version that generated the request.</td>
+    ///    </tr>
+    ///    <tr>
+    ///        <td>CLIENTID</td>
+    ///        <td>A unique identifier for the client computer that generated the request.</td>
+    ///    </tr>
+    ///    <tr>
+    ///        <td>DATASRC</td>
+    ///        <td>Data source name.</td>
+    ///    </tr>
+    ///    <tr>
+    ///        <td>ITEM</td>
+    ///        <td>The type of request</td>
+    ///    </tr>
+    ///    <tr>
+    ///        <td>LYRTYPE</td>
+    ///        <td>Layer Type.</td>
+    ///    </tr>
+    ///    <tr>
+    ///        <td>MLNAME</td>
+    ///        <td>Map layer name.</td>
+    ///    </tr>
+    ///    <tr>
+    ///        <td>MWIN</td>
+    ///        <td>A composite item that generates entries for MWFURL, XMIN, YMIN, XMAX, and YMAX.</td>
+    ///    </tr>
+    ///    <tr>
+    ///        <td>MWFURL</td>
+    ///        <td>The URL of the map that generated the request.</td>
+    ///    </tr>
+    ///    <tr>
+    ///        <td>NLAYER</td>
+    ///        <td>The number of layers in the request.</td>
+    ///    </tr>
+    ///    <tr>
+    ///        <td>NSCALOG</td>
+    ///        <td>A composite item that generates several entries that conform to the NCSA/CERN log file standard.</td>
+    ///    </tr>
+    ///    <tr>
+    ///        <td>PASSWORD</td>
+    ///        <td>Password used by the map layer.</td>
+    ///    </tr>
+    ///    <tr>
+    ///        <td>PREC</td>
+    ///        <td>A number that indicates map data precision.</td>
+    ///    </tr>
+    ///    <tr>
+    ///        <td>REQID</td>
+    ///        <td>The request identification number.</td>
+    ///    </tr>
+    ///    <tr>
+    ///        <td>REQTIME</td>
+    ///        <td>Time taken to process the request in seconds.</td>
+    ///    </tr>
+    ///    <tr>
+    ///        <td>SCALE</td>
+    ///        <td>The current scale.</td>
+    ///    </tr>
+    ///    <tr>
+    ///        <td>TABLE</td>
+    ///        <td>Feature table name used by the map layer.</td>
+    ///    </tr>
+    ///    <tr>
+    ///        <td>TRACKID</td>
+    ///        <td>Customer tracking ID.</td>
+    ///    </tr>
+    ///    <tr>
+    ///        <td>USER</td>
+    ///        <td>User ID used by this map layer.</td>
+    ///    </tr>
+    ///    <tr>
+    ///        <td>XMAX</td>
+    ///        <td>The maximum X value of the area covered by the request.</td>
+    ///    </tr>
+    ///    <tr>
+    ///        <td>YMAX</td>
+    ///        <td>The maximum Y value of the area covered by the request.</td>
+    ///    </tr>
+    ///    <tr>
+    ///        <td>XMIN</td>
+    ///        <td>The minimum X value of the area covered by the request.</td>
+    ///    </tr>
+    ///    <tr>
+    ///        <td>YMIN</td>
+    ///        <td>The minimum Y value of the area covered by the request.</td>
+    ///    </tr>
+    /// </table>
+    /// \n
+    /// The valid Access log customization parameters are:
+    /// CLIENT, CLIENTID, ITEM, NSCALOG, REQID, PREC, REQTIME, MWIN, MWFURL,
+    /// XMAX, YMAX, XMIN, YMIN, NLAYER, SCALE, TRACKID.
+    /// \n
+    /// The valid Map Layer Access log customization parameters are:
+    /// AKEY, CLIENT, CLIENTID, DATASRC, LYRTYPE, MLNAME, MWIN, MWFURL,
+    /// NSCALOG, PASSWORD, PREC, REQID, REQTIME, SCALE, TABLE, TRACKID,
+    /// USER, XMAX, YMAX, XMIN, YMIN.
+    ///
+    /// TODO:
+    /// - Determine the valid log parameters for the various logs.
+    ///
+
+    /// ACCESS LOG PROPERTIES SECTION ------------------------------------------------------------------------------------
+
+    /// Access Log properties.  This log records all requests to the MapGuide server.
+    /// A record is created for each request after it has been completed.
+    static const STRING AccessLogPropertiesSection;                 /// value("AccessLogProperties")
+
+    /// Enables/disables the Access log
+    static const STRING AccessLogPropertyEnabled;                   /// value("Enabled")
+    static const bool DefaultAccessLogPropertyEnabled;              /// value(true)
+
+    /// The Access log's file name.  NOTE: A log's filename may include the following special
+    /// characters: %d,%m,%y, standing for date, month, year.  If one or all of these are used,
+    /// the special char will be replaced by the actual calendar value when the log file is
+    /// created.  A new log file will be created when the shortest time period has elapsed.
+    /// That is, if the filename includes %d, a new log file will be created everyday.  If the
+    /// filename contains both %m and %y, a new log file is created every month.
+    static const STRING AccessLogPropertyFilename;                  /// value("Filename")
+    static const STRING DefaultAccessLogPropertyFilename;           /// value("Access.log")
+
+    /// The Access log's parameters
+    static const STRING AccessLogPropertyParameters;                /// value("Parameters")
+    static const STRING DefaultAccessLogPropertyParameters;         /// value("")
+
+    /// ADMIN LOG PROPERTIES SECTION -------------------------------------------------------------------------------------
+
+    /// Admin Log properties.  This log records all administrative operations (server status
+    /// changes, configuration changes, etc.).
+    static const STRING AdminLogPropertiesSection;                  /// value("AdminLogProperties")
+
+    /// Enables/disables the Admin log
+    static const STRING AdminLogPropertyEnabled;                    /// value("Enabled")
+    static const bool DefaultAdminLogPropertyEnabled;               /// value(true)
+
+    /// The Admin log's file name.  NOTE: As with the Access Log, the special characters: %d,
+    /// %m, %y may be used in the filename.
+    static const STRING AdminLogPropertyFilename;                   /// value("Filename")
+    static const STRING DefaultAdminLogPropertyFilename;            /// value("Admin.log")
+
+    /// The Admin log's parameters
+    static const STRING AdminLogPropertyParameters;                 /// value("Parameters")
+    static const STRING DefaultAdminLogPropertyParameters;          /// value("")
+
+    /// AUTHENTICATION LOG PROPERTIES SECTION ----------------------------------------------------------------------------
+
+    /// Authentication Log properties.  This log records the success or failure of all
+    /// authentication operations.
+    static const STRING AuthenticationLogPropertiesSection;         /// value("AuthenticationLogProperties")
+
+    /// Enables/disables the Authentication log
+    static const STRING AuthenticationLogPropertyEnabled;           /// value("Enabled")
+    static const bool DefaultAuthenticationLogPropertyEnabled;      /// value(true)
+
+    /// The Authentication log's file name.  NOTE: As with the Access Log, the special
+    /// characters: %d, %m, %y may be used in the filename.
+    static const STRING AuthenticationLogPropertyFilename;          /// value("Filename")
+    static const STRING DefaultAuthenticationLogPropertyFilename;   /// value("Authentication.log")
+
+    /// The Authentication log's parameters
+    static const STRING AuthenticationLogPropertyParameters;        /// value("Parameters")
+    static const STRING DefaultAuthenticationLogPropertyParameters; /// value("")
+
+    /// ERROR LOG PROPERTIES SECTION -------------------------------------------------------------------------------------
+
+    /// Error Log properties.  This log records all errors that occur during the MapGuide
+    /// server's operation.
+    static const STRING ErrorLogPropertiesSection;                  /// value("ErrorLogProperties")
+
+    /// Enables/disables the Error log
+    static const STRING ErrorLogPropertyEnabled;                    /// value("Enabled")
+    static const bool DefaultErrorLogPropertyEnabled;               /// value(true)
+
+    /// The Error log's file name.  NOTE: As with the Access Log, the special characters:
+    /// %d, %m, %y may be used in the file name.
+    static const STRING ErrorLogPropertyFilename;                   /// value("Filename")
+    static const STRING DefaultErrorLogPropertyFilename;            /// value("Error.log")
+
+    /// The Error log's parameters
+    static const STRING ErrorLogPropertyParameters;                 /// value("Parameters")
+    static const STRING DefaultErrorLogPropertyParameters;          /// value("")
+
+    /// PERFORMANCE LOG PROPERTIES SECTION -------------------------------------------------------------------------------------
+
+    /// Performance Log properties.  This log records all server statistical information.
+    static const STRING PerformanceLogPropertiesSection;                  /// value("PerformanceLogProperties")
+
+    /// Enables/disables the Performance log
+    static const STRING PerformanceLogPropertyEnabled;                    /// value("Enabled")
+    static const bool DefaultPerformanceLogPropertyEnabled;               /// value(false)
+
+    /// The Performance log's file name.  NOTE: As with the Access Log, the special characters: %d,
+    /// %m, %y may be used in the filename.
+    static const STRING PerformanceLogPropertyFilename;                   /// value("Filename")
+    static const STRING DefaultPerformanceLogPropertyFilename;            /// value("Performance.log")
+
+    /// The Performance log's parameters
+    static const STRING PerformanceLogPropertyParameters;                 /// value("Parameters")
+    static const STRING DefaultPerformanceLogPropertyParameters;          /// value("")
+
+    /// Sets the time duration (in seconds) between logging performance statistics
+    static const STRING PerformanceLogPropertyInterval;                   /// value("Interval")
+    static const INT32 DefaultPerformanceLogPropertyInterval;             /// value(300)
+
+    /// SESSION LOG PROPERTIES SECTION -----------------------------------------------------------------------------------
+
+    /// Session Log properties.  This log records state information for each connection
+    /// to the MapGuide server, such as connection ID, connection, duration,
+    /// user name, operations received, and operations processed.
+    static const STRING SessionLogPropertiesSection;                /// value("SessionLogProperties")
+
+    /// Enables/disables the Session log
+    static const STRING SessionLogPropertyEnabled;                  /// value("Enabled")
+    static const bool DefaultSessionLogPropertyEnabled;             /// value(true)
+
+    /// The Session log's file name.  NOTE: As with the Access Log, the special
+    /// characters: %d, %m, %y may be used in the filename.
+    static const STRING SessionLogPropertyFilename;                 /// value("Filename")
+    static const STRING DefaultSessionLogPropertyFilename;          /// value("Session.log")
+
+    /// The Session log's parameters
+    static const STRING SessionLogPropertyParameters;               /// value("Parameters")
+    static const STRING DefaultSessionLogPropertyParameters;        /// value("")
+
+    /// TRACE LOG PROPERTIES SECTION -------------------------------------------------------------------------------------
+
+    /// Trace Log properties.  This log records the details for each request (logged
+    /// in the access log).  For example, each request can include data from several
+    /// maps or feature sets, and a detailed record would be created for each one.
+    static const STRING TraceLogPropertiesSection;                  /// value("TraceLogProperties")
+
+    /// Enables/disables the Trace log
+    static const STRING TraceLogPropertyEnabled;                    /// value("Enabled")
+    static const bool DefaultTraceLogPropertyEnabled;               /// value(true)
+
+    /// The Trace log's file name.  NOTE: As with the Access Log, the special
+    /// characters: %d, %m, %y may be used in the filename.
+    static const STRING TraceLogPropertyFilename;                   /// value("Filename")
+    static const STRING DefaultTraceLogPropertyFilename;            /// value("Trace.log")
+
+    /// The Trace log's parameters
+    static const STRING TraceLogPropertyParameters;                 /// value("Parameters")
+    static const STRING DefaultTraceLogPropertyParameters;          /// value("")
+
 public:
 
     // Common Configuration Validation Information Maps
@@ -349,6 +638,14 @@
     static const MgConfigValidationInfo sm_cviSiteServiceProperties[];
     static const MgConfigValidationInfo sm_cviTileServiceProperties[];
 
+    static const MgConfigValidationInfo sm_cviAccessLogProperties[];
+    static const MgConfigValidationInfo sm_cviAdminLogProperties[];
+    static const MgConfigValidationInfo sm_cviAuthenticationLogProperties[];
+    static const MgConfigValidationInfo sm_cviErrorLogProperties[];
+    static const MgConfigValidationInfo sm_cviPerformanceLogProperties[];
+    static const MgConfigValidationInfo sm_cviSessionLogProperties[];
+    static const MgConfigValidationInfo sm_cviTraceLogProperties[];
+
 };
 /// \endcond
 

Modified: branches/2.4/MgDev/Desktop/MgDesktop/System/PlatformInit.cpp
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/System/PlatformInit.cpp	2012-05-18 15:54:57 UTC (rev 6669)
+++ branches/2.4/MgDev/Desktop/MgDesktop/System/PlatformInit.cpp	2012-05-18 19:39:12 UTC (rev 6670)
@@ -1,4 +1,5 @@
 #include "MgDesktop.h"
+#include "Log/LogManager.h"
 #include "Fdo.h"
 #include "Services/Rendering/MappingUtil.h"
 #include "Services/Feature/FdoConnectionPool.h"
@@ -33,6 +34,10 @@
     STRING defaultMessageLocale;
     pConfiguration->GetStringValue(MgConfigProperties::GeneralPropertiesSection, MgConfigProperties::GeneralPropertyDefaultMessageLocale, defaultMessageLocale, MgConfigProperties::DefaultGeneralPropertyDefaultMessageLocale);
 
+    //Init log manager
+    MgLogManager* pLogManager = MgLogManager::GetInstance();
+    pLogManager->Initialize();
+
     //Init resources
     MgResources* pResources = MgResources::GetInstance();
     pResources->Initialize(resourcesPath);

Added: branches/2.4/MgDev/Desktop/MgDesktop/System/ThreadBase.cpp
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/System/ThreadBase.cpp	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/MgDesktop/System/ThreadBase.cpp	2012-05-18 19:39:12 UTC (rev 6670)
@@ -0,0 +1,50 @@
+//
+//  Copyright (C) 2004-2011 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#include "ThreadBase.h"
+
+//////////////////////////////////////////////////////////////////
+/// <summary>
+/// Constructor
+/// </summary>
+MgThreadBase::MgThreadBase (ACE_Thread_Manager &tm, INT32 nThreads) :
+    ACE_Task<ACE_MT_SYNCH> (&tm)
+{
+    if(nThreads <= 0)
+    {
+        nThreads = 5;
+    }
+
+    m_nThreads = nThreads;
+}
+
+//////////////////////////////////////////////////////////////////
+/// <summary>
+/// Initialization. This activates the thread(s).
+/// </summary>
+INT32 MgThreadBase::Activate()
+{
+    INT32 nResult = 0;
+
+    if (activate(THR_DETACHED | THR_NEW_LWP, m_nThreads) == -1)
+    {
+        ACE_ERROR ((LM_ERROR, ACE_TEXT("%p\n"), ACE_TEXT("MgThreadBase::activate")));
+        nResult = -1;
+    }
+
+    return nResult;
+}

Added: branches/2.4/MgDev/Desktop/MgDesktop/System/ThreadBase.h
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/System/ThreadBase.h	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/MgDesktop/System/ThreadBase.h	2012-05-18 19:39:12 UTC (rev 6670)
@@ -0,0 +1,43 @@
+//
+//  Copyright (C) 2004-2011 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#ifndef MGTHREADBASE_H
+#define MGTHREADBASE_H
+
+#include "MgDesktop.h"
+#include "Foundation.h"
+
+class MG_DESKTOP_API MgThreadBase : public ACE_Task<ACE_MT_SYNCH>
+{
+    ///////////////////////////////////////////////////////
+    /// Methods
+public:
+    MgThreadBase (ACE_Thread_Manager &tm, INT32 nThreads);
+
+    // ACE_Task methods
+    virtual int svc() = 0;
+
+    // Class methods
+    INT32 Activate();
+
+    ///////////////////////////////////////////////////////
+    /// Member data
+protected:
+    INT32 m_nThreads;
+};
+
+#endif

Added: branches/2.4/MgDev/Desktop/UnitTest/TestLogManager.cpp
===================================================================
--- branches/2.4/MgDev/Desktop/UnitTest/TestLogManager.cpp	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/UnitTest/TestLogManager.cpp	2012-05-18 19:39:12 UTC (rev 6670)
@@ -0,0 +1,1819 @@
+//
+//  Copyright (C) 2004-2011 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#include "MgDesktop.h"
+#include "TestLogManager.h"
+#include "CppUnitExtensions.h"
+#include "Log/LogManager.h"
+#include "TestLogManagerThread.h"
+#include "FoundationDefs.h"
+CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(TestLogManager, "TestLogManager");
+
+const wchar_t TestName[] = L"TestName.log";
+const wchar_t TestName2[] = L"TestName2.log";
+const wchar_t NewTestName[] = L"SuperCoolNewTestName.log";
+const wchar_t JunkName[] = L"junkfile.log";
+const wchar_t JunkName2[] = L"junkfile2.log";
+
+const wchar_t DynamicTestName[] = L"TestName-%y%m%d.log";
+const wchar_t DynamicTestNameDate1[] = L"TestName-050307.log";
+const wchar_t DynamicTestNameDate2[] = L"TestName-050308.log";
+const wchar_t TestParameters[] =L"TEST PARAMETERS";
+
+const STRING TEST_LOCALE = L"en";
+
+#ifdef _WIN32
+const STRING Entry1 = L"<2005-03-07T16:51:13> Entry 1\r\n";
+const STRING Entry2 = L"<2005-03-07T16:53:15> Entry 2\r\n";
+const STRING Entry3 = L"<2005-03-07T16:54:19> Entry 3\r\n";
+const STRING Entry4 = L"<2005-03-07T16:55:10> Entry 4\r\n";
+const STRING LastEntry = L"<2005-03-08T00:57:08> Entry 5\r\n";
+#else
+const STRING Entry1 = L"<2005-03-07T16:51:13> Entry 1\n";
+const STRING Entry2 = L"<2005-03-07T16:53:15> Entry 2\n";
+const STRING Entry3 = L"<2005-03-07T16:54:19> Entry 3\n";
+const STRING Entry4 = L"<2005-03-07T16:55:10> Entry 4\n";
+const STRING LastEntry = L"<2005-03-08T00:57:08> Entry 5\n";
+#endif
+
+void TestLogManager::setUp()
+{
+}
+
+void TestLogManager::tearDown()
+{
+}
+
+void TestLogManager::TestStart()
+{
+    ACE_DEBUG((LM_INFO, ACE_TEXT("\nRunning Log Manager tests.\n")));
+}
+
+void TestLogManager::TestEnd()
+{
+    ACE_DEBUG((LM_INFO, ACE_TEXT("\nLog Manager tests completed.\n\n")));
+}
+
+bool TestLogManager::CreateFile(STRING filename, STRING contents)
+{
+    FILE* file = NULL;
+    file = ::fopen(MG_WCHAR_TO_CHAR(filename), "wb");
+
+    if (file)
+    {
+        ::fputs(MG_WCHAR_TO_CHAR(contents), file);
+        fclose(file);
+        return true;
+    }
+    else
+    {
+        return false;
+    }
+}
+
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
+/// This test case checks to see if there is a valid MgLogManager and that
+/// there is only 1 MgLogManager.
+///----------------------------------------------------------------------------
+void TestLogManager::TestCase_ValidLogManager()
+{
+    MgLogManager* pMgLogManager = MgLogManager::GetInstance();
+    CPPUNIT_ASSERT(pMgLogManager != NULL);
+
+    MgLogManager* pMgLogManager2 = MgLogManager::GetInstance();
+    CPPUNIT_ASSERT(pMgLogManager == pMgLogManager2);
+}
+
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
+/// This test case checks the logs path.
+///----------------------------------------------------------------------------
+void TestLogManager::TestCase_GetLogsPath()
+{
+    MgLogManager* pMgLogManager = MgLogManager::GetInstance();
+    CREFSTRING path = pMgLogManager->GetLogsPath();
+
+    CPPUNIT_ASSERT(path.length() > 0);
+}
+
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
+/// This test case hits the log manager with multiple threads to ensure that
+/// it encounters no deadlocking.
+///----------------------------------------------------------------------------
+void TestLogManager::TestCase_TestForDeadLock()
+{
+    try
+    {
+        ACE_Thread_Manager manager;
+        TestLogManagerThread test(manager);
+        manager.wait();
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
+}
+
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
+/// This test case enumerates the log files that are currently located in the
+/// logs directory
+///----------------------------------------------------------------------------
+void TestLogManager::TestCase_EnumerateLogs()
+{
+    try
+    {
+        MgLogManager* pMgLogManager = MgLogManager::GetInstance();
+
+        // Create a few files
+        STRING path = pMgLogManager->GetLogsPath();
+        CreateFile(path + TestName, L"");
+        CreateFile(path + JunkName, L"");
+        CreateFile(path + TestName2, L"");
+        CreateFile(path + JunkName2, L"");
+
+        Ptr<MgPropertyCollection> logs = pMgLogManager->EnumerateLogs();
+
+        // Make sure the files show up in the enumeration
+        Ptr<MgStringProperty> testNameProp = new MgStringProperty(L"LogNameProperty", TestName);
+        Ptr<MgStringProperty> junkNameProp = new MgStringProperty(L"LogNameProperty", JunkName);
+        Ptr<MgStringProperty> testName2Prop = new MgStringProperty(L"LogNameProperty", TestName2);
+        Ptr<MgStringProperty> junkName2Prop = new MgStringProperty(L"LogNameProperty", JunkName2);
+
+        CPPUNIT_ASSERT(logs->Contains(junkNameProp));
+        CPPUNIT_ASSERT(logs->Contains(testNameProp));
+        CPPUNIT_ASSERT(logs->Contains(junkName2Prop));
+        CPPUNIT_ASSERT(logs->Contains(testName2Prop));
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
+}
+
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
+/// This test case deletes log files that were created during the running
+/// of the log manager tests
+///----------------------------------------------------------------------------
+void TestLogManager::TestCase_DeleteLog()
+{
+    try
+    {
+        MgLogManager* pMgLogManager = MgLogManager::GetInstance();
+
+        pMgLogManager->DeleteLog(TestName);
+        pMgLogManager->DeleteLog(NewTestName);
+        pMgLogManager->DeleteLog(JunkName);
+        pMgLogManager->DeleteLog(TestName2);
+        pMgLogManager->DeleteLog(JunkName2);
+
+        Ptr<MgPropertyCollection> logs = pMgLogManager->EnumerateLogs();
+
+        CPPUNIT_ASSERT(!logs->Contains(TestName));
+        CPPUNIT_ASSERT(!logs->Contains(NewTestName));
+        CPPUNIT_ASSERT(!logs->Contains(JunkName));
+        CPPUNIT_ASSERT(!logs->Contains(TestName2));
+        CPPUNIT_ASSERT(!logs->Contains(JunkName2));
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
+}
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
+/// This test case creates a file in the logs folder and then uses the api
+/// to rename it.
+///----------------------------------------------------------------------------
+void TestLogManager::TestCase_RenameLog()
+{
+    try
+    {
+        MgLogManager* pMgLogManager = MgLogManager::GetInstance();
+
+        // Create test file
+        STRING path = pMgLogManager->GetLogsPath();
+        CreateFile(path + TestName, L"");
+
+        // Rename the test file
+        pMgLogManager->RenameLog(TestName, NewTestName);
+
+        Ptr<MgPropertyCollection> logs = pMgLogManager->EnumerateLogs();
+
+        Ptr<MgStringProperty> newTestNameProp = new MgStringProperty(L"LogNameProperty", NewTestName);
+        CPPUNIT_ASSERT(logs->Contains(newTestNameProp));
+
+        CPPUNIT_ASSERT_THROW_MG(pMgLogManager->RenameLog(L"", NewTestName), MgNullArgumentException*);
+        CPPUNIT_ASSERT_THROW_MG(pMgLogManager->RenameLog(NewTestName, L""), MgNullArgumentException*);
+        CPPUNIT_ASSERT_THROW_MG(pMgLogManager->RenameLog(TestName, TestName), MgDuplicateFileException*);
+        CPPUNIT_ASSERT_THROW_MG(pMgLogManager->RenameLog(L"DoesNotExist.log", L"NewDoesNotExist.log"), MgFileNotFoundException*);
+#ifdef _WIN32
+        CPPUNIT_ASSERT_THROW_MG(pMgLogManager->RenameLog(NewTestName, L"?"), MgInvalidArgumentException*);
+#endif
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
+}
+
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
+/// This test case tries to change the log info.
+///----------------------------------------------------------------------------
+void TestLogManager::TestCase_SetAccessLogInfo()
+{
+    try
+    {
+        MgLogManager* pMgLogManager = MgLogManager::GetInstance();
+
+        // Save original information
+        bool bOriginalEnabled = pMgLogManager->IsAccessLogEnabled();
+        STRING originalName = pMgLogManager->GetAccessLogFileName();
+        STRING originalParams = pMgLogManager->GetAccessLogParameters();
+
+        pMgLogManager->SetAccessLogInfo(false, TestName, TestParameters);
+
+        bool bEnabled = pMgLogManager->IsAccessLogEnabled();
+        STRING name = pMgLogManager->GetAccessLogFileName();
+        STRING params = pMgLogManager->GetAccessLogParameters();
+
+        // Restore original info
+        pMgLogManager->SetAccessLogInfo(bOriginalEnabled, originalName, originalParams);
+
+        CPPUNIT_ASSERT(bEnabled == false);
+        CPPUNIT_ASSERT(wcscmp(name.c_str(), TestName) == 0);
+        CPPUNIT_ASSERT(wcscmp(params.c_str(), TestParameters) == 0);
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
+}
+
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
+/// This test case tries to clear the log.
+///----------------------------------------------------------------------------
+void TestLogManager::TestCase_ClearAccessLog()
+{
+    try
+    {
+        MgLogManager* pMgLogManager = MgLogManager::GetInstance();
+        bool bResult = pMgLogManager->ClearAccessLog();
+        CPPUNIT_ASSERT(bResult);
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
+}
+
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
+/// This test case tries to get the contents of the log.
+///----------------------------------------------------------------------------
+void TestLogManager::TestCase_GetAccessLog()
+{
+    MgLogManager* pMgLogManager = MgLogManager::GetInstance();
+    STRING path = pMgLogManager->GetLogsPath();
+    STRING originalName = pMgLogManager->GetAccessLogFileName();
+    pMgLogManager->SetAccessLogFileName(TestName);
+
+    STRING contents = Entry1 + Entry2 + Entry3 + Entry4 + LastEntry;
+    CreateFile(path + TestName, contents);
+
+    STRING logContents;
+    STRING lastLogEntry;
+
+    try
+    {
+        Ptr<MgByteReader> byteReader;
+        byteReader = pMgLogManager->GetAccessLog();
+        logContents = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        byteReader = pMgLogManager->GetAccessLog(1);
+        lastLogEntry = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+
+        pMgLogManager->SetAccessLogFileName(originalName);
+    }
+    catch (MgException* e)
+    {
+        pMgLogManager->SetAccessLogFileName(originalName);
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        pMgLogManager->SetAccessLogFileName(originalName);
+        throw;
+    }
+
+    CPPUNIT_ASSERT(logContents == contents);
+    CPPUNIT_ASSERT(lastLogEntry == LastEntry);
+}
+
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
+/// This test case tries to get the contents of the log between two dates.
+///----------------------------------------------------------------------------
+void TestLogManager::TestCase_GetAccessLogByDate()
+{
+    MgLogManager* pMgLogManager = MgLogManager::GetInstance();
+    STRING path = pMgLogManager->GetLogsPath();
+    STRING originalName = pMgLogManager->GetAccessLogFileName();
+    pMgLogManager->SetAccessLogFileName(DynamicTestName);
+
+    STRING contents = Entry1 + Entry2 + Entry3 + Entry4;
+    CreateFile(path + DynamicTestNameDate1, contents);
+    contents = LastEntry;
+    CreateFile(path + DynamicTestNameDate2, contents);
+
+    STRING logContents;
+
+    try
+    {
+        Ptr<MgByteReader> byteReader;
+        Ptr<MgDateTime> fromDate;
+        Ptr<MgDateTime> toDate;
+
+        // from & to dates are at exact time an entry was made
+        fromDate = new MgDateTime(2005, 3, 7, 16, 51, 13, 0);
+        toDate = new MgDateTime(2005, 3, 7, 16, 54, 19, 0);
+        byteReader = pMgLogManager->GetAccessLog(fromDate, toDate);
+        logContents = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        CPPUNIT_ASSERT(logContents == (Entry1 + Entry2 + Entry3));
+
+        // from & to date are the same and at exact time an entry was made
+        fromDate = new MgDateTime(2005, 3, 7, 16, 51, 13, 0);
+        toDate = new MgDateTime(2005, 3, 7, 16, 51, 13, 0);
+        byteReader = pMgLogManager->GetAccessLog(fromDate, toDate);
+        logContents = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        CPPUNIT_ASSERT(logContents == Entry1);
+
+        // from & to date are the same and not at exact time an entry was made
+        fromDate = new MgDateTime(2005, 3, 7, 16, 52, 0, 0);
+        toDate = new MgDateTime(2005, 3, 7, 16, 52, 0, 0);
+        byteReader = pMgLogManager->GetAccessLog(fromDate, toDate);
+        logContents = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        CPPUNIT_ASSERT(logContents.length() == 0);
+
+        // from & to dates are at not at exact times an entry was made
+        fromDate = new MgDateTime(2005, 3, 7, 16, 52, 0, 0);
+        toDate = new MgDateTime(2005, 3, 7, 16, 56, 0, 0);
+        byteReader = pMgLogManager->GetAccessLog(fromDate, toDate);
+        logContents = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        CPPUNIT_ASSERT(logContents == (Entry2 + Entry3 + Entry4));
+
+        // spans two different files
+        fromDate = new MgDateTime(2005, 3, 7, 16, 52, 0, 0);
+        toDate = new MgDateTime(2005, 3, 8, 1, 0, 0, 0);
+        byteReader = pMgLogManager->GetAccessLog(fromDate, toDate);
+        logContents = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        CPPUNIT_ASSERT(logContents == (Entry2 + Entry3 + Entry4 + LastEntry));
+
+        // spans two different files, the first of which doesn't exist
+        fromDate = new MgDateTime(2005, 3, 6, 23, 59, 59, 0);
+        toDate = new MgDateTime(2005, 3, 7, 16, 52, 0, 0);
+        byteReader = pMgLogManager->GetAccessLog(fromDate, toDate);
+        logContents = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        CPPUNIT_ASSERT(logContents == Entry1);
+
+        // spans two different files, the second of which doesn't exist
+        fromDate = new MgDateTime(2005, 3, 8, 0, 0, 0, 0);
+        toDate = new MgDateTime(2005, 3, 9, 0, 0, 0, 0);
+        byteReader = pMgLogManager->GetAccessLog(fromDate, toDate);
+        logContents = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        CPPUNIT_ASSERT(logContents == LastEntry);
+
+        // from date is after the latest entry in the log files
+        fromDate = new MgDateTime(2006, 1, 1, 1, 0, 0, 0);
+        toDate = new MgDateTime(2006, 1, 1, 1, 0, 0, 0);
+        byteReader = pMgLogManager->GetAccessLog(fromDate, toDate);
+        logContents = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        CPPUNIT_ASSERT(logContents.length() == 0);
+
+        // Use a null value for the date
+        CPPUNIT_ASSERT_THROW_MG(pMgLogManager->GetAccessLog(NULL, toDate), MgNullArgumentException*);
+
+        // Use dates more than 24 hours apart
+        fromDate = new MgDateTime(2005, 2, 18, 14, 0, 0, 0);
+        toDate = new MgDateTime(2005, 2, 19, 18, 0, 0, 0);
+        CPPUNIT_ASSERT_THROW_MG(pMgLogManager->GetAccessLog(fromDate, toDate), MgInvalidArgumentException*);
+
+        // Search a log file with an invalid log entry as the first entry
+        CreateFile(path + JunkName, L"asdfasdfasdf");
+        pMgLogManager->SetAccessLogFileName(JunkName);
+        fromDate = new MgDateTime(2005, 3, 8, 0, 0, 0, 0);
+        toDate = new MgDateTime(2005, 3, 9, 0, 0, 0, 0);
+        CPPUNIT_ASSERT_THROW_MG(pMgLogManager->GetAccessLog(fromDate, toDate), MgInvalidLogEntryException*);
+
+        pMgLogManager->SetAccessLogFileName(originalName);
+    }
+    catch (MgException* e)
+    {
+        pMgLogManager->SetAccessLogFileName(originalName);
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        pMgLogManager->SetAccessLogFileName(originalName);
+        throw;
+    }
+}
+
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
+/// This test case tries to get the contents of the log using an invalid
+/// argument.  An exception should be thrown.
+///----------------------------------------------------------------------------
+void TestLogManager::TestCase_GetAccessLogInvalid()
+{
+    MgLogManager* pMgLogManager = MgLogManager::GetInstance();
+    CPPUNIT_ASSERT_THROW_MG(pMgLogManager->GetAccessLog(-1), MgArgumentOutOfRangeException*);
+}
+
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
+/// This test case tries to change the log info.
+///----------------------------------------------------------------------------
+void TestLogManager::TestCase_SetAdminLogInfo()
+{
+    try
+    {
+        MgLogManager* pMgLogManager = MgLogManager::GetInstance();
+
+        // Save original information
+        bool bOriginalEnabled = pMgLogManager->IsAdminLogEnabled();
+        STRING originalName = pMgLogManager->GetAdminLogFileName();
+        STRING originalParams = pMgLogManager->GetAdminLogParameters();
+
+        pMgLogManager->SetAdminLogInfo(false, TestName, TestParameters);
+
+        bool bEnabled = pMgLogManager->IsAdminLogEnabled();
+        STRING name = pMgLogManager->GetAdminLogFileName();
+        STRING params = pMgLogManager->GetAdminLogParameters();
+
+        // Restore original info
+        pMgLogManager->SetAdminLogInfo(bOriginalEnabled, originalName, originalParams);
+
+        CPPUNIT_ASSERT(bEnabled == false);
+        CPPUNIT_ASSERT(wcscmp(name.c_str(), TestName) == 0);
+        CPPUNIT_ASSERT(wcscmp(params.c_str(), TestParameters) == 0);
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
+}
+
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
+/// This test case tries to clear the log.
+///----------------------------------------------------------------------------
+void TestLogManager::TestCase_ClearAdminLog()
+{
+    try
+    {
+        MgLogManager* pMgLogManager = MgLogManager::GetInstance();
+        bool bResult = pMgLogManager->ClearAdminLog();
+        CPPUNIT_ASSERT(bResult);
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
+}
+
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
+/// This test case tries to get the contents of the log.
+///----------------------------------------------------------------------------
+void TestLogManager::TestCase_GetAdminLog()
+{
+    MgLogManager* pMgLogManager = MgLogManager::GetInstance();
+    STRING path = pMgLogManager->GetLogsPath();
+    STRING originalName = pMgLogManager->GetAdminLogFileName();
+    pMgLogManager->SetAdminLogFileName(TestName);
+
+    STRING contents = Entry1 + Entry2 + Entry3 + Entry4 + LastEntry;
+    CreateFile(path + TestName, contents);
+
+    STRING logContents;
+    STRING lastLogEntry;
+
+    try
+    {
+        Ptr<MgByteReader> byteReader = pMgLogManager->GetAdminLog();
+        logContents = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        byteReader = pMgLogManager->GetAdminLog(1);
+        lastLogEntry = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        pMgLogManager->SetAdminLogFileName(originalName);
+    }
+    catch (MgException* e)
+    {
+        pMgLogManager->SetAdminLogFileName(originalName);
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        pMgLogManager->SetAdminLogFileName(originalName);
+        throw;
+    }
+
+    CPPUNIT_ASSERT(logContents == contents);
+    CPPUNIT_ASSERT(lastLogEntry == LastEntry);
+}
+
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
+/// This test case tries to get the contents of the log between two dates.
+///----------------------------------------------------------------------------
+void TestLogManager::TestCase_GetAdminLogByDate()
+{
+    MgLogManager* pMgLogManager = MgLogManager::GetInstance();
+    STRING path = pMgLogManager->GetLogsPath();
+    STRING originalName = pMgLogManager->GetAdminLogFileName();
+    pMgLogManager->SetAdminLogFileName(DynamicTestName);
+
+    STRING contents = Entry1 + Entry2 + Entry3 + Entry4;
+    CreateFile(path + DynamicTestNameDate1, contents);
+    contents = LastEntry;
+    CreateFile(path + DynamicTestNameDate2, contents);
+
+    STRING logContents;
+
+    try
+    {
+        Ptr<MgByteReader> byteReader;
+        Ptr<MgDateTime> fromDate;
+        Ptr<MgDateTime> toDate;
+
+        // from & to dates are at exact time an entry was made
+        fromDate = new MgDateTime(2005, 3, 7, 16, 51, 13, 0);
+        toDate = new MgDateTime(2005, 3, 7, 16, 54, 19, 0);
+        byteReader = pMgLogManager->GetAdminLog(fromDate, toDate);
+        logContents = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        CPPUNIT_ASSERT(logContents == (Entry1 + Entry2 + Entry3));
+
+        // from & to date are the same and at exact time an entry was made
+        fromDate = new MgDateTime(2005, 3, 7, 16, 51, 13, 0);
+        toDate = new MgDateTime(2005, 3, 7, 16, 51, 13, 0);
+        byteReader = pMgLogManager->GetAdminLog(fromDate, toDate);
+        logContents = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        CPPUNIT_ASSERT(logContents == Entry1);
+
+        // from & to date are the same and not at exact time an entry was made
+        fromDate = new MgDateTime(2005, 3, 7, 16, 52, 0, 0);
+        toDate = new MgDateTime(2005, 3, 7, 16, 52, 0, 0);
+        byteReader = pMgLogManager->GetAdminLog(fromDate, toDate);
+        logContents = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        CPPUNIT_ASSERT(logContents.length() == 0);
+
+        // from & to dates are at not at exact times an entry was made
+        fromDate = new MgDateTime(2005, 3, 7, 16, 52, 0, 0);
+        toDate = new MgDateTime(2005, 3, 7, 16, 56, 0, 0);
+        byteReader = pMgLogManager->GetAdminLog(fromDate, toDate);
+        logContents = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        CPPUNIT_ASSERT(logContents == (Entry2 + Entry3 + Entry4));
+
+        // spans two different files, the second of which doesn't exist
+        fromDate = new MgDateTime(2005, 3, 8, 0, 0, 0, 0);
+        toDate = new MgDateTime(2005, 3, 9, 0, 0, 0, 0);
+        byteReader = pMgLogManager->GetAdminLog(fromDate, toDate);
+        logContents = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        CPPUNIT_ASSERT(logContents == LastEntry);
+
+        // from date is after the latest entry in the log files
+        fromDate = new MgDateTime(2006, 1, 1, 1, 0, 0, 0);
+        toDate = new MgDateTime(2006, 1, 1, 1, 0, 0, 0);
+        byteReader = pMgLogManager->GetAdminLog(fromDate, toDate);
+        logContents = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        CPPUNIT_ASSERT(logContents.length() == 0);
+
+        // Use a null value for the date
+        CPPUNIT_ASSERT_THROW_MG(pMgLogManager->GetAdminLog(NULL, toDate), MgNullArgumentException*);
+
+        // Use dates more than 24 hours apart
+        fromDate = new MgDateTime(2005, 2, 18, 14, 0, 0, 0);
+        toDate = new MgDateTime(2005, 2, 19, 18, 0, 0, 0);
+        CPPUNIT_ASSERT_THROW_MG(pMgLogManager->GetAdminLog(fromDate, toDate), MgInvalidArgumentException*);
+
+        pMgLogManager->SetAdminLogFileName(originalName);
+    }
+    catch (MgException* e)
+    {
+        pMgLogManager->SetAdminLogFileName(originalName);
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        pMgLogManager->SetAdminLogFileName(originalName);
+        throw;
+    }
+}
+
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
+/// This test case tries to get the contents of the log using an invalid
+/// argument.  An exception should be thrown.
+///----------------------------------------------------------------------------
+void TestLogManager::TestCase_GetAdminLogInvalid()
+{
+    MgLogManager* pMgLogManager = MgLogManager::GetInstance();
+    CPPUNIT_ASSERT_THROW_MG(pMgLogManager->GetAdminLog(-1), MgArgumentOutOfRangeException*);
+}
+
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
+/// This test case tries to change the log info.
+///----------------------------------------------------------------------------
+void TestLogManager::TestCase_SetAuthenticationLogInfo()
+{
+    try
+    {
+        MgLogManager* pMgLogManager = MgLogManager::GetInstance();
+
+        // Save original information
+        bool bOriginalEnabled = pMgLogManager->IsAuthenticationLogEnabled();
+        STRING originalName = pMgLogManager->GetAuthenticationLogFileName();
+        STRING originalParams = pMgLogManager->GetAuthenticationLogParameters();
+
+        pMgLogManager->SetAuthenticationLogInfo(false, TestName, TestParameters);
+
+        bool bEnabled = pMgLogManager->IsAuthenticationLogEnabled();
+        STRING name = pMgLogManager->GetAuthenticationLogFileName();
+        STRING params = pMgLogManager->GetAuthenticationLogParameters();
+
+        // Restore original info
+        pMgLogManager->SetAuthenticationLogInfo(bOriginalEnabled, originalName, originalParams);
+
+        CPPUNIT_ASSERT(bEnabled == false);
+        CPPUNIT_ASSERT(wcscmp(name.c_str(), TestName) == 0);
+        CPPUNIT_ASSERT(wcscmp(params.c_str(), TestParameters) == 0);
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
+}
+
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
+/// This test case tries to clear the log.
+///----------------------------------------------------------------------------
+void TestLogManager::TestCase_ClearAuthenticationLog()
+{
+    try
+    {
+        MgLogManager* pMgLogManager = MgLogManager::GetInstance();
+        bool bResult = pMgLogManager->ClearAuthenticationLog();
+        CPPUNIT_ASSERT(bResult);
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
+}
+
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
+/// This test case tries to get the contents of the log.
+///----------------------------------------------------------------------------
+void TestLogManager::TestCase_GetAuthenticationLog()
+{
+    MgLogManager* pMgLogManager = MgLogManager::GetInstance();
+    STRING path = pMgLogManager->GetLogsPath();
+    STRING originalName = pMgLogManager->GetAuthenticationLogFileName();
+    pMgLogManager->SetAuthenticationLogFileName(TestName);
+
+    STRING contents = Entry1 + Entry2 + Entry3 + Entry4 + LastEntry;
+    CreateFile(path + TestName, contents);
+
+    STRING logContents;
+    STRING lastLogEntry;
+
+    try
+    {
+        Ptr<MgByteReader> byteReader = pMgLogManager->GetAuthenticationLog();
+        logContents = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        byteReader = pMgLogManager->GetAuthenticationLog(1);
+        lastLogEntry = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        pMgLogManager->SetAuthenticationLogFileName(originalName);
+    }
+    catch (MgException* e)
+    {
+        pMgLogManager->SetAuthenticationLogFileName(originalName);
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        pMgLogManager->SetAuthenticationLogFileName(originalName);
+        throw;
+    }
+
+    CPPUNIT_ASSERT(logContents == contents);
+    CPPUNIT_ASSERT(lastLogEntry == LastEntry);
+}
+
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
+/// This test case tries to get the contents of the log between two dates.
+///----------------------------------------------------------------------------
+void TestLogManager::TestCase_GetAuthenticationLogByDate()
+{
+    MgLogManager* pMgLogManager = MgLogManager::GetInstance();
+    STRING path = pMgLogManager->GetLogsPath();
+    STRING originalName = pMgLogManager->GetAuthenticationLogFileName();
+    pMgLogManager->SetAuthenticationLogFileName(DynamicTestName);
+
+    STRING contents = Entry1 + Entry2 + Entry3 + Entry4;
+    CreateFile(path + DynamicTestNameDate1, contents);
+    contents = LastEntry;
+    CreateFile(path + DynamicTestNameDate2, contents);
+
+    STRING logContents;
+
+    try
+    {
+        Ptr<MgByteReader> byteReader;
+        Ptr<MgDateTime> fromDate;
+        Ptr<MgDateTime> toDate;
+
+        // from & to dates are at exact time an entry was made
+        fromDate = new MgDateTime(2005, 3, 7, 16, 51, 13, 0);
+        toDate = new MgDateTime(2005, 3, 7, 16, 54, 19, 0);
+        byteReader = pMgLogManager->GetAuthenticationLog(fromDate, toDate);
+        logContents = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        CPPUNIT_ASSERT(logContents == (Entry1 + Entry2 + Entry3));
+
+        // from & to dates are at not at exact times an entry was made
+        fromDate = new MgDateTime(2005, 3, 7, 16, 52, 0, 0);
+        toDate = new MgDateTime(2005, 3, 7, 16, 56, 0, 0);
+        byteReader = pMgLogManager->GetAuthenticationLog(fromDate, toDate);
+        logContents = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        CPPUNIT_ASSERT(logContents == (Entry2 + Entry3 + Entry4));
+
+        // spans two different files
+        fromDate = new MgDateTime(2005, 3, 7, 16, 52, 0, 0);
+        toDate = new MgDateTime(2005, 3, 8, 1, 0, 0, 0);
+        byteReader = pMgLogManager->GetAuthenticationLog(fromDate, toDate);
+        logContents = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        CPPUNIT_ASSERT(logContents == (Entry2 + Entry3 + Entry4 + LastEntry));
+
+        // spans two different files, the first of which doesn't exist
+        fromDate = new MgDateTime(2005, 3, 6, 23, 59, 59, 0);
+        toDate = new MgDateTime(2005, 3, 7, 16, 52, 0, 0);
+        byteReader = pMgLogManager->GetAuthenticationLog(fromDate, toDate);
+        logContents = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        CPPUNIT_ASSERT(logContents == Entry1);
+
+        // spans two different files, the second of which doesn't exist
+        fromDate = new MgDateTime(2005, 3, 8, 0, 0, 0, 0);
+        toDate = new MgDateTime(2005, 3, 9, 0, 0, 0, 0);
+        byteReader = pMgLogManager->GetAuthenticationLog(fromDate, toDate);
+        logContents = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        CPPUNIT_ASSERT(logContents == LastEntry);
+
+        // from date is after the latest entry in the log files
+        fromDate = new MgDateTime(2006, 1, 1, 1, 0, 0, 0);
+        toDate = new MgDateTime(2006, 1, 1, 1, 0, 0, 0);
+        byteReader = pMgLogManager->GetAuthenticationLog(fromDate, toDate);
+        logContents = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        CPPUNIT_ASSERT(logContents.length() == 0);
+
+        // Use a null value for the date
+        CPPUNIT_ASSERT_THROW_MG(pMgLogManager->GetAuthenticationLog(NULL, toDate), MgNullArgumentException*);
+
+        // Use dates more than 24 hours apart
+        fromDate = new MgDateTime(2005, 2, 18, 14, 0, 0, 0);
+        toDate = new MgDateTime(2005, 2, 19, 18, 0, 0, 0);
+        CPPUNIT_ASSERT_THROW_MG(pMgLogManager->GetAuthenticationLog(fromDate, toDate), MgInvalidArgumentException*);
+
+        pMgLogManager->SetAuthenticationLogFileName(originalName);
+    }
+    catch (MgException* e)
+    {
+        pMgLogManager->SetAuthenticationLogFileName(originalName);
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        pMgLogManager->SetAuthenticationLogFileName(originalName);
+        throw;
+    }
+}
+
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
+/// This test case tries to get the contents of the log using an invalid
+/// argument.  An exception should be thrown.
+///----------------------------------------------------------------------------
+void TestLogManager::TestCase_GetAuthenticationLogInvalid()
+{
+    MgLogManager* pMgLogManager = MgLogManager::GetInstance();
+    CPPUNIT_ASSERT_THROW_MG(pMgLogManager->GetAuthenticationLog(-1), MgArgumentOutOfRangeException*);
+}
+
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
+/// This test case tries to change the log info.
+///----------------------------------------------------------------------------
+void TestLogManager::TestCase_SetErrorLogInfo()
+{
+    try
+    {
+        MgLogManager* pMgLogManager = MgLogManager::GetInstance();
+
+        // Save original information
+        bool bOriginalEnabled = pMgLogManager->IsErrorLogEnabled();
+        STRING originalName = pMgLogManager->GetErrorLogFileName();
+        STRING originalParams = pMgLogManager->GetErrorLogParameters();
+
+        pMgLogManager->SetErrorLogInfo(false, TestName, TestParameters);
+
+        bool bEnabled = pMgLogManager->IsErrorLogEnabled();
+        STRING name = pMgLogManager->GetErrorLogFileName();
+        STRING params = pMgLogManager->GetErrorLogParameters();
+
+        // Restore original info
+        pMgLogManager->SetErrorLogInfo(bOriginalEnabled, originalName, originalParams);
+
+        CPPUNIT_ASSERT(bEnabled == false);
+        CPPUNIT_ASSERT(wcscmp(name.c_str(), TestName) == 0);
+        CPPUNIT_ASSERT(wcscmp(params.c_str(), TestParameters) == 0);
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
+}
+
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
+/// This test case tries to clear the log.
+///----------------------------------------------------------------------------
+void TestLogManager::TestCase_ClearErrorLog()
+{
+    try
+    {
+        MgLogManager* pMgLogManager = MgLogManager::GetInstance();
+        bool bResult = pMgLogManager->ClearErrorLog();
+        CPPUNIT_ASSERT(bResult);
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
+}
+
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
+/// This test case tries to get the contents of the log.
+///----------------------------------------------------------------------------
+void TestLogManager::TestCase_GetErrorLog()
+{
+    MgLogManager* pMgLogManager = MgLogManager::GetInstance();
+    STRING path = pMgLogManager->GetLogsPath();
+    STRING originalName = pMgLogManager->GetErrorLogFileName();
+    pMgLogManager->SetErrorLogFileName(TestName);
+
+    STRING contents = Entry1 + Entry2 + Entry3 + Entry4 + LastEntry;
+    CreateFile(path + TestName, contents);
+
+    STRING logContents;
+    STRING lastLogEntry;
+
+    try
+    {
+        Ptr<MgByteReader> byteReader = pMgLogManager->GetErrorLog();
+        logContents = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        byteReader = pMgLogManager->GetErrorLog(1);
+        lastLogEntry = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        pMgLogManager->SetErrorLogFileName(originalName);
+    }
+    catch (MgException* e)
+    {
+        pMgLogManager->SetErrorLogFileName(originalName);
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        pMgLogManager->SetErrorLogFileName(originalName);
+        throw;
+    }
+
+    CPPUNIT_ASSERT(logContents == contents);
+    CPPUNIT_ASSERT(lastLogEntry == LastEntry);
+}
+
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
+/// This test case tries to get the contents of the log between two dates.
+///----------------------------------------------------------------------------
+void TestLogManager::TestCase_GetErrorLogByDate()
+{
+    MgLogManager* pMgLogManager = MgLogManager::GetInstance();
+    STRING path = pMgLogManager->GetLogsPath();
+    STRING originalName = pMgLogManager->GetErrorLogFileName();
+    pMgLogManager->SetErrorLogFileName(DynamicTestName);
+
+    STRING contents = Entry1 + Entry2 + Entry3 + Entry4;
+    CreateFile(path + DynamicTestNameDate1, contents);
+    contents = LastEntry;
+    CreateFile(path + DynamicTestNameDate2, contents);
+
+    STRING logContents;
+
+    try
+    {
+        Ptr<MgByteReader> byteReader;
+        Ptr<MgDateTime> fromDate;
+        Ptr<MgDateTime> toDate;
+
+        // from & to dates are at exact time an entry was made
+        fromDate = new MgDateTime(2005, 3, 7, 16, 51, 13, 0);
+        toDate = new MgDateTime(2005, 3, 7, 16, 54, 19, 0);
+        byteReader = pMgLogManager->GetErrorLog(fromDate, toDate);
+        logContents = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        CPPUNIT_ASSERT(logContents == (Entry1 + Entry2 + Entry3));
+
+        // from & to dates are at not at exact times an entry was made
+        fromDate = new MgDateTime(2005, 3, 7, 16, 52, 0, 0);
+        toDate = new MgDateTime(2005, 3, 7, 16, 56, 0, 0);
+        byteReader = pMgLogManager->GetErrorLog(fromDate, toDate);
+        logContents = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        CPPUNIT_ASSERT(logContents == (Entry2 + Entry3 + Entry4));
+
+        // spans two different files
+        fromDate = new MgDateTime(2005, 3, 7, 16, 52, 0, 0);
+        toDate = new MgDateTime(2005, 3, 8, 1, 0, 0, 0);
+        byteReader = pMgLogManager->GetErrorLog(fromDate, toDate);
+        logContents = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        CPPUNIT_ASSERT(logContents == (Entry2 + Entry3 + Entry4 + LastEntry));
+
+        // spans two different files, the first of which doesn't exist
+        fromDate = new MgDateTime(2005, 3, 6, 23, 59, 59, 0);
+        toDate = new MgDateTime(2005, 3, 7, 16, 52, 0, 0);
+        byteReader = pMgLogManager->GetErrorLog(fromDate, toDate);
+        logContents = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        CPPUNIT_ASSERT(logContents == Entry1);
+
+        // spans two different files, the second of which doesn't exist
+        fromDate = new MgDateTime(2005, 3, 8, 0, 0, 0, 0);
+        toDate = new MgDateTime(2005, 3, 9, 0, 0, 0, 0);
+        byteReader = pMgLogManager->GetErrorLog(fromDate, toDate);
+        logContents = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        CPPUNIT_ASSERT(logContents == LastEntry);
+
+        // from date is after the latest entry in the log files
+        fromDate = new MgDateTime(2006, 1, 1, 1, 0, 0, 0);
+        toDate = new MgDateTime(2006, 1, 1, 1, 0, 0, 0);
+        byteReader = pMgLogManager->GetErrorLog(fromDate, toDate);
+        logContents = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        CPPUNIT_ASSERT(logContents.length() == 0);
+
+        // Use a null value for the date
+        CPPUNIT_ASSERT_THROW_MG(pMgLogManager->GetErrorLog(NULL, toDate), MgNullArgumentException*);
+
+        // Use dates more than 24 hours apart
+        fromDate = new MgDateTime(2005, 2, 18, 14, 0, 0, 0);
+        toDate = new MgDateTime(2005, 2, 19, 18, 0, 0, 0);
+        CPPUNIT_ASSERT_THROW_MG(pMgLogManager->GetErrorLog(fromDate, toDate), MgInvalidArgumentException*);
+
+        pMgLogManager->SetErrorLogFileName(originalName);
+    }
+    catch (MgException* e)
+    {
+        pMgLogManager->SetErrorLogFileName(originalName);
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        pMgLogManager->SetErrorLogFileName(originalName);
+        throw;
+    }
+}
+
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
+/// This test case tries to get the contents of the log using an invalid
+/// argument.  An exception should be thrown.
+///----------------------------------------------------------------------------
+void TestLogManager::TestCase_GetErrorLogInvalid()
+{
+    MgLogManager* pMgLogManager = MgLogManager::GetInstance();
+    CPPUNIT_ASSERT_THROW_MG(pMgLogManager->GetErrorLog(-1), MgArgumentOutOfRangeException*);
+}
+
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
+/// This test case tries to change the log info.
+///----------------------------------------------------------------------------
+void TestLogManager::TestCase_SetSessionLogInfo()
+{
+    try
+    {
+        MgLogManager* pMgLogManager = MgLogManager::GetInstance();
+
+        // Save original information
+        bool bOriginalEnabled = pMgLogManager->IsSessionLogEnabled();
+        STRING originalName = pMgLogManager->GetSessionLogFileName();
+        STRING originalParams = pMgLogManager->GetSessionLogParameters();
+
+        pMgLogManager->SetSessionLogInfo(false, TestName, TestParameters);
+
+        bool bEnabled = pMgLogManager->IsSessionLogEnabled();
+        STRING name = pMgLogManager->GetSessionLogFileName();
+        STRING params = pMgLogManager->GetSessionLogParameters();
+
+        // Restore original info
+        pMgLogManager->SetSessionLogInfo(bOriginalEnabled, originalName, originalParams);
+
+        CPPUNIT_ASSERT(bEnabled == false);
+        CPPUNIT_ASSERT(wcscmp(name.c_str(), TestName) == 0);
+        CPPUNIT_ASSERT(wcscmp(params.c_str(), TestParameters) == 0);
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
+}
+
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
+/// This test case tries to clear the log.
+///----------------------------------------------------------------------------
+void TestLogManager::TestCase_ClearSessionLog()
+{
+    try
+    {
+        MgLogManager* pMgLogManager = MgLogManager::GetInstance();
+        bool bResult = pMgLogManager->ClearSessionLog();
+        CPPUNIT_ASSERT(bResult);
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
+}
+
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
+/// This test case tries to get the contents of the log.
+///----------------------------------------------------------------------------
+void TestLogManager::TestCase_GetSessionLog()
+{
+    MgLogManager* pMgLogManager = MgLogManager::GetInstance();
+    STRING path = pMgLogManager->GetLogsPath();
+    STRING originalName = pMgLogManager->GetSessionLogFileName();
+    pMgLogManager->SetSessionLogFileName(TestName);
+
+    STRING contents = Entry1 + Entry2 + Entry3 + Entry4 + LastEntry;
+    CreateFile(path + TestName, contents);
+
+    STRING logContents;
+    STRING lastLogEntry;
+
+    try
+    {
+        Ptr<MgByteReader> byteReader = pMgLogManager->GetSessionLog();
+        logContents = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        byteReader = pMgLogManager->GetSessionLog(1);
+        lastLogEntry = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        pMgLogManager->SetSessionLogFileName(originalName);
+    }
+    catch (MgException* e)
+    {
+        pMgLogManager->SetSessionLogFileName(originalName);
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        pMgLogManager->SetSessionLogFileName(originalName);
+        throw;
+    }
+
+    CPPUNIT_ASSERT(logContents == contents);
+    CPPUNIT_ASSERT(lastLogEntry == LastEntry);
+}
+
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
+/// This test case tries to get the contents of the log between two dates.
+///----------------------------------------------------------------------------
+void TestLogManager::TestCase_GetSessionLogByDate()
+{
+    MgLogManager* pMgLogManager = MgLogManager::GetInstance();
+    STRING path = pMgLogManager->GetLogsPath();
+    STRING originalName = pMgLogManager->GetSessionLogFileName();
+    pMgLogManager->SetSessionLogFileName(DynamicTestName);
+
+    STRING contents = Entry1 + Entry2 + Entry3 + Entry4;
+    CreateFile(path + DynamicTestNameDate1, contents);
+    contents = LastEntry;
+    CreateFile(path + DynamicTestNameDate2, contents);
+
+    STRING logContents;
+
+    try
+    {
+        Ptr<MgByteReader> byteReader;
+        Ptr<MgDateTime> fromDate;
+        Ptr<MgDateTime> toDate;
+
+        // from & to dates are at exact time an entry was made
+        fromDate = new MgDateTime(2005, 3, 7, 16, 51, 13, 0);
+        toDate = new MgDateTime(2005, 3, 7, 16, 54, 19, 0);
+        byteReader = pMgLogManager->GetSessionLog(fromDate, toDate);
+        logContents = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        CPPUNIT_ASSERT(logContents == (Entry1 + Entry2 + Entry3));
+
+        // from & to dates are at not at exact times an entry was made
+        fromDate = new MgDateTime(2005, 3, 7, 16, 52, 0, 0);
+        toDate = new MgDateTime(2005, 3, 7, 16, 56, 0, 0);
+        byteReader = pMgLogManager->GetSessionLog(fromDate, toDate);
+        logContents = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        CPPUNIT_ASSERT(logContents == (Entry2 + Entry3 + Entry4));
+
+        // spans two different files
+        fromDate = new MgDateTime(2005, 3, 7, 16, 52, 0, 0);
+        toDate = new MgDateTime(2005, 3, 8, 1, 0, 0, 0);
+        byteReader = pMgLogManager->GetSessionLog(fromDate, toDate);
+        logContents = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        CPPUNIT_ASSERT(logContents == (Entry2 + Entry3 + Entry4 + LastEntry));
+
+        // spans two different files, the first of which doesn't exist
+        fromDate = new MgDateTime(2005, 3, 6, 23, 59, 59, 0);
+        toDate = new MgDateTime(2005, 3, 7, 16, 52, 0, 0);
+        byteReader = pMgLogManager->GetSessionLog(fromDate, toDate);
+        logContents = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        CPPUNIT_ASSERT(logContents == Entry1);
+
+        // spans two different files, the second of which doesn't exist
+        fromDate = new MgDateTime(2005, 3, 8, 0, 0, 0, 0);
+        toDate = new MgDateTime(2005, 3, 9, 0, 0, 0, 0);
+        byteReader = pMgLogManager->GetSessionLog(fromDate, toDate);
+        logContents = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        CPPUNIT_ASSERT(logContents == LastEntry);
+
+        // from date is after the latest entry in the log files
+        fromDate = new MgDateTime(2006, 1, 1, 1, 0, 0, 0);
+        toDate = new MgDateTime(2006, 1, 1, 1, 0, 0, 0);
+        byteReader = pMgLogManager->GetSessionLog(fromDate, toDate);
+        logContents = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        CPPUNIT_ASSERT(logContents.length() == 0);
+
+        // Use a null value for the date
+        CPPUNIT_ASSERT_THROW_MG(pMgLogManager->GetSessionLog(NULL, toDate), MgNullArgumentException*);
+
+        // Use dates more than 24 hours apart
+        fromDate = new MgDateTime(2005, 2, 18, 14, 0, 0, 0);
+        toDate = new MgDateTime(2005, 2, 19, 18, 0, 0, 0);
+        CPPUNIT_ASSERT_THROW_MG(pMgLogManager->GetSessionLog(fromDate, toDate), MgInvalidArgumentException*);
+
+        pMgLogManager->SetSessionLogFileName(originalName);
+    }
+    catch (MgException* e)
+    {
+        pMgLogManager->SetSessionLogFileName(originalName);
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        pMgLogManager->SetSessionLogFileName(originalName);
+        throw;
+    }
+}
+
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
+/// This test case tries to get the contents of the log using an invalid
+/// argument.  An exception should be thrown.
+///----------------------------------------------------------------------------
+void TestLogManager::TestCase_GetSessionLogInvalid()
+{
+    MgLogManager* pMgLogManager = MgLogManager::GetInstance();
+    CPPUNIT_ASSERT_THROW_MG(pMgLogManager->GetSessionLog(-1), MgArgumentOutOfRangeException*);
+}
+
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
+/// This test case tries to change the log info.
+///----------------------------------------------------------------------------
+void TestLogManager::TestCase_SetTraceLogInfo()
+{
+    try
+    {
+        MgLogManager* pMgLogManager = MgLogManager::GetInstance();
+
+        // Save original information
+        bool bOriginalEnabled = pMgLogManager->IsTraceLogEnabled();
+        STRING originalName = pMgLogManager->GetTraceLogFileName();
+        STRING originalParams = pMgLogManager->GetTraceLogParameters();
+
+        pMgLogManager->SetTraceLogInfo(false, TestName, TestParameters);
+
+        bool bEnabled = pMgLogManager->IsTraceLogEnabled();
+        STRING name = pMgLogManager->GetTraceLogFileName();
+        STRING params = pMgLogManager->GetTraceLogParameters();
+
+        // Restore original info
+        pMgLogManager->SetTraceLogInfo(bOriginalEnabled, originalName, originalParams);
+
+        CPPUNIT_ASSERT(bEnabled == false);
+        CPPUNIT_ASSERT(wcscmp(name.c_str(), TestName) == 0);
+        CPPUNIT_ASSERT(wcscmp(params.c_str(), TestParameters) == 0);
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
+}
+
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
+/// This test case tries to clear the log.
+///----------------------------------------------------------------------------
+void TestLogManager::TestCase_ClearTraceLog()
+{
+    try
+    {
+        MgLogManager* pMgLogManager = MgLogManager::GetInstance();
+        bool bResult = pMgLogManager->ClearTraceLog();
+        CPPUNIT_ASSERT(bResult);
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
+}
+
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
+/// This test case tries to get the contents of the log.
+///----------------------------------------------------------------------------
+void TestLogManager::TestCase_GetTraceLog()
+{
+    MgLogManager* pMgLogManager = MgLogManager::GetInstance();
+    STRING path = pMgLogManager->GetLogsPath();
+    STRING originalName = pMgLogManager->GetTraceLogFileName();
+    pMgLogManager->SetTraceLogFileName(TestName);
+
+    STRING contents = Entry1 + Entry2 + Entry3 + Entry4 + LastEntry;
+    CreateFile(path + TestName, contents);
+
+    STRING logContents;
+    STRING lastLogEntry;
+
+    try
+    {
+        Ptr<MgByteReader> byteReader = pMgLogManager->GetTraceLog();
+        logContents = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        byteReader = pMgLogManager->GetTraceLog(1);
+        lastLogEntry = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        pMgLogManager->SetTraceLogFileName(originalName);
+    }
+    catch (MgException* e)
+    {
+        pMgLogManager->SetTraceLogFileName(originalName);
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        pMgLogManager->SetTraceLogFileName(originalName);
+        throw;
+    }
+
+    CPPUNIT_ASSERT(logContents == contents);
+    CPPUNIT_ASSERT(lastLogEntry == LastEntry);
+}
+
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
+/// This test case tries to get the contents of the log between two dates.
+///----------------------------------------------------------------------------
+void TestLogManager::TestCase_GetTraceLogByDate()
+{
+    MgLogManager* pMgLogManager = MgLogManager::GetInstance();
+    STRING path = pMgLogManager->GetLogsPath();
+    STRING originalName = pMgLogManager->GetTraceLogFileName();
+    pMgLogManager->SetTraceLogFileName(DynamicTestName);
+
+    STRING contents = Entry1 + Entry2 + Entry3 + Entry4;
+    CreateFile(path + DynamicTestNameDate1, contents);
+    contents = LastEntry;
+    CreateFile(path + DynamicTestNameDate2, contents);
+
+    STRING logContents;
+
+    try
+    {
+        Ptr<MgByteReader> byteReader;
+        Ptr<MgDateTime> fromDate;
+        Ptr<MgDateTime> toDate;
+
+        // from & to dates are at exact time an entry was made
+        fromDate = new MgDateTime(2005, 3, 7, 16, 51, 13, 0);
+        toDate = new MgDateTime(2005, 3, 7, 16, 54, 19, 0);
+        byteReader = pMgLogManager->GetTraceLog(fromDate, toDate);
+        logContents = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        CPPUNIT_ASSERT(logContents == (Entry1 + Entry2 + Entry3));
+
+        // from & to dates are at not at exact times an entry was made
+        fromDate = new MgDateTime(2005, 3, 7, 16, 52, 0, 0);
+        toDate = new MgDateTime(2005, 3, 7, 16, 56, 0, 0);
+        byteReader = pMgLogManager->GetTraceLog(fromDate, toDate);
+        logContents = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        CPPUNIT_ASSERT(logContents == (Entry2 + Entry3 + Entry4));
+
+        // spans two different files
+        fromDate = new MgDateTime(2005, 3, 7, 16, 52, 0, 0);
+        toDate = new MgDateTime(2005, 3, 8, 1, 0, 0, 0);
+        byteReader = pMgLogManager->GetTraceLog(fromDate, toDate);
+        logContents = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        CPPUNIT_ASSERT(logContents == (Entry2 + Entry3 + Entry4 + LastEntry));
+
+        // spans two different files, the first of which doesn't exist
+        fromDate = new MgDateTime(2005, 3, 6, 23, 59, 59, 0);
+        toDate = new MgDateTime(2005, 3, 7, 16, 52, 0, 0);
+        byteReader = pMgLogManager->GetTraceLog(fromDate, toDate);
+        logContents = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        CPPUNIT_ASSERT(logContents == Entry1);
+
+        // spans two different files, the second of which doesn't exist
+        fromDate = new MgDateTime(2005, 3, 8, 0, 0, 0, 0);
+        toDate = new MgDateTime(2005, 3, 9, 0, 0, 0, 0);
+        byteReader = pMgLogManager->GetTraceLog(fromDate, toDate);
+        logContents = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        CPPUNIT_ASSERT(logContents == LastEntry);
+
+        // from date is after the latest entry in the log files
+        fromDate = new MgDateTime(2006, 1, 1, 1, 0, 0, 0);
+        toDate = new MgDateTime(2006, 1, 1, 1, 0, 0, 0);
+        byteReader = pMgLogManager->GetTraceLog(fromDate, toDate);
+        logContents = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+        CPPUNIT_ASSERT(logContents.length() == 0);
+
+        // Use a null value for the date
+        CPPUNIT_ASSERT_THROW_MG(pMgLogManager->GetTraceLog(NULL, toDate), MgNullArgumentException*);
+
+        // Use dates more than 24 hours apart
+        fromDate = new MgDateTime(2005, 2, 18, 14, 0, 0, 0);
+        toDate = new MgDateTime(2005, 2, 19, 18, 0, 0, 0);
+        CPPUNIT_ASSERT_THROW_MG(pMgLogManager->GetTraceLog(fromDate, toDate), MgInvalidArgumentException*);
+
+        pMgLogManager->SetTraceLogFileName(originalName);
+    }
+    catch (MgException* e)
+    {
+        pMgLogManager->SetTraceLogFileName(originalName);
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        pMgLogManager->SetTraceLogFileName(originalName);
+        throw;
+    }
+}
+
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
+/// This test case tries to get the contents of the log using an invalid
+/// argument.  An exception should be thrown.
+///----------------------------------------------------------------------------
+void TestLogManager::TestCase_GetTraceLogInvalid()
+{
+    MgLogManager* pMgLogManager = MgLogManager::GetInstance();
+    CPPUNIT_ASSERT_THROW_MG(pMgLogManager->GetTraceLog(-1), MgArgumentOutOfRangeException*);
+}
+
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
+/// This test case writes an entry to the log.  (Assumes that getlog works)
+///----------------------------------------------------------------------------
+void TestLogManager::TestCase_LogAccessEntry()
+{
+    Ptr<MgByteReader> byteReader;
+    STRING logEntry;
+    STRING::size_type pos;
+
+    MgLogManager* pMgLogManager = MgLogManager::GetInstance();
+    bool bOriginalEnabled = pMgLogManager->IsAccessLogEnabled();
+    pMgLogManager->SetAccessLogEnabled(true);
+
+    STRING entry = L"TestAccessEntry";
+    MG_LOG_ACCESS_ENTRY(entry, L"TestClient", L"TestClientIp", L"TestUser");
+
+    // Give the server time to write out the entry as it is on a different thread
+    ACE_OS::sleep(2);
+
+    pMgLogManager->SetAccessLogEnabled(bOriginalEnabled);
+
+    try
+    {
+        byteReader = pMgLogManager->GetAccessLog(1);
+        logEntry = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+
+    }
+    catch (...)
+    {
+        throw;
+    }
+
+    pos = logEntry.find(entry);
+    CPPUNIT_ASSERT(pos != string::npos);
+}
+
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
+/// This test case writes an entry to the log.  (Assumes that getlog works)
+///----------------------------------------------------------------------------
+void TestLogManager::TestCase_LogAdminEntry()
+{
+    Ptr<MgByteReader> byteReader;
+    STRING logEntry;
+    STRING::size_type pos;
+
+    MgLogManager* pMgLogManager = MgLogManager::GetInstance();
+    bool bOriginalEnabled = pMgLogManager->IsAdminLogEnabled();
+    pMgLogManager->SetAdminLogEnabled(true);
+
+    STRING entry = L"TestAdminEntry";
+    MG_LOG_ADMIN_ENTRY(entry, L"TestClient", L"TestClientIp", L"TestUser");
+
+    // Give the server time to write out the entry as it is on a different thread
+    ACE_OS::sleep(2);
+
+    pMgLogManager->SetAdminLogEnabled(bOriginalEnabled);
+
+    try
+    {
+        byteReader = pMgLogManager->GetAdminLog(1);
+        logEntry = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
+
+    pos = logEntry.find(entry);
+    CPPUNIT_ASSERT(pos != string::npos);
+}
+
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
+/// This test case writes an entry to the log.  (Assumes that getlog works)
+///----------------------------------------------------------------------------
+void TestLogManager::TestCase_LogAuthenticationEntry()
+{
+    Ptr<MgByteReader> byteReader;
+    STRING logEntry;
+    STRING::size_type pos;
+
+    MgLogManager* pMgLogManager = MgLogManager::GetInstance();
+    bool bOriginalEnabled = pMgLogManager->IsAuthenticationLogEnabled();
+    pMgLogManager->SetAuthenticationLogEnabled(true);
+
+    STRING entry = L"TestAuthenticationEntry";
+    MG_LOG_AUTHENTICATION_ENTRY(entry);
+
+    // Give the server time to write out the entry as it is on a different thread
+    ACE_OS::sleep(2);
+
+    pMgLogManager->SetAdminLogEnabled(bOriginalEnabled);
+
+    try
+    {
+        byteReader = pMgLogManager->GetAuthenticationLog(1);
+        logEntry = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
+
+    pos = logEntry.find(entry);
+    CPPUNIT_ASSERT(pos != string::npos);
+}
+
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
+/// This test case writes an entry to the log.  (Assumes that getlog works)
+///----------------------------------------------------------------------------
+void TestLogManager::TestCase_LogErrorEntry()
+{
+    Ptr<MgByteReader> byteReader;
+    STRING logEntry;
+    STRING::size_type pos;
+
+    MgLogManager* pMgLogManager = MgLogManager::GetInstance();
+    bool bOriginalEnabled = pMgLogManager->IsErrorLogEnabled();
+    pMgLogManager->SetErrorLogEnabled(true);
+
+    STRING entry = L"TestErrorEntry";
+    MG_LOG_ERROR_ENTRY(entry);
+
+    // Give the server time to write out the entry as it is on a different thread
+    ACE_OS::sleep(2);
+
+    pMgLogManager->SetErrorLogEnabled(bOriginalEnabled);
+
+    try
+    {
+        byteReader = pMgLogManager->GetErrorLog(1);
+        logEntry = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
+
+    pos = logEntry.find(entry);
+    CPPUNIT_ASSERT(pos != string::npos);
+}
+
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
+/// This test case writes an entry to the log.  (Assumes that getlog works)
+///----------------------------------------------------------------------------
+void TestLogManager::TestCase_LogTraceEntry()
+{
+    Ptr<MgByteReader> byteReader;
+    STRING logEntry;
+    STRING::size_type pos;
+
+    MgLogManager* pMgLogManager = MgLogManager::GetInstance();
+    bool bOriginalEnabled = pMgLogManager->IsTraceLogEnabled();
+    pMgLogManager->SetTraceLogEnabled(true);
+
+    STRING entry = L"TestTraceEntry";
+    MG_LOG_TRACE_ENTRY(entry);
+
+    // Give the server time to write out the entry as it is on a different thread
+    ACE_OS::sleep(2);
+
+    pMgLogManager->SetTraceLogEnabled(bOriginalEnabled);
+
+    try
+    {
+        byteReader = pMgLogManager->GetTraceLog(1);
+        logEntry = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
+
+    pos = logEntry.find(entry);
+    CPPUNIT_ASSERT(pos != string::npos);
+}
+
+
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
+/// This test case tries to get the contents of the specified log.
+///----------------------------------------------------------------------------
+void TestLogManager::TestCase_GetLogFile()
+{
+    MgLogManager* pMgLogManager = MgLogManager::GetInstance();
+    STRING path = pMgLogManager->GetLogsPath();
+    STRING originalName = pMgLogManager->GetAccessLogFileName();
+    pMgLogManager->SetAccessLogFileName(TestName);
+
+    STRING contents = Entry1 + Entry2 + Entry3 + Entry4 + LastEntry;
+    CreateFile(path + TestName, contents);
+
+    STRING logContents;
+    STRING lastLogEntry;
+
+    try
+    {
+        Ptr<MgByteReader> byteReader;
+        byteReader = pMgLogManager->GetLogFile(TestName);
+        logContents = MgUtil::MultiByteToWideChar(MgUtil::GetTextFromReader(byteReader));
+
+        pMgLogManager->SetAccessLogFileName(originalName);
+    }
+    catch (MgException* e)
+    {
+        pMgLogManager->SetAccessLogFileName(originalName);
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        pMgLogManager->SetAccessLogFileName(originalName);
+        throw;
+    }
+
+    CPPUNIT_ASSERT(logContents == contents);
+}

Added: branches/2.4/MgDev/Desktop/UnitTest/TestLogManager.h
===================================================================
--- branches/2.4/MgDev/Desktop/UnitTest/TestLogManager.h	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/UnitTest/TestLogManager.h	2012-05-18 19:39:12 UTC (rev 6670)
@@ -0,0 +1,145 @@
+//
+//  Copyright (C) 2004-2011 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#ifndef _TESTLOGMANAGER_H
+#define _TESTLOGMANAGER_H
+
+#include <cppunit/extensions/HelperMacros.h>
+
+class TestLogManager : public CppUnit::TestFixture
+{
+    CPPUNIT_TEST_SUITE(TestLogManager);
+    CPPUNIT_TEST(TestStart); // This must be the very first unit test
+
+    CPPUNIT_TEST(TestCase_ValidLogManager);
+    CPPUNIT_TEST(TestCase_GetLogsPath);
+    CPPUNIT_TEST(TestCase_TestForDeadLock);
+
+    CPPUNIT_TEST(TestCase_EnumerateLogs);
+    CPPUNIT_TEST(TestCase_RenameLog);
+
+    CPPUNIT_TEST(TestCase_SetAccessLogInfo);
+    CPPUNIT_TEST(TestCase_ClearAccessLog);
+    CPPUNIT_TEST(TestCase_GetAccessLog);
+    CPPUNIT_TEST(TestCase_GetAccessLogByDate);
+    CPPUNIT_TEST(TestCase_GetAccessLogInvalid);
+
+    CPPUNIT_TEST(TestCase_SetAdminLogInfo);
+    CPPUNIT_TEST(TestCase_ClearAdminLog);
+    CPPUNIT_TEST(TestCase_GetAdminLog);
+    CPPUNIT_TEST(TestCase_GetAdminLogByDate);
+    CPPUNIT_TEST(TestCase_GetAdminLogInvalid);
+
+    CPPUNIT_TEST(TestCase_SetAuthenticationLogInfo);
+    CPPUNIT_TEST(TestCase_ClearAuthenticationLog);
+    CPPUNIT_TEST(TestCase_GetAuthenticationLog);
+    CPPUNIT_TEST(TestCase_GetAuthenticationLogByDate);
+    CPPUNIT_TEST(TestCase_GetAuthenticationLogInvalid);
+
+    CPPUNIT_TEST(TestCase_SetErrorLogInfo);
+    CPPUNIT_TEST(TestCase_ClearErrorLog);
+    CPPUNIT_TEST(TestCase_GetErrorLog);
+    CPPUNIT_TEST(TestCase_GetErrorLogByDate);
+    CPPUNIT_TEST(TestCase_GetErrorLogInvalid);
+
+    CPPUNIT_TEST(TestCase_SetSessionLogInfo);
+    CPPUNIT_TEST(TestCase_ClearSessionLog);
+    CPPUNIT_TEST(TestCase_GetSessionLog);
+    CPPUNIT_TEST(TestCase_GetSessionLogByDate);
+    CPPUNIT_TEST(TestCase_GetSessionLogInvalid);
+
+    CPPUNIT_TEST(TestCase_SetTraceLogInfo);
+    CPPUNIT_TEST(TestCase_ClearTraceLog);
+    CPPUNIT_TEST(TestCase_GetTraceLog);
+    CPPUNIT_TEST(TestCase_GetTraceLogByDate);
+    CPPUNIT_TEST(TestCase_GetTraceLogInvalid);
+
+    CPPUNIT_TEST(TestCase_LogAccessEntry);
+    CPPUNIT_TEST(TestCase_LogAdminEntry);
+    CPPUNIT_TEST(TestCase_LogAuthenticationEntry);
+    CPPUNIT_TEST(TestCase_LogErrorEntry);
+    CPPUNIT_TEST(TestCase_LogTraceEntry);
+
+    CPPUNIT_TEST(TestCase_GetLogFile);
+
+    CPPUNIT_TEST(TestCase_DeleteLog);
+
+    CPPUNIT_TEST(TestEnd); // This must be the very last unit test
+    CPPUNIT_TEST_SUITE_END();
+
+public:
+    void setUp();
+    void tearDown();
+    void TestStart();
+    void TestEnd();
+    bool CreateFile(STRING filename, STRING contents);
+
+    void TestCase_ValidLogManager();
+    void TestCase_GetLogsPath();
+    void TestCase_TestForDeadLock();
+
+    void TestCase_EnumerateLogs();
+    void TestCase_DeleteLog();
+    void TestCase_RenameLog();
+
+    void TestCase_SetAccessLogInfo();
+    void TestCase_ClearAccessLog();
+    void TestCase_GetAccessLog();
+    void TestCase_GetAccessLogByDate();
+    void TestCase_GetAccessLogInvalid();
+
+    void TestCase_SetAdminLogInfo();
+    void TestCase_ClearAdminLog();
+    void TestCase_GetAdminLog();
+    void TestCase_GetAdminLogByDate();
+    void TestCase_GetAdminLogInvalid();
+
+    void TestCase_SetAuthenticationLogInfo();
+    void TestCase_ClearAuthenticationLog();
+    void TestCase_GetAuthenticationLog();
+    void TestCase_GetAuthenticationLogByDate();
+    void TestCase_GetAuthenticationLogInvalid();
+
+    void TestCase_SetErrorLogInfo();
+    void TestCase_ClearErrorLog();
+    void TestCase_GetErrorLog();
+    void TestCase_GetErrorLogByDate();
+    void TestCase_GetErrorLogInvalid();
+
+    void TestCase_SetSessionLogInfo();
+    void TestCase_ClearSessionLog();
+    void TestCase_GetSessionLog();
+    void TestCase_GetSessionLogByDate();
+    void TestCase_GetSessionLogInvalid();
+
+    void TestCase_SetTraceLogInfo();
+    void TestCase_ClearTraceLog();
+    void TestCase_GetTraceLog();
+    void TestCase_GetTraceLogByDate();
+    void TestCase_GetTraceLogInvalid();
+
+    void TestCase_LogAccessEntry();
+    void TestCase_LogAdminEntry();
+    void TestCase_LogAuthenticationEntry();
+    void TestCase_LogErrorEntry();
+    void TestCase_LogSessionEntry();
+    void TestCase_LogTraceEntry();
+
+    void TestCase_GetLogFile();
+};
+
+#endif // _TESTLOGMANAGER_H

Added: branches/2.4/MgDev/Desktop/UnitTest/TestLogManagerThread.cpp
===================================================================
--- branches/2.4/MgDev/Desktop/UnitTest/TestLogManagerThread.cpp	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/UnitTest/TestLogManagerThread.cpp	2012-05-18 19:39:12 UTC (rev 6670)
@@ -0,0 +1,51 @@
+//
+//  Copyright (C) 2004-2011 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#include "MgDesktop.h"
+#include "TestLogManagerThread.h"
+//#include "ServerManager.h"
+#include "Log/LogType.h"
+#include "Log/LogManager.h"
+
+TestLogManagerThread::TestLogManagerThread(ACE_Thread_Manager &tm) :
+    ACE_Task<ACE_MT_SYNCH>(&tm)
+{
+    activate(THR_DETACHED, 5);
+}
+
+int TestLogManagerThread::svc()
+{
+    MgLogManager* pMan = MgLogManager::GetInstance();
+    if (NULL == pMan)
+    {
+        throw new MgNullReferenceException(L"TestLogManagerThread.svc", __LINE__, __WFILE__, NULL, L"", NULL);
+    }
+
+    INT32 nResult = 0;
+
+    INT32 i;
+        Ptr<MgByteReader> reader;
+    for (i = 0; i < 500; i++)
+    {
+        reader = pMan->GetAdminLog();
+        reader = pMan->GetAdminLog(5);
+        pMan->ClearAdminLog();
+        reader = pMan->GetAdminLog(&fromDate, &toDate);
+    }
+
+    return nResult;
+}

Added: branches/2.4/MgDev/Desktop/UnitTest/TestLogManagerThread.h
===================================================================
--- branches/2.4/MgDev/Desktop/UnitTest/TestLogManagerThread.h	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/UnitTest/TestLogManagerThread.h	2012-05-18 19:39:12 UTC (rev 6670)
@@ -0,0 +1,35 @@
+//
+//  Copyright (C) 2004-2011 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#ifndef MGTESTLOGMANAGERTHREAD_H
+#define MGTESTLOGMANAGERTHREAD_H
+
+class TestLogManagerThread : public ACE_Task<ACE_MT_SYNCH>
+{
+public:
+    // Constructor
+    TestLogManagerThread(ACE_Thread_Manager &tm);
+
+    // ACE_Task methods
+    virtual int svc();
+
+private:
+    MgDateTime fromDate;
+    MgDateTime toDate;
+};
+
+#endif // MGTESTLOGMANAGERTHREAD_H

Modified: branches/2.4/MgDev/Desktop/UnitTest/UnitTest.vcproj
===================================================================
--- branches/2.4/MgDev/Desktop/UnitTest/UnitTest.vcproj	2012-05-18 15:54:57 UTC (rev 6669)
+++ branches/2.4/MgDev/Desktop/UnitTest/UnitTest.vcproj	2012-05-18 19:39:12 UTC (rev 6670)
@@ -370,6 +370,14 @@
 				</FileConfiguration>
 			</File>
 			<File
+				RelativePath=".\TestLogManager.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\TestLogManagerThread.cpp"
+				>
+			</File>
+			<File
 				RelativePath=".\TestMappingService.cpp"
 				>
 				<FileConfiguration
@@ -476,6 +484,14 @@
 				>
 			</File>
 			<File
+				RelativePath=".\TestLogManager.h"
+				>
+			</File>
+			<File
+				RelativePath=".\TestLogManagerThread.h"
+				>
+			</File>
+			<File
 				RelativePath=".\TestMappingService.h"
 				>
 			</File>

Modified: branches/2.4/MgDev/Desktop/UnitTest/main.cpp
===================================================================
--- branches/2.4/MgDev/Desktop/UnitTest/main.cpp	2012-05-18 15:54:57 UTC (rev 6669)
+++ branches/2.4/MgDev/Desktop/UnitTest/main.cpp	2012-05-18 19:39:12 UTC (rev 6670)
@@ -73,6 +73,7 @@
     //in this case.
     runner.addTest(CppUnit::TestFactoryRegistry::getRegistry("TestTileService").makeTest());
     
+    runner.addTest(CppUnit::TestFactoryRegistry::getRegistry("TestLogManager").makeTest());
 
     STRING fileName = L"UnitTestResults.xml";
     if (fileName.size() > 0)



More information about the mapguide-commits mailing list