emailservices/emailstore/message_store/debuglog/src/DebugLog.cpp
changeset 0 8466d47a6819
child 8 e1b6206813b4
child 51 d845db10c0d4
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/emailservices/emailstore/message_store/debuglog/src/DebugLog.cpp	Thu Dec 17 08:39:21 2009 +0200
@@ -0,0 +1,1340 @@
+/*
+* Copyright (c) 2006 Nokia Corporation and/or its subsidiary(-ies). 
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:  Logger implementation.
+*
+*/
+
+
+
+// ========
+// INCLUDES
+// ========
+
+#include <e32std.h>
+#include <f32file.h>
+#include <sysutil.h>
+
+#include "DebugLog.h"
+#include "DebugLogConst.h"
+
+// This takes a lot more memory to use, so it is defaulted to off.  If the code is crashing
+// in DoLogLeakedObjects then uncomment this line to help find the problem.  It is most likely
+// caused by a DLL that was explicitly unloaded, making the original copy of the class name
+// unavailable.
+// <cmail>
+// #define __MAKE_COPY_OF_NAMES 
+// </cmail>
+
+// : IMPLEMENT THIS USING RDebugLog::Open/Close AND class name/object address
+
+// This provides additional help for debugging memory leaks.  Uncomment out the following line
+// in order to log all constructions/destructions from all objects from here, rather than requiring
+// recompilation of all code.
+//#define __LOG_CONSTRUCTION_AND_DESTRUCTION
+
+// =========
+// CONSTANTS
+// =========
+
+const TInt KDateOrTimeMaxLength=30;
+
+_LIT( KDateTimeFormat,"%1%/1%2%/2%3 %H%:1%T%:2%S.%*C3 " );
+
+_LIT( KUnderscore, "_" );
+
+_LIT( KBackslash, "\\" );
+
+_LIT8(KEndOfLineCharacters8,"\r\n");
+
+_LIT8( KTwoColons, "::" );
+
+_LIT8( KColonAndSpace, ": " );
+
+const TText8 KFullStopChar8='.';
+
+const TText8 KTabChar8='\t';
+
+const TInt KFormattedBufferSize = 350;
+
+const TInt KMaxTextPerLine = 150;
+
+const TInt KMaxClassAndFuncNameLength = 35;
+
+// ================
+// INTERNAL CLASSES
+// ================
+
+// ============================================
+// 8-bit formatter overflow handler
+// ============================================
+class TDebugLogBase8Overflow : public TDes8Overflow
+{
+public:
+	virtual void Overflow( TDes8& aDes );
+};
+
+// ============================================
+// 16-bit formatter overflow handler and buffer
+// ============================================
+class TDebugLogBase16Overflow : public TDes16Overflow
+{
+public:
+	virtual void Overflow( TDes16& aDes );
+};
+
+// ============================================================
+// CLogFileHandler
+// This class handles a single log file for the current thread.
+// Note that the filenames are the same for all log files in
+// this thread, but the directory names may be different.
+// ============================================================
+class CLogFileHandler : public CBase
+{
+public:
+
+    RPointerArray<RDebugLog> iObjects;
+    
+//#ifdef __MAKE_COPY_OF_NAMES    
+    RPointerArray<HBufC8> iObjectNames;
+//#endif   
+
+    CLogFileHandler( RFs&         aFs,
+                     TDes&        aFormatBuffer, 
+                     TDes8&       aOutputBuffer,
+                     const TDesC& aDirectoryName,
+                     const TDesC& aFileName );
+
+    virtual ~CLogFileHandler();
+    
+    // returns ETrue if this handler is the log handler for the
+    // given directory
+    TBool IsHandler( const TDesC& aDirectoryName );
+        
+    // returns ETrue if the log file is open and ready for writing        
+	TBool ReadyToWrite();
+	
+	// tries to open the log file and sets internal flags
+	// aCloseFile - set to ETrue if the file should be closed during the call
+	void TryToOpenFile( TBool aCloseFile = EFalse );
+	
+	// closes the log file
+    void CloseFile();
+
+    // flushes the log file
+    void Flush();
+
+    void WriteFormat( const TDesC8&                aClassName,
+                      const TDesC8&                aFuncName,
+                      TRefByValue< const TDesC16 > aFmt,
+                      VA_LIST&                     aList );
+                      
+    void WriteFormat( const TDesC8&               aClassName,
+                      const TDesC8&               aFuncName,
+                      TRefByValue< const TDesC8 > aFmt,
+                      VA_LIST&                    aList );
+      
+	void Write( const TDesC8&  aClassName,
+                const TDesC8&  aFuncName,
+                const TDesC16& aDes );
+	
+	void Write( const TDesC8& aClassName,
+                const TDesC8& aFuncName,
+                const TDesC8& aDes );
+	
+	void HexDump( const TDesC8& aClassName,
+                  const TDesC8& aFuncName,
+                  const TDesC8& aBuffer );
+	
+private:
+
+    RFile iFile;
+
+    void WriteLineL( const TDesC8& aDes );
+
+    void WriteLineL( const TDesC16& aDes );
+    
+    void AddTimestampToOutputBufferL();
+    
+    void AddClassAndFunctionToOutputBufferL( const TDesC8& aClassName,
+                                             const TDesC8& aFuncName );
+    
+    RFs&         iFs;
+    TDes&        iFormatBuffer;
+    TPtr8        iFormatBuffer8;
+    TDes8&       iOutputBuffer;
+    const TDesC& iDirectoryName;
+    const TDesC& iFileName;
+    TBool        iTryToOpenFile;
+    TBool        iFileIsOpen;
+    TBool        iFirstTime;
+    
+}; // END CLogFileHandler
+    
+// ================================================================
+// CDebugLogTlsData
+// This class is the singleton object that manages all instances of
+// the log file handler for the current thread.
+// ================================================================
+class CDebugLogTlsData : private CActive
+{
+public:
+
+    static CLogFileHandler* GetLogFileHandler( const TDesC& aDirectory, RDebugLog* aObject );
+    
+    static void ReleaseLogFileHandler( CLogFileHandler* aHandler, RDebugLog* aObject );
+        
+    static CDebugLogTlsData* Instance();
+    
+    static void FreeIfNecessary();
+        
+    static void LogLeakedObjects();
+        
+private:    
+
+    CDebugLogTlsData();
+    
+    TBool Initialize();
+        
+    virtual ~CDebugLogTlsData();
+
+    CLogFileHandler* DoGetLogFileHandler( const TDesC& aDirectory, RDebugLog* aObject );
+
+    void DoReleaseLogFileHandler( CLogFileHandler* aHandler, RDebugLog* aObject );
+    
+    void DoLogLeakedObjects();
+
+	// inherited from CActive
+	void RunL();
+	void DoCancel();
+
+    RFs                            iFs;
+    TFileName                      iFileName;
+    RPointerArray<CLogFileHandler> iFiles;    
+    TBuf<KFormattedBufferSize>     iFormatBuffer;
+   	TBuf8<KMaxTextPerLine+2>       iOutputBuffer;  // two extra bytes for end of line characters
+    
+}; // END CDebugLogTlsData
+
+// ======================
+// METHOD IMPLEMENTATIONS
+// ======================
+
+// ==========================================================================
+// METHOD:  Constructor
+//
+// DESIGN:  
+// ==========================================================================
+EXPORT_C RDebugLog::RDebugLog()
+    {
+    iLogFileHandler = NULL;
+    } // END RDebugLog
+
+// ==========================================================================
+// METHOD:  CleanupClosePushL
+//
+// DESIGN:  
+// ==========================================================================    
+EXPORT_C void RDebugLog::CleanupClosePushL()
+    {
+    CleanupStack::PushL( TCleanupItem(&RDebugLog::StaticClose, this) );
+    } // END CleanupClosePushL
+
+// ==========================================================================
+// METHOD:  Open
+//
+// DESIGN:  Initialize this object.
+// ==========================================================================
+EXPORT_C void RDebugLog::Open( const TDesC&  aLogDirectory,
+                               const TDesC8& aClassName8,
+                               TAny*         aObjectAddress )
+    {
+    iObjectAddress = aObjectAddress;
+    iClassName8.Set( aClassName8 );
+    iLogDirectory.Set( aLogDirectory );
+    
+#ifdef DEBUG_LOG_CLOSE_BETWEEN_WRITES_AS_DEFAULT    
+    iCloseBetweenWrites = ETrue;
+#else
+    iCloseBetweenWrites = EFalse;
+#endif    
+ 
+    iLogFileHandler = CDebugLogTlsData::GetLogFileHandler( aLogDirectory, this );
+
+#ifdef __LOG_CONSTRUCTION_AND_DESTRUCTION
+    if( iObjectAddress != 0 )
+        {        
+        const TUint bufferSize = 20;
+        TBuf8<bufferSize> buf;
+        _LIT8( KObjAddrFmt, "0x%x" );
+        _LIT8( KDestructor, "CONSTRUCTOR" );
+        buf.Format( KObjAddrFmt, iObjectAddress );
+        Write( KDestructor, buf );    
+        }
+#endif
+
+    if( !iLogFileHandler )
+        {        
+        CDebugLogTlsData::FreeIfNecessary();
+        } // end if
+        
+    } // END Open
+    
+// ==========================================================================
+// METHOD:  Close
+//
+// DESIGN:  
+// ==========================================================================
+EXPORT_C void RDebugLog::Close()
+    {
+#ifdef __LOG_CONSTRUCTION_AND_DESTRUCTION
+    if( iObjectAddress != 0 )
+        {        
+        const TUint bufferSize = 20;
+        TBuf8<bufferSize> buf;
+        _LIT8( KObjAddrFmt, "0x%x" );
+        _LIT8( KDestructor, "DESTRUCTOR" );
+        buf.Format( KObjAddrFmt(), iObjectAddress );
+        Write( KDestructor(), buf );    
+        }
+#endif
+
+    if( iLogFileHandler )
+        {        
+        CDebugLogTlsData::ReleaseLogFileHandler( iLogFileHandler, this );
+        iLogFileHandler = NULL;
+
+        CDebugLogTlsData::FreeIfNecessary();
+
+        } // end if
+        
+    } // END Close
+
+// ==========================================================================
+// METHOD:  Destructor
+//
+// DESIGN:  
+// ==========================================================================
+EXPORT_C RDebugLog::~RDebugLog()
+    {
+    if( iLogFileHandler )
+        {
+        // Error!  This means that Open was called, but not Close.        
+        if( PrepareForWrite() )
+            {        
+            _LIT8( KDummyFuncName, "***" );
+            _LIT8( KErrorText, "DEBUG LOG NOT CLOSED!" );
+        
+        	iLogFileHandler->Write( iClassName8, KDummyFuncName, KErrorText );
+        	WriteComplete();
+            } // end if
+            
+        Close();            
+        }    
+    
+    } // END Destructor
+
+// ==========================================================================
+// METHOD:  SetCloseBetweenWrites
+//
+// DESIGN:  
+// ==========================================================================
+EXPORT_C void RDebugLog::SetCloseBetweenWrites( TBool aValue )
+    {
+   iCloseBetweenWrites = aValue;
+        
+    } // END SetCloseBetweenWrites
+
+// ==========================================================================
+// METHOD:  Write
+//
+// DESIGN:  
+// ==========================================================================
+EXPORT_C void RDebugLog::Write( const TDesC8& aFuncName8, 
+                                const TDesC16& aText ) const
+    {
+	RDebugLog* self = const_cast<RDebugLog*>(this);
+
+    if( self->PrepareForWrite() )
+        {        
+    	// Write the descriptor to the log file
+    	iLogFileHandler->Write( iClassName8, aFuncName8, aText );
+    	self->WriteComplete();
+        } // end if            
+
+    } // END Write
+
+// ==========================================================================
+// METHOD:  Write
+//
+// DESIGN:  
+// ==========================================================================
+EXPORT_C void RDebugLog::Write( const TDesC8& aFuncName8, 
+                                const TDesC8& aText ) const
+    {
+	RDebugLog* self = const_cast<RDebugLog*>(this);
+
+    if( self->PrepareForWrite() )
+        {        
+    	// Write the descriptor to the log file
+    	iLogFileHandler->Write( iClassName8, aFuncName8, aText );
+    	self->WriteComplete();
+        } // end if
+
+    } // END Write
+
+// ==========================================================================
+// METHOD:  WriteFormat
+//
+// DESIGN:  
+// ==========================================================================
+EXPORT_C void RDebugLog::WriteFormat( const TDesC8& aFuncName8, 
+                                      TRefByValue< const TDesC16 > aFmt, 
+                                      ... ) const
+    {
+	VA_LIST list;
+	VA_START(list,aFmt);
+
+	RDebugLog* self = const_cast<RDebugLog*>(this);
+
+    if( self->PrepareForWrite() )
+        {        
+    	// Call WriteFormat method with argument list
+    	iLogFileHandler->WriteFormat( iClassName8, aFuncName8, aFmt, list );
+    	self->WriteComplete();
+        } // end if
+
+    } // END WriteFormat
+
+// ==========================================================================
+// METHOD:  WriteFormat
+//
+// DESIGN:  
+// ==========================================================================
+EXPORT_C void RDebugLog::WriteFormat( const TDesC8&                aFuncName8, 
+                                      TRefByValue< const TDesC16 > aFmt,
+                                      VA_LIST&                     aList ) const
+    {
+	RDebugLog* self = const_cast<RDebugLog*>(this);
+
+    if( self->PrepareForWrite() )
+        {        
+    	// Call WriteFormat method with argument list
+    	iLogFileHandler->WriteFormat( iClassName8, aFuncName8, aFmt, aList );
+    	self->WriteComplete();
+        } // end if
+
+    } // END WriteFormat
+
+// ==========================================================================
+// METHOD:  WriteFormat
+//
+// DESIGN:  
+// ==========================================================================
+EXPORT_C void RDebugLog::WriteFormat( const TDesC8& aFuncName8, 
+                                      TRefByValue< const TDesC8 > aFmt, 
+                                      ... ) const
+    {
+	VA_LIST list;
+	VA_START(list,aFmt);
+
+	RDebugLog* self = const_cast<RDebugLog*>(this);
+
+    if( self->PrepareForWrite() )
+        {        
+    	// Call WriteFormat method with argument list
+    	iLogFileHandler->WriteFormat( iClassName8, aFuncName8, aFmt, list );
+    	self->WriteComplete();
+        } // end if
+
+    } // END WriteFormat
+
+// ==========================================================================
+// METHOD:  WriteFormat
+//
+// DESIGN:  
+// ==========================================================================
+EXPORT_C void RDebugLog::WriteFormat( const TDesC8&               aFuncName8, 
+                                      TRefByValue< const TDesC8 > aFmt,
+                                      VA_LIST&                    aList ) const
+    {
+	RDebugLog* self = const_cast<RDebugLog*>(this);
+
+    if( self->PrepareForWrite() )
+        {        
+    	// Call WriteFormat method with argument list
+    	iLogFileHandler->WriteFormat( iClassName8, aFuncName8, aFmt, aList );
+    	self->WriteComplete();
+        } // end if
+
+    } // END WriteFormat
+
+// ==========================================================================
+// METHOD:  HexDump
+//
+// DESIGN:  
+// ==========================================================================
+EXPORT_C void RDebugLog::HexDump( const TDesC8& aFuncName8,
+                                  const TDesC8& aBuffer ) const
+    {
+	RDebugLog* self = const_cast<RDebugLog*>(this);
+
+    if( self->PrepareForWrite() )
+        {        
+    	// Call WriteFormat method with argument list
+    	iLogFileHandler->HexDump( iClassName8, aFuncName8, aBuffer );
+    	self->WriteComplete();
+        } // end if
+
+    } // END HexDump
+        
+// ==========================================================================
+// METHOD:  PrepareForWrite
+//
+// DESIGN:  
+// ==========================================================================
+TBool RDebugLog::PrepareForWrite()
+    {
+    if( !iLogFileHandler )
+        {
+        iLogFileHandler = CDebugLogTlsData::GetLogFileHandler( iLogDirectory, this );
+        } // end if
+       
+    return (iLogFileHandler != NULL) && iLogFileHandler->ReadyToWrite();
+           
+    } // END PrepareForWrite
+    
+// ==========================================================================
+// METHOD:  WriteComplete
+//
+// DESIGN:  
+// ==========================================================================
+void RDebugLog::WriteComplete()
+    {
+    if( iCloseBetweenWrites )
+        {
+        iLogFileHandler->CloseFile();
+        }
+    else
+        {
+    	iLogFileHandler->Flush();	        
+        } // end if
+       
+    } // END WriteComplete
+    
+// ==========================================================================
+// METHOD:  StaticClose
+//
+// DESIGN:  
+// ==========================================================================
+void RDebugLog::StaticClose( TAny* ptr )
+    {
+    RDebugLog* debugLog = reinterpret_cast<RDebugLog*>(ptr);
+    debugLog->Close();
+    } // end StaticClose
+    
+// ==========================================================================
+// METHOD:  LogLeakedObjects
+//
+// DESIGN:  
+// ==========================================================================
+EXPORT_C void RDebugLog::LogLeakedObjects()
+    {
+    CDebugLogTlsData::LogLeakedObjects();
+    }
+    
+TPtrC8 RDebugLog::ClassName8()
+    {
+    return iClassName8;
+    }
+
+TUint32 RDebugLog::ObjectAddress()
+    {
+    return (TUint32)iObjectAddress;
+    }
+
+// ---------------
+// CLogFileHandler
+// ---------------
+
+// ==========================================================================
+// METHOD:  Constructor
+//
+// DESIGN:  
+// ==========================================================================
+CLogFileHandler::CLogFileHandler( RFs& aFs,
+                                  TDes& aFormatBuffer, 
+                                  TDes8& aOutputBuffer,
+                                  const TDesC& aDirectoryName,
+                                  const TDesC& aFileName ) : 
+    iFs( aFs ),                                  
+    iFormatBuffer( aFormatBuffer ),
+    iFormatBuffer8( const_cast<TUint8*>(reinterpret_cast<const TUint8*>(aFormatBuffer.Ptr())), 0, aFormatBuffer.MaxLength()*2 ),
+    iOutputBuffer( aOutputBuffer ),
+    iDirectoryName( aDirectoryName ),
+    iFileName( aFileName ),
+    iTryToOpenFile( ETrue ),
+    iFileIsOpen( EFalse ),
+    iFirstTime( ETrue )
+    {
+    } // END CLogFileHandler
+
+// ==========================================================================
+// METHOD:  Destructor
+//
+// DESIGN:  
+// ==========================================================================
+CLogFileHandler::~CLogFileHandler() 
+    {
+//#ifdef __MAKE_COPY_OF_NAMES    
+    iObjectNames.ResetAndDestroy();
+//#endif   
+    iObjects.Close();
+    iFile.Close();
+    } // END ~CLogFileHandler
+
+// ==========================================================================
+// METHOD:  IsHandler
+//
+// DESIGN:  
+// ==========================================================================
+TBool CLogFileHandler::IsHandler( const TDesC& aDirectoryName )
+    {
+    return (iDirectoryName.Compare( aDirectoryName ) == 0);
+    } // end IsHandler        
+
+// ==========================================================================
+// METHOD:  ReadyToWrite
+//
+// DESIGN:  
+// ==========================================================================
+TBool CLogFileHandler::ReadyToWrite()
+    { 
+    if( iTryToOpenFile )
+        {
+        TryToOpenFile(); 
+        } // end if    
+           
+    return iFileIsOpen;
+    
+    } // END ReadyToWrite
+
+// ==========================================================================
+// METHOD:  TryToOpenFile
+//
+// DESIGN:  
+// ==========================================================================
+void CLogFileHandler::TryToOpenFile( TBool aCloseFile )
+    {
+    if( !iFileIsOpen )
+        {        
+        // Add the directory name to the start of the file name, to avoid
+        // many files with the same name in different directories.
+    	TFileName logFileName;
+    	logFileName.Copy( KDebugLogsBaseDirectory );
+    	logFileName.Append( iDirectoryName );   	
+        logFileName.Append( KBackslash );
+    	logFileName.Append( iDirectoryName );  
+    	logFileName.Append( KUnderscore );
+        logFileName.Append( iFileName );
+
+    	TInt result = iFile.Open( iFs, logFileName, EFileWrite | EFileShareAny );
+    	
+    	if( result == KErrNotFound )
+    	    {
+        	result = iFile.Create( iFs, logFileName, EFileWrite | EFileShareAny );
+    	    } // end if
+
+        if( iFirstTime )
+            {
+            iFirstTime = EFalse;
+            
+            // Put a marker in the file.            
+            if( result == KErrNone )
+                {
+                // Write the marker line and software version.
+                TBuf<KSysUtilVersionTextLength> text;
+                SysUtil::GetSWVersion(text);
+
+                const TUint bufSize = KSysUtilVersionTextLength+30;
+                TBuf8<bufSize> text8;
+
+                _LIT8( KMarkerLine, "------------------" );
+                
+                text8.Copy( text );
+                text8.Insert( 0, KEndOfLineCharacters8 );
+                text8.Insert( 0, KMarkerLine );
+                text8.Append( KEndOfLineCharacters8 );
+
+                iFile.Write( KMaxTInt, text8 );
+                }
+            }
+
+        if( aCloseFile )
+            {
+            iFile.Close();
+            }
+        else
+            {            
+            // Leave the file open.
+            iFileIsOpen = (result == KErrNone );                    
+            } // end if
+            
+        // Only try next time if this open succeeded.
+        iTryToOpenFile = (result == KErrNone );
+
+        } // end if
+        
+    } // END TryToOpenFile
+
+// ==========================================================================
+// METHOD:  CloseFile
+//
+// DESIGN:  
+// ==========================================================================
+void CLogFileHandler::CloseFile()
+    {
+    iFile.Close();
+    
+    iFileIsOpen = EFalse;
+    
+    } // END CloseFile
+
+// ==========================================================================
+// METHOD:  Flush
+//
+// DESIGN:  
+// ==========================================================================
+void CLogFileHandler::Flush()
+    {
+    iFile.Flush();
+    
+    } // END Flush
+
+// ==========================================================================
+// METHOD:  WriteFormat
+//
+// DESIGN:  
+// ==========================================================================
+void CLogFileHandler::WriteFormat( const TDesC8&                aClassName,
+                                   const TDesC8&                aFuncName,
+                                   TRefByValue< const TDesC16 > aFmt,
+                                   VA_LIST&                     aList )
+    {
+	TDebugLogBase16Overflow overflow16;
+	
+	iFormatBuffer.SetLength( 0 );
+	iFormatBuffer.AppendFormatList( aFmt, aList, &overflow16 );
+
+	Write( aClassName, aFuncName, iFormatBuffer );
+
+    } // END WriteFormat
+
+// ==========================================================================
+// METHOD:  WriteFormat
+//
+// DESIGN:  
+// ==========================================================================
+void CLogFileHandler::WriteFormat( const TDesC8&               aClassName,
+                                   const TDesC8&               aFuncName,
+                                   TRefByValue< const TDesC8 > aFmt,
+                                   VA_LIST&                    aList ) 
+    {
+	TDebugLogBase8Overflow overflow8;
+	
+	iFormatBuffer8.SetLength( 0 );
+	iFormatBuffer8.AppendFormatList( aFmt, aList, &overflow8 );
+
+	Write( aClassName, aFuncName, iFormatBuffer8 );
+
+    } // END WriteFormat
+
+// ==========================================================================
+// METHOD:  Write
+//
+// DESIGN:  Write the given buffer.  Chunk the string if it is longer than
+//          KMaxTextPerLine. 
+// ==========================================================================
+void CLogFileHandler::Write( const TDesC8&  aClassName,
+                             const TDesC8&  aFuncName,
+                             const TDesC16& aDes )
+    {
+    TRAP_IGNORE( AddTimestampToOutputBufferL() );
+        
+    TInt prefixLength = iOutputBuffer.Length();
+        
+    TRAP_IGNORE( AddClassAndFunctionToOutputBufferL( aClassName, aFuncName ) );
+            
+    TInt curPos = 0;
+    
+	while( curPos < aDes.Length() )
+	    {
+        TInt lengthToWrite = Min( KMaxTextPerLine - iOutputBuffer.Length(), aDes.Length() - curPos );
+        
+		TRAP_IGNORE( WriteLineL( aDes.Mid( curPos, lengthToWrite ) ) );
+		    
+		iOutputBuffer.SetLength( prefixLength );
+				    
+		curPos += lengthToWrite;
+
+    	} // end while
+    
+    } // END Write
+
+// ==========================================================================
+// METHOD:  Write
+//
+// DESIGN:  Write the given buffer.  Chunk the string if it is longer than
+//          KDebugLogBufferSize. 
+// ==========================================================================
+void CLogFileHandler::Write( const TDesC8& aClassName,
+                             const TDesC8& aFuncName,
+                             const TDesC8& aDes )
+    {
+    TRAP_IGNORE( AddTimestampToOutputBufferL() );
+        
+    TInt prefixLength = iOutputBuffer.Length();
+        
+    TRAP_IGNORE( AddClassAndFunctionToOutputBufferL( aClassName, aFuncName ) );
+            
+    TInt curPos = 0;
+    
+	while( curPos < aDes.Length() )
+    	{
+        TInt lengthToWrite = Min( KMaxTextPerLine - iOutputBuffer.Length(), aDes.Length() - curPos );        
+
+    	TRAP_IGNORE( WriteLineL( aDes.Mid( curPos, lengthToWrite ) ) );
+		    
+		iOutputBuffer.SetLength( prefixLength );
+				    
+		curPos += lengthToWrite;
+
+    	} // end while
+
+    } // END Write
+
+// ==========================================================================
+// METHOD:  AddTimestampToOutputBufferL
+//
+// DESIGN:  
+// ==========================================================================
+void CLogFileHandler::AddTimestampToOutputBufferL()
+    {
+    // Add timestamp
+    
+	TBuf<KDateOrTimeMaxLength> dateTimeBuffer;
+	TTime t;
+	t.HomeTime();
+	t.FormatL(dateTimeBuffer, KDateTimeFormat);
+	
+	iOutputBuffer.Copy( dateTimeBuffer );		
+    
+    } // END AddTimestampToOutputBufferL
+
+// ==========================================================================
+// METHOD:  AddClassAndFunctionToOutputBufferL
+//
+// DESIGN:  
+// ==========================================================================
+void CLogFileHandler::AddClassAndFunctionToOutputBufferL( const TDesC8& aClassName,
+                                                          const TDesC8& aFuncName )
+    {
+	// Add class name & function name
+	
+    iOutputBuffer.Append( aClassName.Right( KMaxClassAndFuncNameLength ) );
+    iOutputBuffer.Append( KTwoColons );
+    iOutputBuffer.Append( aFuncName.Right( KMaxClassAndFuncNameLength ) );
+    iOutputBuffer.Append( KColonAndSpace );
+    
+    } // END AddClassAndFunctionToOutputBufferL
+
+// ==========================================================================
+// METHOD:  WriteLineL
+//
+// DESIGN:  
+// ==========================================================================
+void CLogFileHandler::WriteLineL( const TDesC16& aSrc )
+	{
+    // Converting from Unicode to Utf8 is overkill for debug logging.  Instead, just use the
+    // check-and-dirty Append function, which converts multi-byte characters to char 1.
+	// CnvUtfConverter::ConvertFromUnicodeToUtf8( iOutputBuffer, aSrc );
+	
+	iOutputBuffer.Append( aSrc );
+	
+	TChar ch;
+	for( TInt i=0; i < iOutputBuffer.Length(); i++ )
+		{
+		ch=iOutputBuffer[i];
+		if(!((ch.IsPrint()) || (ch==KTabChar8)))
+		    {		    
+			iOutputBuffer[i]=KFullStopChar8;
+		    } // end if
+		} // end for
+		
+	iOutputBuffer.Append( KEndOfLineCharacters8 );
+	
+	iFile.Write( KMaxTInt, iOutputBuffer );
+	
+	} // END WriteLineL
+
+// ==========================================================================
+// METHOD:  WriteLineL
+//
+// DESIGN:  Prepend date/time, truncate, and convert unprintable characters to '.'.
+// ==========================================================================
+void CLogFileHandler::WriteLineL( const TDesC8& aSrc )
+	{	
+    TInt i = iOutputBuffer.Length();
+    
+	iOutputBuffer.Append( aSrc );
+	                  
+	TChar ch;
+	while( i < iOutputBuffer.Length() )
+		{
+		ch=iOutputBuffer[i];
+		if(!((ch.IsPrint()) || (ch==KTabChar8)))
+		    {		    
+			iOutputBuffer[i]=KFullStopChar8;
+		    } // end if
+        i++;		    
+		} // end for
+		
+	iOutputBuffer.Append( KEndOfLineCharacters8 );
+	
+	iFile.Write( KMaxTInt, iOutputBuffer );
+	
+	} // END WriteLineL
+
+// ==========================================================================
+// METHOD:  HexDump
+//
+// DESIGN:  
+// ==========================================================================
+void CLogFileHandler::HexDump( const TDesC8& /*aClassName*/,
+                               const TDesC8& /*aFuncName*/,
+                               const TDesC8& aBuffer )
+    {
+	TInt remainingLength = aBuffer.Length();
+	TInt i = 0;
+	
+	while( remainingLength > 0 )
+		{
+        const TInt KHexDumpWidth=32;
+		TInt n = Min( KHexDumpWidth, remainingLength );
+		
+		// Add the starting byte number.
+        _LIT8(KFirstFormatString,"%04x : ");
+		iFormatBuffer8.Format(KFirstFormatString, i);
+		
+		// Add hex values.
+		TInt j;
+		for (j=0; j<n; j++)
+		    {		    
+            _LIT8(KSecondFormatString,"%02x ");
+			iFormatBuffer8.AppendFormat(KSecondFormatString, aBuffer[i+j]);
+		    } // end for
+			
+        // Fill in incomplete lines.			
+		while (j<KHexDumpWidth)
+		    {		    
+            _LIT8(KThreeSpaces,"   ");
+			iFormatBuffer8.Append(KThreeSpaces);
+			j++;
+		    } // end while
+		    
+		// Add text representation.
+        _LIT8(KTwoSpaces," ");
+		iFormatBuffer8.Append(KTwoSpaces);
+		for (j=0; j<n; j++)
+		    {		    
+            _LIT8(KThirdFormatString,"%c");
+			iFormatBuffer8.AppendFormat( KThirdFormatString, aBuffer[i+j] );
+		    } // end for
+		
+		iOutputBuffer.SetLength( 0 );		
+		TRAP_IGNORE( WriteLineL( iFormatBuffer8 ) );
+		
+		remainingLength -= n;
+		i += n;
+		
+		} // end while
+		    
+    } // END HexDump
+	
+// ----------------
+// CDebugLogTlsData
+// ----------------
+
+// ==========================================================================
+// METHOD: Instance 
+//
+// DESIGN:  
+// ==========================================================================
+CDebugLogTlsData* CDebugLogTlsData::Instance()
+    {
+    CDebugLogTlsData* tlsData = NULL;
+    
+	if ( !Dll::Tls() )
+    	{
+		tlsData = new CDebugLogTlsData;
+
+        if( ( tlsData ) && tlsData->Initialize() )
+            {
+    		Dll::SetTls( tlsData );
+            }
+        else
+            {
+            delete tlsData;
+            tlsData = NULL;
+            } // end if
+    	}
+    else
+        {
+        tlsData = reinterpret_cast<CDebugLogTlsData*>(Dll::Tls());
+        } // end if
+
+    return tlsData;
+    } // END Instance
+
+// ==========================================================================
+// METHOD:  Constructor
+//
+// DESIGN:  
+// ==========================================================================
+CDebugLogTlsData::CDebugLogTlsData() : CActive( EPriorityNormal )
+    {
+   	CActiveScheduler::Add(this);        
+    } // END constructor
+    
+// ==========================================================================
+// METHOD:  Destructor
+//
+// DESIGN:  
+// ==========================================================================
+CDebugLogTlsData::~CDebugLogTlsData()
+    {
+    Cancel();    
+    iFs.Close();
+    iFiles.Close();  
+    } // END ~CDebugLogTlsData
+
+// ==========================================================================
+// METHOD:  Initialize
+//
+// DESIGN:  
+// ==========================================================================
+TBool CDebugLogTlsData::Initialize()
+    {
+    TInt returnValue = ( iFs.Connect() == KErrNone );
+    
+    if( returnValue )
+        {
+        // Request notification of directory adds/deletes in the logs directory.
+        iFs.NotifyChange( ENotifyDir, iStatus, KDebugLogsBaseDirectory );        
+        SetActive();
+        
+    	// Dynamically create the name of the log files based on the application name
+    	// and thread ID.  This will eliminate multiple processes/thread usage of
+    	// this debug logging infrastructure from scribbling each others traces.
+	    RProcess thisProcess;
+   	    RThread  thisThread;
+
+	    // The file name is the process name followed by the thread ID.
+    	TParsePtrC fileNameParser( thisProcess.FileName() );
+    	iFileName.Copy( fileNameParser.Name() );
+    	iFileName.Append( KUnderscore );
+    	iFileName.Append( thisThread.Name() );    	    	
+    	iFileName.Append( KDebugLogFileExt );    	       
+        
+        } // end if
+        
+    return returnValue;        
+
+    } // END Initialize
+        
+// ==========================================================================
+// METHOD:  FreeIfNecessary
+//
+// DESIGN:  
+// ==========================================================================
+void CDebugLogTlsData::FreeIfNecessary()
+    {
+    CDebugLogTlsData* tlsData;
+
+    tlsData = reinterpret_cast<CDebugLogTlsData*>(Dll::Tls());
+    
+    if( tlsData->iFiles.Count() == 0 )
+        {
+        delete tlsData;
+        Dll::SetTls( NULL );       
+        }
+           
+    } // END FreeIfNecessary
+
+// ==========================================================================
+// METHOD:  RunL
+//
+// DESIGN:  
+// ==========================================================================
+void CDebugLogTlsData::RunL()
+    {
+    if( iStatus == KErrNone )
+        {
+        // Try to open each file, just in case the modified directory was
+        // for one of the log files.
+        for( TInt i = 0; i < iFiles.Count(); i++ )
+            {
+    	    iFiles[i]->TryToOpenFile( ETrue );
+            } // end for
+	        
+        iFs.NotifyChange( ENotifyDir, iStatus, KDebugLogsBaseDirectory );
+        SetActive();
+        
+        } // end if
+        
+    } // END RunL
+        
+// ==========================================================================
+// METHOD:  DoCancel
+//
+// DESIGN:  
+// ==========================================================================
+void CDebugLogTlsData::DoCancel()
+    {
+    iFs.NotifyChangeCancel();
+    
+    } // END DoCancel
+        
+// ==========================================================================
+// METHOD:  GetLogFileHandler
+//
+// DESIGN:  
+// ==========================================================================
+CLogFileHandler* CDebugLogTlsData::GetLogFileHandler( const TDesC& aDirectory, RDebugLog* aObject )
+    {
+    CLogFileHandler*  returnValue = NULL;
+    
+    CDebugLogTlsData* tlsData = CDebugLogTlsData::Instance();
+
+    if( tlsData )
+        {            
+        returnValue = tlsData->DoGetLogFileHandler( aDirectory, aObject );
+        } // end if
+        
+    return returnValue;
+    } // END GetLogFileHandler
+    
+// ==========================================================================
+// METHOD:  ReleaseLogFileHandler
+//
+// DESIGN:  
+// ==========================================================================
+void CDebugLogTlsData::ReleaseLogFileHandler( CLogFileHandler* aHandler, RDebugLog* aObject )
+    {
+	if ( Dll::Tls() )
+	    {
+        CDebugLogTlsData* tlsData;
+
+        tlsData = reinterpret_cast<CDebugLogTlsData*>(Dll::Tls());
+
+        tlsData->DoReleaseLogFileHandler( aHandler, aObject );        
+	    } // end if
+	    
+    } // END ReleaseLogFileHandler
+        
+// ==========================================================================
+// METHOD:  DoGetLogFileHandler
+//
+// DESIGN:  
+// ==========================================================================
+CLogFileHandler* CDebugLogTlsData::DoGetLogFileHandler( const TDesC& aDirectory, RDebugLog* aObject )
+    {        
+    CLogFileHandler* handler = NULL;
+    
+    // Look for the log file handler for the given directory.
+    TInt  index = 0;
+    while( index < iFiles.Count() && ( !handler ) )
+        {
+        CLogFileHandler* currentHandler = iFiles[index];
+        if( currentHandler->IsHandler( aDirectory ) )
+            {
+            handler = currentHandler;
+            }
+        else
+            {                
+            index++;
+            } // end if
+        } // end while
+        
+    if( !handler )
+        {        
+        handler = new CLogFileHandler( iFs, iFormatBuffer, iOutputBuffer, aDirectory, iFileName );
+
+        if( handler )
+            {            
+            iFiles.Append( handler );
+            } // end if
+        }
+    
+    if( handler )
+        {        
+        // Handler already exists.  Add object to list of objects.
+//#ifdef __MAKE_COPY_OF_NAMES 
+        HBufC8* copyOfName = HBufC8::New( aObject->ClassName8().Length() ); 
+		if ( copyOfName )
+		    {       
+            copyOfName->Des().Copy( aObject->ClassName8() );
+            handler->iObjectNames.Append( copyOfName );
+			}
+//#endif        
+
+        handler->iObjects.Append( aObject );
+	    } // end if
+	    
+	return handler;       
+    
+    } // END DoGetLogFileHandler
+	    
+// ==========================================================================
+// METHOD:  DoReleaseLogFileHandler
+//
+// DESIGN:  
+// ==========================================================================
+void CDebugLogTlsData::DoReleaseLogFileHandler( CLogFileHandler* aHandler, RDebugLog* aObject )
+    {
+    TInt index = aHandler->iObjects.Find( aObject );
+    
+    if( index >= 0 )
+        {
+//#ifdef __MAKE_COPY_OF_NAMES
+        delete aHandler->iObjectNames[index];
+        aHandler->iObjectNames.Remove(index);
+//#endif        
+        aHandler->iObjects.Remove( index );
+        
+        if( aHandler->iObjects.Count() == 0 )
+            {
+            delete aHandler;
+            
+            iFiles.Remove( iFiles.Find(aHandler) );                        
+            } // end if
+        }
+    else
+        {        
+        // Something is wrong.  The most likely case is incorrect usage of the debug log macros.
+        _LIT8( KDummyFuncName, "***" );
+        _LIT8( KErrorText, "INCORRECT DEBUG LOG USAGE!" );
+        
+        aObject->Write( KDummyFuncName, KErrorText );        
+        }
+        
+    } // END DoReleaseLogFileHandler
+
+// ==========================================================================
+// METHOD:  LogLeakedObjects
+//
+// DESIGN:  
+// ==========================================================================
+void CDebugLogTlsData::LogLeakedObjects()
+    {    
+    if( Dll::Tls() )
+        {
+        // If the TLS data wasn't cleaned up then there was a leak, either due
+        // to incorrect usage of the logger or due to the leak of an object that
+        // is using the logger.
+        Instance()->DoLogLeakedObjects();
+        }
+    }
+
+// ==========================================================================
+// METHOD:  DoLogLeakedObjects
+//
+// DESIGN:  
+// ==========================================================================
+void CDebugLogTlsData::DoLogLeakedObjects()
+    {   
+    for( TInt i = 0; i < iFiles.Count(); i++ )
+        {
+        // There are still objects hanging around.  Something leaked, or the log macros
+        // were not properly used. 
+
+        _LIT8( KDebugLogClassName, "DebugLogger" );
+        _LIT8( KDebugLogFunctionNameName, "DoLogLeakedObjects" );
+        _LIT8( KDebugLogErrorText, "LEAKS DETECTED!" );
+        const TUint bufSize = 60;
+        
+        TBuf8<bufSize> tempBuffer;
+        
+        if( iFiles[i]->ReadyToWrite() )
+            {                
+            iFiles[i]->Write( KDebugLogClassName, KDebugLogFunctionNameName, KDebugLogErrorText );        
+
+            for( TInt j = 0; j < iFiles[i]->iObjects.Count(); j++ )
+                {
+                _LIT8( KLeakFmt, "Leak #%i" );
+                tempBuffer.Format( KLeakFmt, j+1 );
+                iFiles[i]->Write( KDebugLogClassName, KDebugLogFunctionNameName, tempBuffer );
+                _LIT8( KAdressFmt, "address=0x%x" );
+                tempBuffer.Format( KAdressFmt(), iFiles[i]->iObjects[j]->ObjectAddress() );
+                iFiles[i]->Write( KDebugLogClassName, KDebugLogFunctionNameName, tempBuffer );
+                
+//#ifdef __MAKE_COPY_OF_NAMES                
+                TPtrC8 className( iFiles[i]->iObjectNames[j]->Des() );             
+//#else
+//                TPtrC8 className( iFiles[i]->iObjects[j]->ClassName8() );             
+//#endif                
+                _LIT8( KClassFmt, "class=%S" );
+                tempBuffer.Format(KClassFmt() , &className );
+                iFiles[i]->Write( KDebugLogClassName, KDebugLogFunctionNameName, tempBuffer );
+                }
+            iFiles[i]->CloseFile();            
+            }
+        }
+    }
+
+// ----------------------
+// TDebugLogBase8Overflow
+// ----------------------
+
+// ==========================================================================
+// METHOD:  Overflow
+//
+// DESIGN:  Handle 8-bit descriptor overflow from the 8-bit formatter.
+// ==========================================================================
+void TDebugLogBase8Overflow::Overflow( TDes8& /* aDes */ )
+    {
+	// NOOP; nothing we can do.  The descriptor parameter is the
+	// string that has already been printed, not the remainder that
+	// hasn't been printed yet.
+
+    } // END Overflow
+
+// -----------------------
+// TDebugLogBase16Overflow
+// -----------------------
+
+// ==========================================================================
+// METHOD:  Overflow
+//
+// DESIGN:  Handle 16-bit descriptor overflow from the 16-bit formatter.
+// ==========================================================================
+void TDebugLogBase16Overflow::Overflow( TDes16& /* aDes */ )
+    {
+	// NOOP; nothing we can do.  The descriptor parameter is the
+	// string that has already been printed, not the remainder that
+	// hasn't been printed yet.
+
+    } // END Overflow
+
+// END FILE DebugLog.cpp
+