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 #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
28 #include <VersionHelpers.h>
31 #define ASSERT(f) assert(f)
35 # define VERIFY(f) ASSERT(f)
37 # define VERIFY(f) ((void)(f))
41 static DWORD g_dwThreadNameTlsId
= TLS_OUT_OF_INDEXES
;
42 static LPTSTR pszUnknownThreadName
= _T("Unknown");
45 static bool bInitialized
= false;
49 g_dwThreadNameTlsId
= TlsAlloc();
50 ASSERT(g_dwThreadNameTlsId
!= TLS_OUT_OF_INDEXES
);
52 LPCTSTR
GetLogThreadName()
54 ASSERT(g_dwThreadNameTlsId
!= TLS_OUT_OF_INDEXES
);
55 if (g_dwThreadNameTlsId
== TLS_OUT_OF_INDEXES
)
57 return static_cast<LPCTSTR
>(TlsGetValue(g_dwThreadNameTlsId
));
59 void FreeLogThreadName()
61 ASSERT(g_dwThreadNameTlsId
!= TLS_OUT_OF_INDEXES
);
62 if (g_dwThreadNameTlsId
== TLS_OUT_OF_INDEXES
)
64 LPTSTR pThreadName
= static_cast<LPTSTR
>(TlsGetValue(g_dwThreadNameTlsId
));
65 if (pThreadName
!= pszUnknownThreadName
)
68 VERIFY(TlsSetValue(g_dwThreadNameTlsId
, pszUnknownThreadName
));
71 void SetLogThreadName(LPCTSTR pszThreadName
)
73 ASSERT(g_dwThreadNameTlsId
!= TLS_OUT_OF_INDEXES
);
74 if (g_dwThreadNameTlsId
== TLS_OUT_OF_INDEXES
)
77 VERIFY(TlsSetValue(g_dwThreadNameTlsId
, LPVOID(pszThreadName
!= NULL
? _tcsdup(pszThreadName
) : pszUnknownThreadName
)));
78 // SetDebuggerThreadName(-1, __LPCSTR(pszThreadName));
81 //! Создаёт путь к файлу.
82 bool CreateFileDir(LPCTSTR pszFilePath
)
87 DWORD dwRes
= GetFullPathName(pszFilePath
, sizeof(szBuffer
)/sizeof(*szBuffer
), szBuffer
, &pszFilePart
);
89 || dwRes
>= sizeof(szBuffer
)/sizeof(*szBuffer
)
90 || pszFilePart
== NULL
)
94 *pszFilePart
= _T('\0');
96 CString
sPath(szBuffer
);
97 sPath
.Replace(_T('/'), _T('\\'));
98 ASSERT(sPath
.Right(1) == _T("\\"));
101 if (sPath
.Left(2) == _T("\\\\"))
102 nPos
= sPath
.Find(_T("\\"), sPath
.Find(_T("\\"), 2) + 1) + 1; // Пропустим имя компьютера и шары
104 nPos
= 4; // Пропустим имя диска
105 while ( (nPos
= sPath
.Find(_T('\\'), nPos
+ 1)) != -1)
107 if (!CreateDirectory(sPath
.Left(nPos
), NULL
) && GetLastError() != ERROR_ALREADY_EXISTS
)
113 void LogBase::SetThreadName(LPCTSTR pszThreadName
)
115 SetLogThreadName(pszThreadName
);
118 LPCTSTR
LogBase::GetThreadName()
120 LPCTSTR pszName
= GetLogThreadName();
121 return pszName
? pszName
: _T("Unknown");
125 LogMediaPtr
LogBase::GetAppLogMedia()
127 static LogMediaPtr
pAppLog(new LogMediaProxy());
131 void LogBase::SetAppLogMedia(LogMediaPtr pLog
)
133 ASSERT(pLog
!= GetAppLogMedia());
134 if (pLog
== GetAppLogMedia())
136 std::static_pointer_cast
<LogMediaProxy
>(GetAppLogMedia())->SetLog(pLog
);
139 LogMediaPtr
LogBase::CreateConsoleMedia()
141 static LogMediaPtr
pConsoleMedia(new ConsoleMedia());
142 if (pConsoleMedia
->IsWorking())
143 return pConsoleMedia
;
144 return LogMediaPtr();
147 LogMediaPtr
LogBase::CreateFileMedia(LPCTSTR pszFilename
, bool bAppend
, bool bFlush
, bool bNewFileDaily
)
149 LogMediaPtr
pLog(new FileMedia(pszFilename
, bAppend
, bFlush
, bNewFileDaily
));
150 if (pLog
->IsWorking())
152 return LogMediaPtr();
155 LogMediaPtr
LogBase::CreateDebugMedia(DWORD dwParam
)
157 LogMediaPtr
pDebugMedia(new DebugMedia(dwParam
));
158 if (pDebugMedia
->IsWorking())
160 return LogMediaPtr();
164 //////////////////////////////////////////////////////////////////////////
166 //////////////////////////////////////////////////////////////////////////
168 void FormatLogMessage(ELogMessageType type
,
169 ELogMessageLevel nLevel
,
173 LPCTSTR pszThreadName
,
180 output
.Preallocate(1024);
182 if (type
!= eLM_DirectOutput
)
187 #if defined(LOG_THREAD_NAME)
189 output
+= pszThreadId
;
191 size_t nThreadNameLen
= _tcslen(pszThreadName
);
192 if (nThreadNameLen
> 12)
193 output
.append(pszThreadName
, 12);
196 output
.append(12 - nThreadNameLen
, _T(' '));
197 output
+= pszThreadName
;
202 output
+= pszThreadId
;
225 output
.AppendFormat(_T("%i"), nLevel
);
229 output
+= _T(" : [");
236 output
+= pszMessage
;
240 output
.reserve(1024);
246 output
+= pszThreadId
;
248 output
+= pszThreadName
;
272 output
.AppendFormat(_T("%i"), nLevel
);
274 output
+= pszMessage
;
279 CString
GetSystemInformation()
281 CString info
= _T("Microsoft Windows ");
283 #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
284 if (IsWindows8Point1OrGreater())
285 info
+= _T(">= 8.1");
286 else if (IsWindows8OrGreater())
288 else if (IsWindows7SP1OrGreater())
290 else if (IsWindows7OrGreater())
292 else if (IsWindowsVistaSP2OrGreater())
293 info
+= _T("Vista SP2");
294 else if (IsWindowsVistaSP1OrGreater())
295 info
+= _T("Vista SP1");
296 else if (IsWindowsVistaOrGreater())
299 if (IsWindowsServer())
300 info
+= _T(" Server");
302 info
+= _T(" Client");
304 OSVERSIONINFOEX rcOS
;
305 ZeroMemory(&rcOS
, sizeof(rcOS
));
306 rcOS
.dwOSVersionInfoSize
= sizeof(rcOS
);
308 GetVersionEx((OSVERSIONINFO
*)&rcOS
);
310 if (rcOS
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
)
312 switch (rcOS
.dwMinorVersion
)
314 case 0: info
+= _T("95"); break;
315 case 10: info
+= _T("98"); break;
316 case 90: info
+= _T("Me"); break;
318 if (!_tcscmp(rcOS
.szCSDVersion
, _T(" A")))
319 info
+= _T(" Second Edition");
321 if (!_tcscmp(rcOS
.szCSDVersion
, _T(" C")))
324 else if (rcOS
.dwPlatformId
== VER_PLATFORM_WIN32_NT
)
326 switch (rcOS
.dwMajorVersion
)
328 case 3: info
+= _T("NT 3.51"); break;
329 case 4: info
+= _T("NT 4.0"); break;
331 switch (rcOS
.dwMinorVersion
)
333 case 0: info
+= _T("2000"); break;
334 case 1: info
+= _T("XP"); break;
335 case 2: info
+= _T("2003 Server"); break;
336 default: ASSERT(false); info
+= _T("future version"); break;
340 switch (rcOS
.dwMinorVersion
)
342 case 0: info
+= rcOS
.wProductType
== VER_NT_WORKSTATION
? _T("Vista") : _T("Server 2008"); break;
343 case 1: info
+= rcOS
.wProductType
== VER_NT_WORKSTATION
? _T("7") : _T("Server 2008 R2"); break;
344 case 2: info
+= rcOS
.wProductType
== VER_NT_WORKSTATION
? _T("8") : _T("Server 2012"); break;
345 case 3: info
+= rcOS
.wProductType
== VER_NT_WORKSTATION
? _T("8.1") : _T("Server 2012 R2"); break;
349 future
.Format(_T("%ld.%ld%s"), rcOS
.dwMajorVersion
, rcOS
.dwMinorVersion
, VER_NT_WORKSTATION
? _T("") : _T(" Server"));
358 future
.Format(_T("%ld.%ld%s"), rcOS
.dwMajorVersion
, rcOS
.dwMinorVersion
, VER_NT_WORKSTATION
? _T("") : _T(" Server"));
363 if (_tcslen(rcOS
.szCSDVersion
) > 0)
366 info
+= rcOS
.szCSDVersion
;
373 CString
GetModuleInformation()
376 TCHAR szApp
[MAX_PATH
];
377 if (!GetModuleFileName(NULL
, szApp
, _countof(szApp
)))
383 DWORD dwInfoSize
= GetFileVersionInfoSize(szApp
, &dwDummy
);
386 LPVOID pInfoBuffer
= _alloca(dwInfoSize
);
387 if (GetFileVersionInfo(szApp
, 0, dwInfoSize
, pInfoBuffer
))
389 VS_FIXEDFILEINFO
*pInfo
= NULL
;
391 if (VerQueryValue (pInfoBuffer
, _T("\\"), (LPVOID
*)&pInfo
, &nInfoSize
) && nInfoSize
== sizeof(VS_FIXEDFILEINFO
))
393 info
.AppendFormat(_T(" (%d.%d.%d.%d)"),
394 HIWORD(pInfo
->dwFileVersionMS
),
395 LOWORD(pInfo
->dwFileVersionMS
),
396 HIWORD(pInfo
->dwFileVersionLS
),
397 LOWORD(pInfo
->dwFileVersionLS
)
403 info
.AppendFormat(_T(" PID: %d (0x%x)"), GetCurrentProcessId(), GetCurrentProcessId());
408 //////////////////////////////////////////////////////////////////////////
410 //////////////////////////////////////////////////////////////////////////
412 ConsoleMedia::ConsoleMedia()
414 m_bRedirectedToFile
= true;
416 m_hConsole
= GetStdHandle(STD_OUTPUT_HANDLE
);
417 if (m_hConsole
== NULL
)
419 if (!AllocConsole() //|| !SetConsoleTitle(_T("Log"))
420 || (m_hConsole
= GetStdHandle(STD_OUTPUT_HANDLE
)) == NULL
)
423 GetConsoleScreenBufferInfo(m_hConsole
, &m_info
);
426 m_bRedirectedToFile
= GetConsoleMode(m_hConsole
, &t
) == FALSE
;
429 void ConsoleMedia::Write(ELogMessageType type
,
430 ELogMessageLevel nLevel
,
434 LPCTSTR pszThreadName
,
438 if (m_hConsole
==NULL
)
440 WORD color
= FOREGROUND_GREEN
|FOREGROUND_INTENSITY
;
441 //FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_INTENSITY|BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_BLUE|BACKGROUND_INTENSITY;
445 color
= FOREGROUND_RED
|FOREGROUND_GREEN
|FOREGROUND_BLUE
;
448 color
= FOREGROUND_RED
|FOREGROUND_GREEN
|FOREGROUND_INTENSITY
;
451 color
= FOREGROUND_RED
|FOREGROUND_INTENSITY
;
456 FormatLogMessage(type
, nLevel
, pszDate
, pszTime
, pszThreadId
, pszThreadName
, pszModule
, pszMessage
, output
);
458 if (m_bRedirectedToFile
)
461 CStringA outputA
= output
;
464 CriticalSection::SyncLock
lock(m_cs
);
466 WriteFile(m_hConsole
, (LPCSTR
)outputA
, (DWORD
)outputA
.GetLength(), &dwWritten
, NULL
);
473 CriticalSection::SyncLock
lock(m_cs
);
474 SetConsoleTextAttribute(m_hConsole
, color
);
476 WriteConsole(m_hConsole
, (LPCTSTR
)output
, (DWORD
)output
.GetLength(), &dwWritten
, NULL
);
478 SetConsoleTextAttribute(m_hConsole
, m_info
.wAttributes
);
479 WriteConsole(m_hConsole
, _T("\n"), 1, &dwWritten
, NULL
);
483 //////////////////////////////////////////////////////////////////////////
485 //////////////////////////////////////////////////////////////////////////
487 FileMedia::FileMedia(LPCTSTR pszFilename
, bool bAppend
, bool bFlush
, bool bNewFileDaily
)
488 : m_bAppend(bAppend
), m_bFlush(bFlush
), m_bNewFileDaily(bNewFileDaily
), m_wLogYear(0), m_wLogMonth(0), m_wLogDay(0),
489 m_sOrigFilename(pszFilename
)
494 FileMedia::~FileMedia()
499 void FileMedia::CloseLogFile()
501 if (m_hFile
!= INVALID_HANDLE_VALUE
&& WaitForSingleObject(m_hMutex
, 1000) != WAIT_TIMEOUT
)
507 _T("=================================================\r\n")
508 _T("=== Trace Log Finished on %i-%02i-%02i %02i:%02i:%02i ===\r\n")
509 _T("=================================================\r\n")
510 , st
.wYear
, st
.wMonth
, st
.wDay
, st
.wHour
, st
.wMinute
, st
.wSecond
);
512 LONG dwDistanceToMoveHigh
= 0; // Нужен, чтобы писать в файлы больше 4Гб
513 VERIFY(SetFilePointer(m_hFile
, 0, &dwDistanceToMoveHigh
, FILE_END
) != INVALID_SET_FILE_POINTER
|| GetLastError() == NO_ERROR
);
514 CStringA headerA
= header
;
516 // VERIFY(WriteFile(m_hFile, (LPCTSTR)header, (DWORD) header.size() * sizeof(TCHAR), &dwWritten, NULL));
517 VERIFY(WriteFile(m_hFile
, (LPCSTR
)headerA
, (DWORD
) headerA
.GetLength() * sizeof(CHAR
), &dwWritten
, NULL
));
518 VERIFY(ReleaseMutex(m_hMutex
));
522 bool FileMedia::IsWorking() const
524 return m_hFile
!= INVALID_HANDLE_VALUE
;
527 void FileMedia::OpenLogFile()
532 m_sFilename
= m_sOrigFilename
;
533 m_sFilename
.Replace(_T("%DATETIME%"), _T("%DATE% %TIME%"));
534 if (m_sFilename
.Find(_T("%DATE%")) != -1)
537 _stprintf_s(bufdate
, _T("%i-%02i-%02i"), st
.wYear
, st
.wMonth
, st
.wDay
);
538 m_sFilename
.Replace(_T("%DATE%"), bufdate
);
539 m_wLogYear
= st
.wYear
;
540 m_wLogMonth
= st
.wMonth
;
543 if (m_sFilename
.Find(_T("%TIME%")) != -1)
547 _stprintf_s(buftime
, _T("%02i-%02i"), st
.wHour
, st
.wMinute
);
548 m_sFilename
.Replace(_T("%TIME%"), buftime
);
551 if (!CreateFileDir(m_sFilename
))
553 _RPT1(_CRT_ERROR
, "FileMedia: Can't create folder '%S'", (LPCWSTR
) CStringW(m_sFilename
));
558 // Создадим для доступа к этому файлу мьютекс
559 CString
sMtx(m_sFilename
);
561 for (int i
= 0, size
= sMtx
.GetLength(); i
< size
; ++i
)
563 if (!_istalnum(sMtx
[i
]))
564 sMtx
.SetAt(i
, _T('_'));
566 m_hMutex
= CreateMutex(NULL
, TRUE
, (LPCTSTR
)sMtx
);
567 DWORD dwMtxError
= GetLastError();
569 m_hFile
= CreateFile(m_sFilename
,
571 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
573 (m_bAppend
|| dwMtxError
== ERROR_ALREADY_EXISTS
) ? OPEN_ALWAYS
: CREATE_ALWAYS
,
574 FILE_ATTRIBUTE_NORMAL
,
577 if (m_hFile
== INVALID_HANDLE_VALUE
)
579 if (dwMtxError
!= ERROR_ALREADY_EXISTS
)
580 VERIFY(ReleaseMutex(m_hMutex
));
585 if (dwMtxError
!= ERROR_ALREADY_EXISTS
)
589 _T("================================================\r\n")
590 _T("=== Trace Log Started on %i-%02i-%02i %02i:%02i:%02i ===\r\n")
592 _T("================================================\r\n")
594 , st
.wYear
, st
.wMonth
, st
.wDay
, st
.wHour
, st
.wMinute
, st
.wSecond
595 , (LPCTSTR
)GetSystemInformation()
596 , (LPCTSTR
)GetModuleInformation());
598 LONG dwDistanceToMoveHigh
= 0; // Нужен, чтобы писать в файлы больше 4Гб
599 VERIFY(SetFilePointer(m_hFile
, 0, &dwDistanceToMoveHigh
, FILE_END
) != INVALID_SET_FILE_POINTER
|| GetLastError() == NO_ERROR
);
600 CStringA headerA
= header
;
602 VERIFY(WriteFile(m_hFile
, (LPCSTR
)headerA
, (DWORD
)headerA
.GetLength() * sizeof(CHAR
), &dwWritten
, NULL
));
603 if (m_hMutex
!= NULL
)
604 VERIFY(ReleaseMutex(m_hMutex
));
608 void FileMedia::Write(ELogMessageType type
, ELogMessageLevel nLevel
, LPCTSTR pszDate
, LPCTSTR pszTime
, LPCTSTR pszThreadId
, LPCTSTR pszThreadName
, LPCTSTR pszModule
, LPCTSTR pszMessage
)
610 if (m_bNewFileDaily
&& m_wLogYear
!= 0)
614 if (st
.wDay
!= m_wLogDay
|| st
.wMonth
!= m_wLogMonth
|| st
.wDay
!= m_wLogDay
)
621 if (WaitForSingleObject(m_hMutex
, 1000) == WAIT_TIMEOUT
)
624 // trying to restore access
625 if (m_hFile
== INVALID_HANDLE_VALUE
)
627 m_hFile
= CreateFile(m_sFilename
,
629 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
632 FILE_ATTRIBUTE_NORMAL
,
634 if (m_hFile
== INVALID_HANDLE_VALUE
)
636 VERIFY(ReleaseMutex(m_hMutex
));
641 LONG dwDistanceToMoveHigh
= 0; // Нужен, чтобы писать в файлы больше 4Гб
642 if (SetFilePointer(m_hFile
, 0, &dwDistanceToMoveHigh
, FILE_END
) == INVALID_SET_FILE_POINTER
643 && GetLastError() != NO_ERROR
)
645 _RPT0(_CRT_ERROR
, "FileMedia: Can't set file pointer");
647 VERIFY(ReleaseMutex(m_hMutex
));
652 FormatLogMessage(type
, nLevel
, pszDate
, pszTime
, pszThreadId
, pszThreadName
, pszModule
, pszMessage
, output
);
653 output
+= _T("\r\n");
655 CStringA outputA
= output
;
658 VERIFY(WriteFile(m_hFile
, (LPCSTR
)outputA
, (DWORD
) outputA
.GetLength() * sizeof(CHAR
), &dwWritten
, NULL
));
660 VERIFY(FlushFileBuffers(m_hFile
));
661 VERIFY(ReleaseMutex(m_hMutex
));
664 //////////////////////////////////////////////////////////////////////////
666 //////////////////////////////////////////////////////////////////////////
668 DebugMedia::DebugMedia(DWORD dwParam
)
673 extern "C" WINBASEAPI BOOL WINAPI
IsDebuggerPresent ( VOID
);
675 bool DebugMedia::IsWorking() const
677 return (m_dwParam
& LogBase::DEBUGMEDIA_FORCE
) ? true : IsDebuggerPresent() != FALSE
;
680 void DebugMedia::Write(ELogMessageType type
,
681 ELogMessageLevel nLevel
,
685 LPCTSTR pszThreadName
,
690 FormatLogMessage(type
, nLevel
, pszDate
, pszTime
, pszThreadId
, pszThreadName
, pszModule
, pszMessage
, output
);
693 OutputDebugString(output
);
694 if (type
== eLM_Error
&& (m_dwParam
& LogBase::DEBUGMEDIA_REPORTERRORS
))
696 _RPT1(_CRT_ERROR
, "%ws", static_cast<LPCWSTR
>(output
));
700 //////////////////////////////////////////////////////////////////////////
702 //////////////////////////////////////////////////////////////////////////
704 LogMediaProxy::LogMediaProxy(const LogMediaPtr
& pLog
)
709 LogMediaProxy::~LogMediaProxy()
713 void LogMediaProxy::SetLog(const LogMediaPtr
& pLog
)
715 CriticalSection::SyncLock
lock(m_cs
);
719 void LogMediaProxy::Write(ELogMessageType type
, ELogMessageLevel nLevel
, LPCTSTR pszDate
, LPCTSTR pszTime
, LPCTSTR pszThreadId
, LPCTSTR pszThreadName
, LPCTSTR pszModule
, LPCTSTR pszMessage
)
721 CriticalSection::SyncLock
lock(m_cs
);
723 m_pLog
->Write(type
, nLevel
, pszDate
, pszTime
, pszThreadId
, pszThreadName
, pszModule
, pszMessage
);
726 bool LogMediaProxy::Check(ELogMessageType type
, ELogMessageLevel nLevel
, LPCTSTR pszModule
)
728 CriticalSection::SyncLock
lock(m_cs
);
730 return m_pLog
->Check(type
, nLevel
, pszModule
);
734 //////////////////////////////////////////////////////////////////////////
736 //////////////////////////////////////////////////////////////////////////
738 LogMediaColl::LogMediaColl()
742 LogMediaColl::~LogMediaColl()
746 void LogMediaColl::Add(const LogMediaPtr
& pMedia
)
750 CriticalSection::SyncLock
lock(m_cs
);
751 m_MediaColl
.push_back(pMedia
);
754 void LogMediaColl::Write(ELogMessageType type
, ELogMessageLevel nLevel
, LPCTSTR pszDate
, LPCTSTR pszTime
, LPCTSTR pszThreadId
, LPCTSTR pszThreadName
, LPCTSTR pszModule
, LPCTSTR pszMessage
)
756 CriticalSection::SyncLock
lock(m_cs
);
757 for (MediaColl::iterator it
= m_MediaColl
.begin(), end
= m_MediaColl
.end(); it
!= end
; ++it
)
758 (*it
)->Write(type
, nLevel
, pszDate
, pszTime
, pszThreadId
, pszThreadName
, pszModule
, pszMessage
);
761 bool LogMediaColl::Check(ELogMessageType type
, ELogMessageLevel nLevel
, LPCTSTR pszModule
)
763 CriticalSection::SyncLock
lock(m_cs
);
764 // Если хотя бы один лог пропускает, то и мы пропускаем.
765 for (MediaColl::iterator it
= m_MediaColl
.begin(), end
= m_MediaColl
.end(); it
!= end
; ++it
)
766 if ((*it
)->Check(type
, nLevel
, pszModule
))
771 //////////////////////////////////////////////////////////////////////////
773 //////////////////////////////////////////////////////////////////////////
775 FilterLogMedia::FilterLogMedia(const LogMediaPtr
& pMedia
)
780 FilterLogMedia::~FilterLogMedia()
784 void FilterLogMedia::AddFilter(FilterPtr pFilter
)
786 CriticalSection::SyncLock
lock(m_cs
);
787 m_FilterColl
.push_back(pFilter
);
790 void FilterLogMedia::Write(ELogMessageType type
, ELogMessageLevel nLevel
, LPCTSTR pszDate
, LPCTSTR pszTime
, LPCTSTR pszThreadId
, LPCTSTR pszThreadName
, LPCTSTR pszModule
, LPCTSTR pszMessage
)
795 CriticalSection::SyncLock
lock(m_cs
);
796 for (FilterColl::iterator it
= m_FilterColl
.begin(), end
= m_FilterColl
.end(); it
!= end
; ++it
)
797 if (!(*it
)->Check(type
, nLevel
, pszModule
))
800 m_pMedia
->Write(type
, nLevel
, pszDate
, pszTime
, pszThreadId
, pszThreadName
, pszModule
, pszMessage
);
803 bool FilterLogMedia::Check(ELogMessageType type
, ELogMessageLevel nLevel
, LPCTSTR pszModule
)
808 CriticalSection::SyncLock
lock(m_cs
);
809 for (FilterColl::iterator it
= m_FilterColl
.begin(), end
= m_FilterColl
.end(); it
!= end
; ++it
)
810 if (!(*it
)->Check(type
, nLevel
, pszModule
))
813 return m_pMedia
->Check(type
, nLevel
, pszModule
);
816 //////////////////////////////////////////////////////////////////////////
818 //////////////////////////////////////////////////////////////////////////
820 LogBase::LogBase(LogMediaPtr pMedia
, LPCTSTR pszModule
)
821 : m_szModule(pszModule
)
824 ASSERT(pszModule
!= NULL
);
831 template <typename T
, size_t nSize
>
832 class StackResizableBuf
835 void Clear() { if (data
!= loc_data
) delete[] data
; }
837 StackResizableBuf() { data
= loc_data
; size
= nSize
; }
838 ~StackResizableBuf() { Clear(); }
839 void Resize(size_t nNewSize
) { Clear(); data
= new T
[nNewSize
]; size
= nNewSize
; }
845 bool LogBase::IsFiltered(ELogMessageType type
, ELogMessageLevel nLevel
)
847 return !m_pMedia
|| !m_pMedia
->Check(type
, nLevel
, m_szModule
.c_str());
850 void LogBase::WriteVA(ELogMessageType type
,
851 ELogMessageLevel nLevel
,
854 va_list args
) throw()
856 if (IsFiltered(type
, nLevel
)) // не обрабатываем сообщение, если оно не попадает в лог
858 // 75% времени тратится на new и delete, поэтому первую попытку попробуем сделать без него.
859 StackResizableBuf
<TCHAR
, 16*1024> buf
;
863 pos
= _vsntprintf_s(buf
.data
, buf
.size
, buf
.size
- 1, pszMessage
, args
);
866 // BUG 16456 FIX, см. в конец WriteVAW почему
867 //if (buf.size >= 1024 * 256)
868 if (buf
.size
>= 1024 * 1024 * 10) //Increased limit for DumpServer
870 pos
= (int)buf
.size
- 1;
873 buf
.Resize(buf
.size
* 2);
880 TCHAR bufdate
[128], buftime
[128], bufthread
[128];
881 _stprintf_s(bufdate
, _T("%i-%02i-%02i"), st
.wYear
, st
.wMonth
, st
.wDay
);
882 _stprintf_s(buftime
, _T("%02i:%02i:%02i.%03d"), st
.wHour
, st
.wMinute
, st
.wSecond
, st
.wMilliseconds
);
883 _stprintf_s(bufthread
, _T("%4x"), GetCurrentThreadId());
884 m_pMedia
->Write(type
, nLevel
, bufdate
, buftime
, bufthread
, GetThreadName()
885 , pszModule
? pszModule
: m_szModule
.c_str(), buf
.data
);
889 void LogBase::WriteVAW(ELogMessageType type
,
890 ELogMessageLevel nLevel
,
893 va_list args
) throw()
895 #if defined(_UNICODE) || defined(UNICODE)
896 WriteVA(type
, nLevel
, pszModule
, pszMessage
, args
);
899 if (IsFiltered(type
, nLevel
)) // не обрабатываем сообщение, если оно не попадает в лог
901 // 75% времени тратится на new и delete, поэтому первую попытку попробуем сделать без него.
902 StackResizableBuf
<WCHAR
, 1024> buf
;
906 pos
= _vsnwprintf(buf
.data
, buf
.size
- 1, pszMessage
, args
);
909 // BUG 16456 FIX, см. в конец WriteVAW почему
910 if (buf
.size
>= 1024 * 256)
915 buf
.Resize(buf
.size
* 2);
920 LPTSTR pszStr
= static_cast<LPTSTR
>(_alloca(buf
.size
));
921 if (0 == WideCharToMultiByte(CP_ACP
, 0/*WC_DEFAULTCHAR*/, buf
.data
, pos
+ 1, pszStr
, buf
.size
, NULL
, NULL
))
923 _RPT1(_CRT_ERROR
, "Can't convert Unicode string (error #0x%08X)", GetLastError());
928 if (pszModule
== NULL
)
929 pszMod
= m_szModule
.c_str();
932 size_t nModuleLen
= wcslen(pszModule
) + 1;
933 LPTSTR pszModBuf
= static_cast<LPTSTR
>(_alloca(nModuleLen
));
934 if (0 == WideCharToMultiByte(CP_ACP
, 0/*WC_DEFAULTCHAR*/, pszModule
, nModuleLen
, pszModBuf
, nModuleLen
, NULL
, NULL
))
936 _RPT1(_CRT_ERROR
, "Can't convert Unicode string (error #0x%08X)", GetLastError());
944 TCHAR bufdate
[128], buftime
[128], bufthread
[128];
945 _stprintf(bufdate
, _T("%i-%02i-%02i"), st
.wYear
, st
.wMonth
, st
.wDay
);
946 _stprintf(buftime
, _T("%02i:%02i:%02i.%03d"), st
.wHour
, st
.wMinute
, st
.wSecond
, st
.wMilliseconds
);
947 _stprintf(bufthread
, _T("%03x"), GetCurrentThreadId());
948 m_pMedia
->Write(type
, nLevel
, bufdate
, buftime
, bufthread
, GetThreadName(), pszMod
, pszStr
);
952 _vsnwprintf спотыкается на строках с символом 0xFFFF,
953 возвращает -1 при любой длине буфера. Соответсвтвенно
954 буфер увеличивается (Resize) пока не хватит памяти,
955 а потом вызывается _vsnwprintf на NULL.
956 Решение: Т.к. _vsnwprintf, даже если нехватает буфера, начало заполняет,
957 то просто ограничим буфер 256кб (а 0 на конце и так ставим на всякий случай)
962 void WriteVAW(wchar_t* pszMessage, va_list args)
965 int n = _vsnwprintf(buf, 1000, pszMessage, args);
966 printf("Return %i\nBuf is: \"%ls\"", n, buf); // n будет -1, хотя буфера хватает !!!
968 void WriteW(wchar_t* pszMessage, ...)
971 va_start(ap, pszMessage);
972 WriteVAW(pszMessage, ap);
977 WriteW(L"%ls!", L"123\xffff");
983 //////////////////////////////////////////////////////////////////////////
985 //////////////////////////////////////////////////////////////////////////
987 LocalLog::LocalLog(const LogParam
& param
, LPCTSTR pszModule
)
988 : LogBase(param
.m_pMedia
, param
.m_pszModule
? param
.m_pszModule
: pszModule
)
992 LocalLog::LocalLog(LogMediaPtr pMedia
, LPCTSTR pszModule
)
993 : LogBase(pMedia
, pszModule
)
995 ASSERT(pszModule
!= NULL
);
998 LocalLog::LocalLog(const LogBase
& log
, LPCTSTR pszModule
)
999 : LogBase(log
.GetMedia(), pszModule
)
1003 LocalLog::~LocalLog()
1007 //////////////////////////////////////////////////////////////////////////
1009 //////////////////////////////////////////////////////////////////////////
1011 Log::Log(const LogParam
& param
, LPCTSTR pszModule
)
1012 : LogBase(param
.m_pMedia
, param
.m_pszModule
? param
.m_pszModule
: pszModule
)
1016 Log::Log(LogMediaPtr pMedia
, LPCTSTR pszModule
)
1017 : LogBase(pMedia
, pszModule
)
1021 Log::Log(const LogBase
& log
, LPCTSTR pszModule
)
1022 : LogBase(log
.GetMedia(), pszModule
)
1030 void Log::SetParams(LogMediaPtr pMedia
, LPCTSTR pszModule
)
1032 CriticalSection::SyncLock
lock(m_cs
);
1034 if (pszModule
!= NULL
)
1035 m_szModule
= pszModule
;
1038 void Log::WriteVA(ELogMessageType type
,
1039 ELogMessageLevel nLevel
,
1042 va_list args
) throw()
1044 CriticalSection::SyncLock
lock(m_cs
);
1045 LogBase::WriteVA(type
, nLevel
, pszModule
, pszMessage
, args
);
1048 void Log::WriteVAW(ELogMessageType type
,
1049 ELogMessageLevel nLevel
,
1052 va_list args
) throw()
1054 CriticalSection::SyncLock
lock(m_cs
);
1055 LogBase::WriteVAW(type
, nLevel
, pszModule
, pszMessage
, args
);
1058 //////////////////////////////////////////////////////////////////////////
1060 //////////////////////////////////////////////////////////////////////////
1062 FilterLog::~FilterLog()