1
// Copyright 2014 Idol Software, Inc.
3 // This file is part of Doctor Dump SDK.
5 // Doctor Dump SDK is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU Lesser General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU Lesser General Public License for more details.
15 // You should have received a copy of the GNU Lesser General Public License
16 // along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #define WIN32_LEAN_AND_MEAN
25 #include "log_media.h"
27 #ifndef WINAPI_FAMILY_PARTITION
28 #define WINAPI_FAMILY_PARTITION(Partition) 0
31 #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
32 #include <VersionHelpers.h>
35 #define ASSERT(f) assert(f)
39 # define VERIFY(f) ASSERT(f)
41 # define VERIFY(f) ((void)(f))
45 static DWORD g_dwThreadNameTlsId
= TLS_OUT_OF_INDEXES
;
46 static LPTSTR pszUnknownThreadName
= _T("Unknown");
49 static bool bInitialized
= false;
53 g_dwThreadNameTlsId
= TlsAlloc();
54 ASSERT(g_dwThreadNameTlsId
!= TLS_OUT_OF_INDEXES
);
56 LPCTSTR
GetLogThreadName()
58 ASSERT(g_dwThreadNameTlsId
!= TLS_OUT_OF_INDEXES
);
59 if (g_dwThreadNameTlsId
== TLS_OUT_OF_INDEXES
)
61 return static_cast<LPCTSTR
>(TlsGetValue(g_dwThreadNameTlsId
));
63 void FreeLogThreadName()
65 ASSERT(g_dwThreadNameTlsId
!= TLS_OUT_OF_INDEXES
);
66 if (g_dwThreadNameTlsId
== TLS_OUT_OF_INDEXES
)
68 LPTSTR pThreadName
= static_cast<LPTSTR
>(TlsGetValue(g_dwThreadNameTlsId
));
69 if (pThreadName
!= pszUnknownThreadName
)
72 VERIFY(TlsSetValue(g_dwThreadNameTlsId
, pszUnknownThreadName
));
75 void SetLogThreadName(LPCTSTR pszThreadName
)
77 ASSERT(g_dwThreadNameTlsId
!= TLS_OUT_OF_INDEXES
);
78 if (g_dwThreadNameTlsId
== TLS_OUT_OF_INDEXES
)
81 VERIFY(TlsSetValue(g_dwThreadNameTlsId
, LPVOID(pszThreadName
!= NULL
? _tcsdup(pszThreadName
) : pszUnknownThreadName
)));
82 // SetDebuggerThreadName(-1, __LPCSTR(pszThreadName));
85 //! Создаёт путь к файлу.
86 bool CreateFileDir(LPCTSTR pszFilePath
)
91 DWORD dwRes
= GetFullPathName(pszFilePath
, sizeof(szBuffer
)/sizeof(*szBuffer
), szBuffer
, &pszFilePart
);
93 || dwRes
>= sizeof(szBuffer
)/sizeof(*szBuffer
)
94 || pszFilePart
== NULL
)
98 *pszFilePart
= _T('\0');
100 CString
sPath(szBuffer
);
101 sPath
.Replace(_T('/'), _T('\\'));
102 ASSERT(sPath
.Right(1) == _T("\\"));
105 if (sPath
.Left(2) == _T("\\\\"))
106 nPos
= sPath
.Find(_T("\\"), sPath
.Find(_T("\\"), 2) + 1) + 1; // Пропустим имя компьютера и шары
108 nPos
= 4; // Пропустим имя диска
109 while ( (nPos
= sPath
.Find(_T('\\'), nPos
+ 1)) != -1)
111 if (!CreateDirectory(sPath
.Left(nPos
), NULL
) && GetLastError() != ERROR_ALREADY_EXISTS
)
117 void LogBase::SetThreadName(LPCTSTR pszThreadName
)
119 SetLogThreadName(pszThreadName
);
122 LPCTSTR
LogBase::GetThreadName()
124 LPCTSTR pszName
= GetLogThreadName();
125 return pszName
? pszName
: _T("Unknown");
129 LogMediaPtr
LogBase::GetAppLogMedia()
131 static LogMediaPtr
pAppLog(new LogMediaProxy());
135 void LogBase::SetAppLogMedia(LogMediaPtr pLog
)
137 ASSERT(pLog
!= GetAppLogMedia());
138 if (pLog
== GetAppLogMedia())
140 std::static_pointer_cast
<LogMediaProxy
>(GetAppLogMedia())->SetLog(pLog
);
143 LogMediaPtr
LogBase::CreateConsoleMedia()
145 static LogMediaPtr
pConsoleMedia(new ConsoleMedia());
146 if (pConsoleMedia
->IsWorking())
147 return pConsoleMedia
;
148 return LogMediaPtr();
151 LogMediaPtr
LogBase::CreateFileMedia(LPCTSTR pszFilename
, bool bAppend
, bool bFlush
, bool bNewFileDaily
)
153 LogMediaPtr
pLog(new FileMedia(pszFilename
, bAppend
, bFlush
, bNewFileDaily
));
154 if (pLog
->IsWorking())
156 return LogMediaPtr();
159 LogMediaPtr
LogBase::CreateDebugMedia(DWORD dwParam
)
161 LogMediaPtr
pDebugMedia(new DebugMedia(dwParam
));
162 if (pDebugMedia
->IsWorking())
164 return LogMediaPtr();
168 //////////////////////////////////////////////////////////////////////////
170 //////////////////////////////////////////////////////////////////////////
172 void FormatLogMessage(ELogMessageType type
,
173 ELogMessageLevel nLevel
,
177 LPCTSTR pszThreadName
,
184 output
.Preallocate(1024);
186 if (type
!= eLM_DirectOutput
)
191 #if defined(LOG_THREAD_NAME)
193 output
+= pszThreadId
;
195 size_t nThreadNameLen
= _tcslen(pszThreadName
);
196 if (nThreadNameLen
> 12)
197 output
.append(pszThreadName
, 12);
200 output
.append(12 - nThreadNameLen
, _T(' '));
201 output
+= pszThreadName
;
206 output
+= pszThreadId
;
229 output
.AppendFormat(_T("%i"), nLevel
);
233 output
+= _T(" : [");
240 output
+= pszMessage
;
244 output
.reserve(1024);
250 output
+= pszThreadId
;
252 output
+= pszThreadName
;
276 output
.AppendFormat(_T("%i"), nLevel
);
278 output
+= pszMessage
;
283 CString
GetSystemInformation()
285 CString info
= _T("Microsoft Windows ");
287 #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
288 if (IsWindows8Point1OrGreater())
289 info
+= _T(">= 8.1");
290 else if (IsWindows8OrGreater())
292 else if (IsWindows7SP1OrGreater())
294 else if (IsWindows7OrGreater())
296 else if (IsWindowsVistaSP2OrGreater())
297 info
+= _T("Vista SP2");
298 else if (IsWindowsVistaSP1OrGreater())
299 info
+= _T("Vista SP1");
300 else if (IsWindowsVistaOrGreater())
303 if (IsWindowsServer())
304 info
+= _T(" Server");
306 info
+= _T(" Client");
308 OSVERSIONINFOEX rcOS
;
309 ZeroMemory(&rcOS
, sizeof(rcOS
));
310 rcOS
.dwOSVersionInfoSize
= sizeof(rcOS
);
312 GetVersionEx((OSVERSIONINFO
*)&rcOS
);
314 if (rcOS
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
)
316 switch (rcOS
.dwMinorVersion
)
318 case 0: info
+= _T("95"); break;
319 case 10: info
+= _T("98"); break;
320 case 90: info
+= _T("Me"); break;
322 if (!_tcscmp(rcOS
.szCSDVersion
, _T(" A")))
323 info
+= _T(" Second Edition");
325 if (!_tcscmp(rcOS
.szCSDVersion
, _T(" C")))
328 else if (rcOS
.dwPlatformId
== VER_PLATFORM_WIN32_NT
)
330 switch (rcOS
.dwMajorVersion
)
332 case 3: info
+= _T("NT 3.51"); break;
333 case 4: info
+= _T("NT 4.0"); break;
335 switch (rcOS
.dwMinorVersion
)
337 case 0: info
+= _T("2000"); break;
338 case 1: info
+= _T("XP"); break;
339 case 2: info
+= _T("2003 Server"); break;
340 default: ASSERT(false); info
+= _T("future version"); break;
344 switch (rcOS
.dwMinorVersion
)
346 case 0: info
+= rcOS
.wProductType
== VER_NT_WORKSTATION
? _T("Vista") : _T("Server 2008"); break;
347 case 1: info
+= rcOS
.wProductType
== VER_NT_WORKSTATION
? _T("7") : _T("Server 2008 R2"); break;
348 case 2: info
+= rcOS
.wProductType
== VER_NT_WORKSTATION
? _T("8") : _T("Server 2012"); break;
349 case 3: info
+= rcOS
.wProductType
== VER_NT_WORKSTATION
? _T("8.1") : _T("Server 2012 R2"); break;
353 future
.Format(_T("%ld.%ld%s"), rcOS
.dwMajorVersion
, rcOS
.dwMinorVersion
, VER_NT_WORKSTATION
? _T("") : _T(" Server"));
362 future
.Format(_T("%ld.%ld%s"), rcOS
.dwMajorVersion
, rcOS
.dwMinorVersion
, VER_NT_WORKSTATION
? _T("") : _T(" Server"));
367 if (_tcslen(rcOS
.szCSDVersion
) > 0)
370 info
+= rcOS
.szCSDVersion
;
377 CString
GetModuleInformation()
380 TCHAR szApp
[MAX_PATH
];
381 if (!GetModuleFileName(NULL
, szApp
, _countof(szApp
)))
387 DWORD dwInfoSize
= GetFileVersionInfoSize(szApp
, &dwDummy
);
390 LPVOID pInfoBuffer
= _alloca(dwInfoSize
);
391 if (GetFileVersionInfo(szApp
, 0, dwInfoSize
, pInfoBuffer
))
393 VS_FIXEDFILEINFO
*pInfo
= NULL
;
395 if (VerQueryValue (pInfoBuffer
, _T("\\"), (LPVOID
*)&pInfo
, &nInfoSize
) && nInfoSize
== sizeof(VS_FIXEDFILEINFO
))
397 info
.AppendFormat(_T(" (%d.%d.%d.%d)"),
398 HIWORD(pInfo
->dwFileVersionMS
),
399 LOWORD(pInfo
->dwFileVersionMS
),
400 HIWORD(pInfo
->dwFileVersionLS
),
401 LOWORD(pInfo
->dwFileVersionLS
)
407 info
.AppendFormat(_T(" PID: %d (0x%x)"), GetCurrentProcessId(), GetCurrentProcessId());
412 //////////////////////////////////////////////////////////////////////////
414 //////////////////////////////////////////////////////////////////////////
416 ConsoleMedia::ConsoleMedia()
418 m_bRedirectedToFile
= true;
420 m_hConsole
= GetStdHandle(STD_OUTPUT_HANDLE
);
421 if (m_hConsole
== NULL
)
423 if (!AllocConsole() //|| !SetConsoleTitle(_T("Log"))
424 || (m_hConsole
= GetStdHandle(STD_OUTPUT_HANDLE
)) == NULL
)
427 GetConsoleScreenBufferInfo(m_hConsole
, &m_info
);
430 m_bRedirectedToFile
= GetConsoleMode(m_hConsole
, &t
) == FALSE
;
433 void ConsoleMedia::Write(ELogMessageType type
,
434 ELogMessageLevel nLevel
,
438 LPCTSTR pszThreadName
,
442 if (m_hConsole
==NULL
)
444 WORD color
= FOREGROUND_GREEN
|FOREGROUND_INTENSITY
;
445 //FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_INTENSITY|BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_BLUE|BACKGROUND_INTENSITY;
449 color
= FOREGROUND_RED
|FOREGROUND_GREEN
|FOREGROUND_BLUE
;
452 color
= FOREGROUND_RED
|FOREGROUND_GREEN
|FOREGROUND_INTENSITY
;
455 color
= FOREGROUND_RED
|FOREGROUND_INTENSITY
;
460 FormatLogMessage(type
, nLevel
, pszDate
, pszTime
, pszThreadId
, pszThreadName
, pszModule
, pszMessage
, output
);
462 if (m_bRedirectedToFile
)
465 CStringA outputA
= output
;
468 CriticalSection::SyncLock
lock(m_cs
);
470 WriteFile(m_hConsole
, (LPCSTR
)outputA
, (DWORD
)outputA
.GetLength(), &dwWritten
, NULL
);
477 CriticalSection::SyncLock
lock(m_cs
);
478 SetConsoleTextAttribute(m_hConsole
, color
);
480 WriteConsole(m_hConsole
, (LPCTSTR
)output
, (DWORD
)output
.GetLength(), &dwWritten
, NULL
);
482 SetConsoleTextAttribute(m_hConsole
, m_info
.wAttributes
);
483 WriteConsole(m_hConsole
, _T("\n"), 1, &dwWritten
, NULL
);
487 //////////////////////////////////////////////////////////////////////////
489 //////////////////////////////////////////////////////////////////////////
491 FileMedia::FileMedia(LPCTSTR pszFilename
, bool bAppend
, bool bFlush
, bool bNewFileDaily
)
492 : m_bAppend(bAppend
), m_bFlush(bFlush
), m_bNewFileDaily(bNewFileDaily
), m_wLogYear(0), m_wLogMonth(0), m_wLogDay(0),
493 m_sOrigFilename(pszFilename
)
498 FileMedia::~FileMedia()
503 void FileMedia::CloseLogFile()
505 if (m_hFile
!= INVALID_HANDLE_VALUE
&& WaitForSingleObject(m_hMutex
, 1000) != WAIT_TIMEOUT
)
511 _T("=================================================\r\n")
512 _T("=== Trace Log Finished on %i-%02i-%02i %02i:%02i:%02i ===\r\n")
513 _T("=================================================\r\n")
514 , st
.wYear
, st
.wMonth
, st
.wDay
, st
.wHour
, st
.wMinute
, st
.wSecond
);
516 LONG dwDistanceToMoveHigh
= 0; // Нужен, чтобы писать в файлы больше 4Гб
517 VERIFY(SetFilePointer(m_hFile
, 0, &dwDistanceToMoveHigh
, FILE_END
) != INVALID_SET_FILE_POINTER
|| GetLastError() == NO_ERROR
);
518 CStringA headerA
= header
;
520 // VERIFY(WriteFile(m_hFile, (LPCTSTR)header, (DWORD) header.size() * sizeof(TCHAR), &dwWritten, NULL));
521 VERIFY(WriteFile(m_hFile
, (LPCSTR
)headerA
, (DWORD
) headerA
.GetLength() * sizeof(CHAR
), &dwWritten
, NULL
));
522 VERIFY(ReleaseMutex(m_hMutex
));
526 bool FileMedia::IsWorking() const
528 return m_hFile
!= INVALID_HANDLE_VALUE
;
531 void FileMedia::OpenLogFile()
536 m_sFilename
= m_sOrigFilename
;
537 m_sFilename
.Replace(_T("%DATETIME%"), _T("%DATE% %TIME%"));
538 if (m_sFilename
.Find(_T("%DATE%")) != -1)
541 _stprintf_s(bufdate
, _T("%i-%02i-%02i"), st
.wYear
, st
.wMonth
, st
.wDay
);
542 m_sFilename
.Replace(_T("%DATE%"), bufdate
);
543 m_wLogYear
= st
.wYear
;
544 m_wLogMonth
= st
.wMonth
;
547 if (m_sFilename
.Find(_T("%TIME%")) != -1)
551 _stprintf_s(buftime
, _T("%02i-%02i"), st
.wHour
, st
.wMinute
);
552 m_sFilename
.Replace(_T("%TIME%"), buftime
);
555 if (!CreateFileDir(m_sFilename
))
557 _RPT1(_CRT_ERROR
, "FileMedia: Can't create folder '%S'", (LPCWSTR
) CStringW(m_sFilename
));
562 // Создадим для доступа к этому файлу мьютекс
563 CString
sMtx(m_sFilename
);
565 for (int i
= 0, size
= sMtx
.GetLength(); i
< size
; ++i
)
567 if (!_istalnum(sMtx
[i
]))
568 sMtx
.SetAt(i
, _T('_'));
570 m_hMutex
= CreateMutex(NULL
, TRUE
, (LPCTSTR
)sMtx
);
571 DWORD dwMtxError
= GetLastError();
573 m_hFile
= CreateFile(m_sFilename
,
575 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
577 (m_bAppend
|| dwMtxError
== ERROR_ALREADY_EXISTS
) ? OPEN_ALWAYS
: CREATE_ALWAYS
,
578 FILE_ATTRIBUTE_NORMAL
,
581 if (m_hFile
== INVALID_HANDLE_VALUE
)
583 if (dwMtxError
!= ERROR_ALREADY_EXISTS
)
584 VERIFY(ReleaseMutex(m_hMutex
));
589 if (dwMtxError
!= ERROR_ALREADY_EXISTS
)
593 _T("================================================\r\n")
594 _T("=== Trace Log Started on %i-%02i-%02i %02i:%02i:%02i ===\r\n")
596 _T("================================================\r\n")
598 , st
.wYear
, st
.wMonth
, st
.wDay
, st
.wHour
, st
.wMinute
, st
.wSecond
599 , (LPCTSTR
)GetSystemInformation()
600 , (LPCTSTR
)GetModuleInformation());
602 LONG dwDistanceToMoveHigh
= 0; // Нужен, чтобы писать в файлы больше 4Гб
603 VERIFY(SetFilePointer(m_hFile
, 0, &dwDistanceToMoveHigh
, FILE_END
) != INVALID_SET_FILE_POINTER
|| GetLastError() == NO_ERROR
);
604 CStringA headerA
= header
;
606 VERIFY(WriteFile(m_hFile
, (LPCSTR
)headerA
, (DWORD
)headerA
.GetLength() * sizeof(CHAR
), &dwWritten
, NULL
));
607 if (m_hMutex
!= NULL
)
608 VERIFY(ReleaseMutex(m_hMutex
));
612 void FileMedia::Write(ELogMessageType type
, ELogMessageLevel nLevel
, LPCTSTR pszDate
, LPCTSTR pszTime
, LPCTSTR pszThreadId
, LPCTSTR pszThreadName
, LPCTSTR pszModule
, LPCTSTR pszMessage
)
614 if (m_bNewFileDaily
&& m_wLogYear
!= 0)
618 if (st
.wDay
!= m_wLogDay
|| st
.wMonth
!= m_wLogMonth
|| st
.wDay
!= m_wLogDay
)
625 if (WaitForSingleObject(m_hMutex
, 1000) == WAIT_TIMEOUT
)
628 // trying to restore access
629 if (m_hFile
== INVALID_HANDLE_VALUE
)
631 m_hFile
= CreateFile(m_sFilename
,
633 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
636 FILE_ATTRIBUTE_NORMAL
,
638 if (m_hFile
== INVALID_HANDLE_VALUE
)
640 VERIFY(ReleaseMutex(m_hMutex
));
645 LONG dwDistanceToMoveHigh
= 0; // Нужен, чтобы писать в файлы больше 4Гб
646 if (SetFilePointer(m_hFile
, 0, &dwDistanceToMoveHigh
, FILE_END
) == INVALID_SET_FILE_POINTER
647 && GetLastError() != NO_ERROR
)
649 _RPT0(_CRT_ERROR
, "FileMedia: Can't set file pointer");
651 VERIFY(ReleaseMutex(m_hMutex
));
656 FormatLogMessage(type
, nLevel
, pszDate
, pszTime
, pszThreadId
, pszThreadName
, pszModule
, pszMessage
, output
);
657 output
+= _T("\r\n");
659 CStringA outputA
= output
;
662 VERIFY(WriteFile(m_hFile
, (LPCSTR
)outputA
, (DWORD
) outputA
.GetLength() * sizeof(CHAR
), &dwWritten
, NULL
));
664 VERIFY(FlushFileBuffers(m_hFile
));
665 VERIFY(ReleaseMutex(m_hMutex
));
668 //////////////////////////////////////////////////////////////////////////
670 //////////////////////////////////////////////////////////////////////////
672 DebugMedia::DebugMedia(DWORD dwParam
)
677 extern "C" WINBASEAPI BOOL WINAPI
IsDebuggerPresent ( VOID
);
679 bool DebugMedia::IsWorking() const
681 return (m_dwParam
& LogBase::DEBUGMEDIA_FORCE
) ? true : IsDebuggerPresent() != FALSE
;
684 void DebugMedia::Write(ELogMessageType type
,
685 ELogMessageLevel nLevel
,
689 LPCTSTR pszThreadName
,
694 FormatLogMessage(type
, nLevel
, pszDate
, pszTime
, pszThreadId
, pszThreadName
, pszModule
, pszMessage
, output
);
697 OutputDebugString(output
);
698 if (type
== eLM_Error
&& (m_dwParam
& LogBase::DEBUGMEDIA_REPORTERRORS
))
700 _RPT1(_CRT_ERROR
, "%ws", static_cast<LPCWSTR
>(output
));
704 //////////////////////////////////////////////////////////////////////////
706 //////////////////////////////////////////////////////////////////////////
708 LogMediaProxy::LogMediaProxy(const LogMediaPtr
& pLog
)
713 LogMediaProxy::~LogMediaProxy()
717 void LogMediaProxy::SetLog(const LogMediaPtr
& pLog
)
719 CriticalSection::SyncLock
lock(m_cs
);
723 void LogMediaProxy::Write(ELogMessageType type
, ELogMessageLevel nLevel
, LPCTSTR pszDate
, LPCTSTR pszTime
, LPCTSTR pszThreadId
, LPCTSTR pszThreadName
, LPCTSTR pszModule
, LPCTSTR pszMessage
)
725 CriticalSection::SyncLock
lock(m_cs
);
727 m_pLog
->Write(type
, nLevel
, pszDate
, pszTime
, pszThreadId
, pszThreadName
, pszModule
, pszMessage
);
730 bool LogMediaProxy::Check(ELogMessageType type
, ELogMessageLevel nLevel
, LPCTSTR pszModule
)
732 CriticalSection::SyncLock
lock(m_cs
);
734 return m_pLog
->Check(type
, nLevel
, pszModule
);
738 //////////////////////////////////////////////////////////////////////////
740 //////////////////////////////////////////////////////////////////////////
742 LogMediaColl::LogMediaColl()
746 LogMediaColl::~LogMediaColl()
750 void LogMediaColl::Add(const LogMediaPtr
& pMedia
)
754 CriticalSection::SyncLock
lock(m_cs
);
755 m_MediaColl
.push_back(pMedia
);
758 void LogMediaColl::Write(ELogMessageType type
, ELogMessageLevel nLevel
, LPCTSTR pszDate
, LPCTSTR pszTime
, LPCTSTR pszThreadId
, LPCTSTR pszThreadName
, LPCTSTR pszModule
, LPCTSTR pszMessage
)
760 CriticalSection::SyncLock
lock(m_cs
);
761 for (MediaColl::iterator it
= m_MediaColl
.begin(), end
= m_MediaColl
.end(); it
!= end
; ++it
)
762 (*it
)->Write(type
, nLevel
, pszDate
, pszTime
, pszThreadId
, pszThreadName
, pszModule
, pszMessage
);
765 bool LogMediaColl::Check(ELogMessageType type
, ELogMessageLevel nLevel
, LPCTSTR pszModule
)
767 CriticalSection::SyncLock
lock(m_cs
);
768 // Если хотя бы один лог пропускает, то и мы пропускаем.
769 for (MediaColl::iterator it
= m_MediaColl
.begin(), end
= m_MediaColl
.end(); it
!= end
; ++it
)
770 if ((*it
)->Check(type
, nLevel
, pszModule
))
775 //////////////////////////////////////////////////////////////////////////
777 //////////////////////////////////////////////////////////////////////////
779 FilterLogMedia::FilterLogMedia(const LogMediaPtr
& pMedia
)
784 FilterLogMedia::~FilterLogMedia()
788 void FilterLogMedia::AddFilter(FilterPtr pFilter
)
790 CriticalSection::SyncLock
lock(m_cs
);
791 m_FilterColl
.push_back(pFilter
);
794 void FilterLogMedia::Write(ELogMessageType type
, ELogMessageLevel nLevel
, LPCTSTR pszDate
, LPCTSTR pszTime
, LPCTSTR pszThreadId
, LPCTSTR pszThreadName
, LPCTSTR pszModule
, LPCTSTR pszMessage
)
799 CriticalSection::SyncLock
lock(m_cs
);
800 for (FilterColl::iterator it
= m_FilterColl
.begin(), end
= m_FilterColl
.end(); it
!= end
; ++it
)
801 if (!(*it
)->Check(type
, nLevel
, pszModule
))
804 m_pMedia
->Write(type
, nLevel
, pszDate
, pszTime
, pszThreadId
, pszThreadName
, pszModule
, pszMessage
);
807 bool FilterLogMedia::Check(ELogMessageType type
, ELogMessageLevel nLevel
, LPCTSTR pszModule
)
812 CriticalSection::SyncLock
lock(m_cs
);
813 for (FilterColl::iterator it
= m_FilterColl
.begin(), end
= m_FilterColl
.end(); it
!= end
; ++it
)
814 if (!(*it
)->Check(type
, nLevel
, pszModule
))
817 return m_pMedia
->Check(type
, nLevel
, pszModule
);
820 //////////////////////////////////////////////////////////////////////////
822 //////////////////////////////////////////////////////////////////////////
824 LogBase::LogBase(LogMediaPtr pMedia
, LPCTSTR pszModule
)
825 : m_szModule(pszModule
)
828 ASSERT(pszModule
!= NULL
);
835 template <typename T
, size_t nSize
>
836 class StackResizableBuf
839 void Clear() { if (data
!= loc_data
) delete[] data
; }
841 StackResizableBuf() { data
= loc_data
; size
= nSize
; }
842 ~StackResizableBuf() { Clear(); }
843 void Resize(size_t nNewSize
) { Clear(); data
= new T
[nNewSize
]; size
= nNewSize
; }
849 bool LogBase::IsFiltered(ELogMessageType type
, ELogMessageLevel nLevel
)
851 return !m_pMedia
|| !m_pMedia
->Check(type
, nLevel
, m_szModule
.c_str());
854 void LogBase::WriteVA(ELogMessageType type
,
855 ELogMessageLevel nLevel
,
858 va_list args
) throw()
860 if (IsFiltered(type
, nLevel
)) // не обрабатываем сообщение, если оно не попадает в лог
862 // 75% времени тратится на new и delete, поэтому первую попытку попробуем сделать без него.
863 StackResizableBuf
<TCHAR
, 16*1024> buf
;
867 pos
= _vsntprintf_s(buf
.data
, buf
.size
, buf
.size
- 1, pszMessage
, args
);
870 // BUG 16456 FIX, см. в конец WriteVAW почему
871 //if (buf.size >= 1024 * 256)
872 if (buf
.size
>= 1024 * 1024 * 10) //Increased limit for DumpServer
874 pos
= (int)buf
.size
- 1;
877 buf
.Resize(buf
.size
* 2);
884 TCHAR bufdate
[128], buftime
[128], bufthread
[128];
885 _stprintf_s(bufdate
, _T("%i-%02i-%02i"), st
.wYear
, st
.wMonth
, st
.wDay
);
886 _stprintf_s(buftime
, _T("%02i:%02i:%02i.%03d"), st
.wHour
, st
.wMinute
, st
.wSecond
, st
.wMilliseconds
);
887 _stprintf_s(bufthread
, _T("%4x"), GetCurrentThreadId());
888 m_pMedia
->Write(type
, nLevel
, bufdate
, buftime
, bufthread
, GetThreadName()
889 , pszModule
? pszModule
: m_szModule
.c_str(), buf
.data
);
893 void LogBase::WriteVAW(ELogMessageType type
,
894 ELogMessageLevel nLevel
,
897 va_list args
) throw()
899 #if defined(_UNICODE) || defined(UNICODE)
900 WriteVA(type
, nLevel
, pszModule
, pszMessage
, args
);
903 if (IsFiltered(type
, nLevel
)) // не обрабатываем сообщение, если оно не попадает в лог
905 // 75% времени тратится на new и delete, поэтому первую попытку попробуем сделать без него.
906 StackResizableBuf
<WCHAR
, 1024> buf
;
910 pos
= _vsnwprintf(buf
.data
, buf
.size
- 1, pszMessage
, args
);
913 // BUG 16456 FIX, см. в конец WriteVAW почему
914 if (buf
.size
>= 1024 * 256)
919 buf
.Resize(buf
.size
* 2);
924 LPTSTR pszStr
= static_cast<LPTSTR
>(_alloca(buf
.size
));
925 if (0 == WideCharToMultiByte(CP_ACP
, 0/*WC_DEFAULTCHAR*/, buf
.data
, pos
+ 1, pszStr
, buf
.size
, NULL
, NULL
))
927 _RPT1(_CRT_ERROR
, "Can't convert Unicode string (error #0x%08X)", GetLastError());
932 if (pszModule
== NULL
)
933 pszMod
= m_szModule
.c_str();
936 size_t nModuleLen
= wcslen(pszModule
) + 1;
937 LPTSTR pszModBuf
= static_cast<LPTSTR
>(_alloca(nModuleLen
));
938 if (0 == WideCharToMultiByte(CP_ACP
, 0/*WC_DEFAULTCHAR*/, pszModule
, nModuleLen
, pszModBuf
, nModuleLen
, NULL
, NULL
))
940 _RPT1(_CRT_ERROR
, "Can't convert Unicode string (error #0x%08X)", GetLastError());
948 TCHAR bufdate
[128], buftime
[128], bufthread
[128];
949 _stprintf(bufdate
, _T("%i-%02i-%02i"), st
.wYear
, st
.wMonth
, st
.wDay
);
950 _stprintf(buftime
, _T("%02i:%02i:%02i.%03d"), st
.wHour
, st
.wMinute
, st
.wSecond
, st
.wMilliseconds
);
951 _stprintf(bufthread
, _T("%03x"), GetCurrentThreadId());
952 m_pMedia
->Write(type
, nLevel
, bufdate
, buftime
, bufthread
, GetThreadName(), pszMod
, pszStr
);
956 _vsnwprintf спотыкается на строках с символом 0xFFFF,
957 возвращает -1 при любой длине буфера. Соответсвтвенно
958 буфер увеличивается (Resize) пока не хватит памяти,
959 а потом вызывается _vsnwprintf на NULL.
960 Решение: Т.к. _vsnwprintf, даже если нехватает буфера, начало заполняет,
961 то просто ограничим буфер 256кб (а 0 на конце и так ставим на всякий случай)
966 void WriteVAW(wchar_t* pszMessage, va_list args)
969 int n = _vsnwprintf(buf, 1000, pszMessage, args);
970 printf("Return %i\nBuf is: \"%ls\"", n, buf); // n будет -1, хотя буфера хватает !!!
972 void WriteW(wchar_t* pszMessage, ...)
975 va_start(ap, pszMessage);
976 WriteVAW(pszMessage, ap);
981 WriteW(L"%ls!", L"123\xffff");
987 //////////////////////////////////////////////////////////////////////////
989 //////////////////////////////////////////////////////////////////////////
991 LocalLog::LocalLog(const LogParam
& param
, LPCTSTR pszModule
)
992 : LogBase(param
.m_pMedia
, param
.m_pszModule
? param
.m_pszModule
: pszModule
)
996 LocalLog::LocalLog(LogMediaPtr pMedia
, LPCTSTR pszModule
)
997 : LogBase(pMedia
, pszModule
)
999 ASSERT(pszModule
!= NULL
);
1002 LocalLog::LocalLog(const LogBase
& log
, LPCTSTR pszModule
)
1003 : LogBase(log
.GetMedia(), pszModule
)
1007 LocalLog::~LocalLog()
1011 //////////////////////////////////////////////////////////////////////////
1013 //////////////////////////////////////////////////////////////////////////
1015 Log::Log(const LogParam
& param
, LPCTSTR pszModule
)
1016 : LogBase(param
.m_pMedia
, param
.m_pszModule
? param
.m_pszModule
: pszModule
)
1020 Log::Log(LogMediaPtr pMedia
, LPCTSTR pszModule
)
1021 : LogBase(pMedia
, pszModule
)
1025 Log::Log(const LogBase
& log
, LPCTSTR pszModule
)
1026 : LogBase(log
.GetMedia(), pszModule
)
1034 void Log::SetParams(LogMediaPtr pMedia
, LPCTSTR pszModule
)
1036 CriticalSection::SyncLock
lock(m_cs
);
1038 if (pszModule
!= NULL
)
1039 m_szModule
= pszModule
;
1042 void Log::WriteVA(ELogMessageType type
,
1043 ELogMessageLevel nLevel
,
1046 va_list args
) throw()
1048 CriticalSection::SyncLock
lock(m_cs
);
1049 LogBase::WriteVA(type
, nLevel
, pszModule
, pszMessage
, args
);
1052 void Log::WriteVAW(ELogMessageType type
,
1053 ELogMessageLevel nLevel
,
1056 va_list args
) throw()
1058 CriticalSection::SyncLock
lock(m_cs
);
1059 LogBase::WriteVAW(type
, nLevel
, pszModule
, pszMessage
, args
);
1062 //////////////////////////////////////////////////////////////////////////
1064 //////////////////////////////////////////////////////////////////////////
1066 FilterLog::~FilterLog()