Exetools  

Go Back   Exetools > General > General Discussion

Notices

Reply
 
Thread Tools Display Modes
  #1  
Old 01-05-2005, 21:23
WhoCares's Avatar
WhoCares WhoCares is offline
who cares
 
Join Date: Jan 2002
Location: Here
Posts: 378
Rept. Given: 9
Rept. Rcvd 13 Times in 11 Posts
Thanks Given: 19
Thanks Rcvd at 95 Times in 46 Posts
WhoCares Reputation: 13
implement a simple thread-safe debug printf logger under MS VC++

Currently I need to implement a thread-safe application logger under MS Visual C++. The main purpose is to redirect debug_printf and exception strings (thown by C++ classes) to files so I can find out what's wrong with my Win32 service program, and the max log file size can be controlled so that disk space will not be exhausted by too many debug output. __FILE__ , __LINE__ and date/time are
mandatory parameters for the logger class or function.

Unfortunately MS C++ compiler is not C99-compatible so it doesn't support variable-argument macros using __VA_ARGS__ as GCC does. After some search, I found some useful info, but some of those implementations are not thread-safe, for example, the following two printf() can be interrupted in multi-threaded environment, and the log file size can't be controlled.
http://jxta-c.jxta.org/source/browse/jxta-c/include/Attic/jxta_debug.h?logsort=date&search=&hideattic=1&sortby=file&hidecvsroot=1&diff_format=h&r1=1.2
Code:
#define JXTA_LOG(x) \
printf("%s:%d ", __FILE__, __LINE__), printf x
"Calls" to JXTA_LOG would look like:
JXTA_LOG((a1, a2, a3, ...));
http://forum.sources.ru/index.php?showtopic=63242&view=showall
The above Russian post is quite good, especially the CMyPrintf and MYprintfFN implementations. But it seems that they can't be used in c++ "throw" environment. For example, I want to log the following exception string to file with __FILE__ and __LINE__.
Code:
if ((f = fopen(FileName, "rb")) == NULL)
{
       throw MyException("can't open file: %s\n", FileName);
}
Anyone has any experience with suck tricks?

I have implement similar logger, but it is not so elegant and can't be used in throw environment either.
Code:
class Logger
{
	public:
		
		Logger();
		~Logger();

		static void LogPrefix(const TCHAR *File, int Line);
		static void Log(const TCHAR *Format, ...);

	private:

		#ifdef LOG_TO_FILE
			static void OpenFile(const char *mode);
			static const long       MAX_LOG_FILE_SIZE;
		#endif

		static FILE            *m_File;
		static DWORD            m_LogCount;
		static CCriticalSection m_FileLock;
};

#define LOG(x)    (                                        \
					Logger::LogPrefix(__FILE__, __LINE__), \
					(void)(x)                              \
				  )

#ifdef LOG_TO_FILE
	const long Logger::MAX_LOG_FILE_SIZE = 2 * 1024 * 1024;
	FILE *           Logger::m_File            = NULL;
#else
	FILE *           Logger::m_File            = stderr;
#endif

DWORD            Logger::m_LogCount        = 0;
CCriticalSection Logger::m_FileLock;

Logger::Logger()
{
	#ifdef LOG_TO_FILE
		OpenFile("at");
	#else
		m_File = stderr;
	#endif
}

Logger::~Logger()
{
	#ifdef LOG_TO_FILE
		if (m_File)
		{
			fclose(m_File);
			m_File = NULL;
		}
	#endif
}

#ifdef LOG_TO_FILE

	void Logger::OpenFile(const char *mode)
	{
		TCHAR LogFileName[MAX_PATH];
		GetModuleFileNameA(NULL, LogFileName, sizeof(LogFileName)/sizeof(LogFileName[0]));
		strncpy(LogFileName, g_pVar->m_AppPath.c_str(), sizeof(LogFileName) - 1);
		LogFileName[sizeof(LogFileName) - 1] = '\0';
		strncat(LogFileName, "\\logcenter.log", sizeof(LogFileName) - g_pVar->m_AppPath.size() - 2);		

		m_File = fopen(LogFileName, mode);
	}

#endif

void Logger::LogPrefix(const TCHAR *File, int Line)
{
	m_FileLock.Lock();

	#ifdef LOG_TO_FILE	
		if (NULL == m_File) OpenFile("at");
		
		if (m_LogCount  > 100)
		{
			if (ftell(m_File) > MAX_LOG_FILE_SIZE)                  
			{
				fclose(m_File);
				OpenFile("wt");                                
			}
			m_LogCount = 0;
		}
	#endif

	for(signed int k = strlen(File); k >= 0; k--)              
	{
		if (File[k] == '\\')
		{			
			break;
		}
	}
	k++;

	TCHAR Prefix[512];

	SYSTEMTIME LocalTime;
	GetLocalTime(&LocalTime);
	wsprintf(Prefix, _T("%04d-%02d-%02d %02d:%02d:%02d %s %d"), 
		     LocalTime.wYear, LocalTime.wMonth, LocalTime.wDay,
		     LocalTime.wHour, LocalTime.wMinute, LocalTime.wSecond,
			 File + k, Line);

	fprintf(m_File, _T("%s "), Prefix);
}

void Logger::Log(const TCHAR *Format, ...)
{
	TCHAR ErrorMsg[1024];
	va_list ap;
	va_start(ap, Format);
	_vsntprintf(ErrorMsg, sizeof(ErrorMsg)/sizeof(ErrorMsg[0]), Format, ap);

	fprintf(m_File, _T("%s"), ErrorMsg);
	m_LogCount++;

	m_FileLock.Unlock();
}
__________________
AKA Solomon/blowfish.

Last edited by WhoCares; 01-05-2005 at 21:34.
Reply With Quote
  #2  
Old 01-05-2005, 21:55
nuemga2000 nuemga2000 is offline
Friend
 
Join Date: Jan 2002
Posts: 54
Rept. Given: 1
Rept. Rcvd 2 Times in 2 Posts
Thanks Given: 0
Thanks Rcvd at 4 Times in 4 Posts
nuemga2000 Reputation: 2
Hi,
maybe you can take a look at hxxp://www.codeproject.com/debug/dbg.asp ...
... even if this one doesn't fit your needs, you can take some ideas from there

Kerstin
Reply With Quote
  #3  
Old 01-06-2005, 13:26
WhoCares's Avatar
WhoCares WhoCares is offline
who cares
 
Join Date: Jan 2002
Location: Here
Posts: 378
Rept. Given: 9
Rept. Rcvd 13 Times in 11 Posts
Thanks Given: 19
Thanks Rcvd at 95 Times in 46 Posts
WhoCares Reputation: 13
Thanks for the info.
I read the CDebugPrintf source, it doesn't embed __FILE__/__LINE__ into log lines. My conclusion is that only Macros with a variable number of arguments can do the job. That is, only C99-compatible c++ compilers. Actually I have implemented such a logger with GCC(what a splendid compiler!)

I have tested Intel c++ compiler v8.1, it's a pity that its "/Qc99" option only works with pure C programs, neither c++ programs nor c/c++ mixed programs.
http://softwareforums.intel.com/ids/board/message?board.id=16&message.id=1643#M1643

I will try to see whether GCC for Windows can compile my MFC program.
__________________
AKA Solomon/blowfish.

Last edited by WhoCares; 01-06-2005 at 13:29.
Reply With Quote
  #4  
Old 01-06-2005, 15:59
new_profile new_profile is offline
VIP
 
Join Date: Aug 2002
Posts: 142
Rept. Given: 26
Rept. Rcvd 7 Times in 7 Posts
Thanks Given: 39
Thanks Rcvd at 32 Times in 15 Posts
new_profile Reputation: 7
Hi,
May this is helpful (or useless) : xxxx://logging.apache.org/log4cxx/
If you are familiar with Log4j you won't be disappointed.
Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



All times are GMT +8. The time now is 18:39.


Always Your Best Friend: Aaron, JMI, ahmadmansoor, ZeNiX
( 1998 - 2021 )