AnimatLab  2
Test
XYTrace.cpp
1 
2 #include "StdAfx.h"
3 
4 namespace StdUtils
5 {
6 
7 #ifdef WIN32
8 
9 // private helper class
10 class XYTraceHelper
11 {
12  // friend functions of this class
13  friend void SetTraceFilePrefix(LPCTSTR strFilePrefix);
14  friend std::string GetTraceFilePrefix();
15  friend void SetTraceLevel(const int nLevel);
16  friend int GetTraceLevel();
17  friend void Std_Log(const int nLevel, bool bPrintHeader, LPCTSTR strFormat, ...);
18  friend void Std_ResetLog();
19 
20  // internal data members
21  std::string m_strFilename;
22  HANDLE m_hFile;
23  int m_nLevel;
24 #ifdef _WIN64
25  long long m_nThreadId;
26 #else
27  long m_nThreadId;
28 #endif
29 
30  std::string m_strTraceFilePrefix;
31  SYSTEMTIME m_timeStart;
32 
33  // close the current trace file
34  void CloseTraceFile()
35  {
36  if(m_hFile) ::CloseHandle(m_hFile);
37  m_hFile = NULL;
38  }
39  // open a new trace file
40  HANDLE OpenTraceFile()
41  {
42  // construct the new trace file path
43  TCHAR strFilePath[1001];
44  std::string strPrefix;
45  SYSTEMTIME sysTime;
46  ::GetLocalTime(&sysTime);
47 
48  if(m_strTraceFilePrefix.length())
49  strPrefix = m_strTraceFilePrefix;
50  else
51  strPrefix = "Trace";
52 
53  _stprintf
54  (
55  strFilePath,
56  _T("%s_%04d%02d%02d_%02d%02d%02d_%X.txt"),
57  strPrefix.c_str(),
58  sysTime.wYear,
59  sysTime.wMonth,
60  sysTime.wDay,
61  sysTime.wHour,
62  sysTime.wMinute,
63  sysTime.wSecond,
64  ::GetCurrentProcessId()
65  );
66 
67  m_strFilename = strFilePath;
68 
69  // create the new trace file
70  m_hFile = CreateFile
71  (
72  strFilePath,
73  GENERIC_WRITE,
74  FILE_SHARE_READ,
75  NULL,
76  CREATE_ALWAYS,
77  FILE_ATTRIBUTE_NORMAL,
78  NULL
79  );
80  // if successful, save the start time variable
81  if(m_hFile) m_timeStart = sysTime;
82  // return the file handle
83  return m_hFile;
84  }
85  // set lock to gain exclusive access to trace
86  // functions
87  void Lock()
88  {
89 #ifdef _WIN64
90  long long nThreadId;
91 #else
92  long nThreadId;
93 #endif
94 
95  nThreadId = ::GetCurrentThreadId();
96  while(m_nThreadId!=nThreadId)
97  {
98  // keep trying until successfully completed the operation
99  #if _MSC_VER > 1300 // VC 7
100  ::InterlockedCompareExchangePointer((void**)&m_nThreadId, (void*)nThreadId, 0);
101  #else // VC 6
102  ::InterlockedCompareExchange((void**)&m_nThreadId, (void*)nThreadId, 0);
103  #endif
104 
105  if(m_nThreadId==nThreadId) break;
106  ::Sleep(25);
107  }
108  }
109  // release lock so that other threads can access
110  // trace functions
111  void Unlock()
112  {
113  // only the thread that set the lock can release it
114  #if _MSC_VER > 1300 // VC 7
115  ::InterlockedCompareExchangePointer((void**)&m_nThreadId, 0, (void*)::GetCurrentThreadId());
116  #else // VC 6
117  ::InterlockedCompareExchange((void**)&m_nThreadId, 0, (void*)::GetCurrentThreadId());
118  #endif
119  }
120  // set the current trace level
121  void SetTraceLevel(const int nLevel) { m_nLevel = nLevel>0?nLevel:0; }
122  int GetTraceLevel() {return m_nLevel; }
123 
124  // set the trace file name prefix
125  void SetTraceFilePrefix(LPCTSTR strFilePrefix)
126  {
127  // close existing trace file first
128  CloseTraceFile();
129  m_strTraceFilePrefix = strFilePrefix;
130  }
131 public:
132  // constructor and destructor
133  XYTraceHelper()
134  {
135  m_hFile = NULL;
136  m_nLevel = TraceDetail;
137  m_nThreadId = 0;
138  }
139  ~XYTraceHelper()
140  {
141  CloseTraceFile();
142  }
143 };
144 
145 // the one and only instance of XYTraceHelper
146 XYTraceHelper theHelper;
147 
148 void SetTraceFilePrefix(LPCTSTR strFilePrefix)
149 {
150  // set lock
151  theHelper.Lock();
152  // set trace file name prefix
153  theHelper.SetTraceFilePrefix(strFilePrefix);
154  // release lock
155  theHelper.Unlock();
156 }
157 
158 std::string GetTraceFilePrefix()
159 {
160  return theHelper.m_strTraceFilePrefix;
161 }
162 
163 void SetTraceLevel(const int nLevel)
164 {
165  // set lock
166  theHelper.Lock();
167  // set trace level
168  theHelper.SetTraceLevel(nLevel);
169  // release lock
170  theHelper.Unlock();
171 }
172 
173 int GetTraceLevel()
174 {return theHelper.GetTraceLevel();}
175 
176 std::string GetLevel(const int nLevel)
177 {
178  switch ( nLevel )
179  {
180  case TraceNone:
181  return "NONE";
182  case TraceError:
183  return "ERROR";
184  case TraceInfo:
185  return "INFO";
186  case TraceDebug:
187  return "DEBUG";
188  case TraceDetail:
189  return "DETAIL";
190  }
191  return "NONE";
192 }
193 
201 void STD_UTILS_PORT Std_ResetLog()
202 {
203  theHelper.Lock();
204 
205  if(theHelper.m_hFile)
206  {
207  theHelper.CloseTraceFile();
208  if(theHelper.m_strFilename.length())
209  DeleteFile((LPCSTR) theHelper.m_strFilename.c_str());
210  }
211 
212  theHelper.Unlock();
213 }
214 
227 void STD_UTILS_PORT Std_Log(const int nLevel, bool bPrintHeader, LPCTSTR strFormat, ...)
228 {
229  // if the specified trace level is greater than
230  // the current trace level, return immediately
231  if(theHelper.m_nLevel==0||nLevel>theHelper.m_nLevel) return;
232  // set lock
233  theHelper.Lock();
234  try
235  {
236  // get local time
237  SYSTEMTIME sysTime;
238  ::GetLocalTime(&sysTime);
239  // get trace file handle
240  HANDLE hFile = theHelper.m_hFile;
241  // open the trace file if not already open
242  if(hFile==NULL) hFile = theHelper.OpenTraceFile();
243  // if it is already a new day, close the old
244  // trace file and open a new one
245  else if
246  (
247  sysTime.wYear!=theHelper.m_timeStart.wYear||
248  sysTime.wMonth!=theHelper.m_timeStart.wMonth||
249  sysTime.wDay!=theHelper.m_timeStart.wDay)
250  {
251  theHelper.CloseTraceFile();
252  theHelper.OpenTraceFile();
253  }
254 
255  std::string strLevel = GetLevel(nLevel);
256 
257  // write the trace message
258  if(hFile)
259  {
260  // declare buffer (default max buffer size = 32k)
261  const int nMaxSize = 32*1024;
262  TCHAR pBuffer[nMaxSize+51];
263  int nPos=0;
264 
265  if(bPrintHeader)
266  {
267  // print time stamp and thread id to buffer
268  nPos = _stprintf
269  (
270  pBuffer,
271  _T("[%s %02d/%02d/%04d %02d:%02d:%02d_%03d_%X] "),
272  strLevel.c_str(),
273  sysTime.wDay,
274  sysTime.wMonth,
275  sysTime.wYear,
276  sysTime.wHour,
277  sysTime.wMinute,
278  sysTime.wSecond,
279  sysTime.wMilliseconds,
280  theHelper.m_nThreadId
281  );
282  }
283 
284  // print the trace message to buffer
285  va_list args;
286  va_start(args, strFormat);
287  nPos += _vsntprintf(pBuffer+nPos,nMaxSize,strFormat,args);
288  va_end(args);
289  // print the end of the line to buffer
290  _stprintf(pBuffer+nPos,_T("\r\n"));
291  // write the buffer to the trace file
292  DWORD dwBytes;
293  ::WriteFile(hFile,pBuffer,_tcslen(pBuffer),&dwBytes,NULL);
294  }
295  }
296  catch(...)
297  {
298  // add code to handle exception (if needed)
299  }
300  // release lock
301  theHelper.Unlock();
302 }
303 
304 #endif
305 } //StdUtils
Namespace for the standard utility objects.
Definition: MarkupSTL.cpp:19