[Bug Report Tool] Report event viewer logs (#11458)
This commit is contained in:
Родитель
208e1701d0
Коммит
0b13c4d6a5
|
@ -541,6 +541,7 @@ EUQ
|
|||
evenodd
|
||||
eventlog
|
||||
everytime
|
||||
evt
|
||||
EWXFORCE
|
||||
EWXFORCEIFHUNG
|
||||
EWXLOGOFF
|
||||
|
@ -954,6 +955,7 @@ IVector
|
|||
IView
|
||||
IVirtual
|
||||
IWeb
|
||||
IXml
|
||||
ixx
|
||||
IZone
|
||||
IZoom
|
||||
|
@ -1785,6 +1787,7 @@ sln
|
|||
SMALLICON
|
||||
SMTO
|
||||
snd
|
||||
snwprintf
|
||||
softline
|
||||
somil
|
||||
Soref
|
||||
|
@ -1944,6 +1947,7 @@ THISCOMPONENT
|
|||
thre
|
||||
tif
|
||||
TILEDWINDOW
|
||||
timediff
|
||||
TIMERID
|
||||
timeunion
|
||||
timeutil
|
||||
|
@ -2127,6 +2131,7 @@ webpack
|
|||
webpage
|
||||
website
|
||||
wekyb
|
||||
Wevtapi
|
||||
Whichdoes
|
||||
whitespaces
|
||||
WIC
|
||||
|
@ -2156,6 +2161,7 @@ windowwalker
|
|||
winerror
|
||||
WINEVENT
|
||||
winexe
|
||||
winevt
|
||||
winforms
|
||||
winfx
|
||||
winget
|
||||
|
|
|
@ -30,15 +30,18 @@
|
|||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<AdditionalDependencies>Wevtapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\..\deps\cziplib\src\zip.c">
|
||||
<WarningLevel>TurnOffAllWarnings</WarningLevel>
|
||||
</ClCompile>
|
||||
<ClCompile Include="EventViewer.cpp" />
|
||||
<ClCompile Include="ReportMonitorInfo.cpp" />
|
||||
<ClCompile Include="Main.cpp" />
|
||||
<ClCompile Include="RegistryUtils.cpp" />
|
||||
<ClCompile Include="XmlDocumentEx.cpp" />
|
||||
<ClCompile Include="ZipTools\ZipFolder.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -52,9 +55,11 @@
|
|||
<ItemGroup>
|
||||
<ClInclude Include="..\..\..\deps\cziplib\src\miniz.h" />
|
||||
<ClInclude Include="..\..\..\deps\cziplib\src\zip.h" />
|
||||
<ClInclude Include="EventViewer.h" />
|
||||
<ClInclude Include="ReportMonitorInfo.h" />
|
||||
<ClInclude Include="..\..\..\common\utils\json.h" />
|
||||
<ClInclude Include="RegistryUtils.h" />
|
||||
<ClInclude Include="XmlDocumentEx.h" />
|
||||
<ClInclude Include="ZipTools\ZipFolder.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
<ClCompile Include="..\..\..\deps\cziplib\src\zip.c" />
|
||||
<ClCompile Include="ReportMonitorInfo.cpp" />
|
||||
<ClCompile Include="RegistryUtils.cpp" />
|
||||
<ClCompile Include="EventViewer.cpp" />
|
||||
<ClCompile Include="XmlDocumentEx.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="ZipTools">
|
||||
|
@ -26,5 +28,7 @@
|
|||
<ClInclude Include="..\..\..\deps\cziplib\src\zip.h" />
|
||||
<ClInclude Include="ReportMonitorInfo.h" />
|
||||
<ClInclude Include="RegistryUtils.h" />
|
||||
<ClInclude Include="EventViewer.h" />
|
||||
<ClInclude Include="XmlDocumentEx.h" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,189 @@
|
|||
#include "EventViewer.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <sddl.h>
|
||||
#include <stdio.h>
|
||||
#include <winevt.h>
|
||||
#include <fstream>
|
||||
#include <common/utils/winapi_error.h>
|
||||
|
||||
#include "XmlDocumentEx.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
std::vector<std::wstring> processes =
|
||||
{
|
||||
L"PowerToys.exe",
|
||||
L"ColorPickerUI.exe",
|
||||
L"PowerToys.Espresso.exe"
|
||||
L"FancyZonesEditor.exe",
|
||||
L"PowerToys.KeyboardManagerEngine.exe",
|
||||
L"PowerToys.KeyboardManagerEditor.exe",
|
||||
L"PowerLauncher.exe",
|
||||
L"PowerToys.ShortcutGuide.exe"
|
||||
};
|
||||
|
||||
// Batch size for number of events queried at once
|
||||
constexpr int BATCH_SIZE = 50;
|
||||
|
||||
class EventViewerReporter
|
||||
{
|
||||
private:
|
||||
// Report last 30 days
|
||||
const long long PERIOD = 10 * 24 * 3600ll * 1000;
|
||||
|
||||
const std::wstring QUERY = L"<QueryList>" \
|
||||
L" <Query Id='0'>" \
|
||||
L" <Select Path='Application'>" \
|
||||
L" *[System[TimeCreated[timediff(@SystemTime)<%I64u]]] " \
|
||||
L" and *[EventData[Data and (Data='%s')]]" \
|
||||
L" </Select>" \
|
||||
L" </Query>" \
|
||||
L"</QueryList>";
|
||||
|
||||
std::wstring GetQuery(std::wstring processName)
|
||||
{
|
||||
wchar_t buff[1000];
|
||||
memset(buff, 0, sizeof(buff));
|
||||
_snwprintf_s(buff, sizeof(buff), QUERY.c_str(), PERIOD, processName.c_str());
|
||||
return buff;
|
||||
}
|
||||
|
||||
std::wofstream report;
|
||||
EVT_HANDLE hResults;
|
||||
|
||||
void PrintEvent(EVT_HANDLE hEvent)
|
||||
{
|
||||
DWORD status = ERROR_SUCCESS;
|
||||
DWORD dwBufferSize = 0;
|
||||
DWORD dwBufferUsed = 0;
|
||||
DWORD dwPropertyCount = 0;
|
||||
LPWSTR pRenderedContent = NULL;
|
||||
|
||||
// The EvtRenderEventXml flag tells EvtRender to render the event as an XML string.
|
||||
if (!EvtRender(NULL, hEvent, EvtRenderEventXml, dwBufferSize, pRenderedContent, &dwBufferUsed, &dwPropertyCount))
|
||||
{
|
||||
if (ERROR_INSUFFICIENT_BUFFER == (status = GetLastError()))
|
||||
{
|
||||
dwBufferSize = dwBufferUsed;
|
||||
pRenderedContent = (LPWSTR)malloc(dwBufferSize);
|
||||
if (pRenderedContent)
|
||||
{
|
||||
EvtRender(NULL, hEvent, EvtRenderEventXml, dwBufferSize, pRenderedContent, &dwBufferUsed, &dwPropertyCount);
|
||||
}
|
||||
}
|
||||
|
||||
if (ERROR_SUCCESS != (status = GetLastError()))
|
||||
{
|
||||
report << std::endl << L"EvtRender failed with " << get_last_error_or_default(GetLastError()) << std::endl << std::endl;
|
||||
if (pRenderedContent)
|
||||
{
|
||||
free(pRenderedContent);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
XmlDocumentEx doc;
|
||||
doc.LoadXml(pRenderedContent);
|
||||
std::wstring formattedXml = L"";
|
||||
try
|
||||
{
|
||||
formattedXml = doc.GetFormatedXml();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
formattedXml = pRenderedContent;
|
||||
}
|
||||
|
||||
report << std::endl << formattedXml << std::endl;
|
||||
if (pRenderedContent)
|
||||
{
|
||||
free(pRenderedContent);
|
||||
}
|
||||
}
|
||||
|
||||
// Enumerate all the events in the result set.
|
||||
void PrintResults(EVT_HANDLE hResults)
|
||||
{
|
||||
DWORD status = ERROR_SUCCESS;
|
||||
EVT_HANDLE hEvents[BATCH_SIZE];
|
||||
DWORD dwReturned = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
// Get a block of events from the result set.
|
||||
if (!EvtNext(hResults, BATCH_SIZE, hEvents, INFINITE, 0, &dwReturned))
|
||||
{
|
||||
if (ERROR_NO_MORE_ITEMS != (status = GetLastError()))
|
||||
{
|
||||
report << L"EvtNext failed with " << status << std::endl;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// For each event, call the PrintEvent function which renders the
|
||||
// event for display. PrintEvent is shown in RenderingEvents.
|
||||
for (DWORD i = 0; i < dwReturned; i++)
|
||||
{
|
||||
PrintEvent(hEvents[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for (DWORD i = 0; i < dwReturned; i++)
|
||||
{
|
||||
if (nullptr != hEvents[i])
|
||||
EvtClose(hEvents[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
EventViewerReporter(const std::filesystem::path& tmpDir, std::wstring processName)
|
||||
{
|
||||
auto query = GetQuery(processName);
|
||||
auto reportPath = tmpDir;
|
||||
reportPath.append(L"EventViewer-" + processName + L".xml");
|
||||
report = std::wofstream(reportPath);
|
||||
|
||||
hResults = EvtQuery(NULL, NULL, GetQuery(processName).c_str(), EvtQueryChannelPath);
|
||||
if (NULL == hResults)
|
||||
{
|
||||
report << "Failed to report info for " << processName << ". " << get_last_error_or_default(GetLastError()) << std::endl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
~EventViewerReporter()
|
||||
{
|
||||
if (hResults)
|
||||
{
|
||||
EvtClose(hResults);
|
||||
hResults = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Report()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (hResults)
|
||||
{
|
||||
PrintResults(hResults);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
report << "Failed to report info" << std::endl;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void EventViewer::ReportEventViewerInfo(const std::filesystem::path& tmpDir)
|
||||
{
|
||||
for (auto& process : processes)
|
||||
{
|
||||
EventViewerReporter(tmpDir, process).Report();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
#include <filesystem>
|
||||
|
||||
namespace EventViewer
|
||||
{
|
||||
void ReportEventViewerInfo(const std::filesystem::path& tmpDir);
|
||||
}
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
#include "ReportMonitorInfo.h"
|
||||
#include "RegistryUtils.h"
|
||||
#include "EventViewer.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace std::filesystem;
|
||||
using namespace winrt::Windows::Data::Json;
|
||||
|
@ -331,6 +333,9 @@ int wmain(int argc, wchar_t* argv[], wchar_t*)
|
|||
// Write compatibility tab info to the temporary folder
|
||||
ReportCompatibilityTab(tmpDir);
|
||||
|
||||
// Write event viewer logs info to the temporary folder
|
||||
EventViewer::ReportEventViewerInfo(tmpDir);
|
||||
|
||||
ReportBootstrapperLog(tmpDir);
|
||||
|
||||
// Zip folder
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
#include "XmlDocumentEx.h"
|
||||
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
|
||||
std::wstring XmlDocumentEx::GetFormatedXml()
|
||||
{
|
||||
stream.clear();
|
||||
Print(FirstChild(), 0);
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
void XmlDocumentEx::Print(winrt::Windows::Data::Xml::Dom::IXmlNode node, int indentation)
|
||||
{
|
||||
for (int i = 0; i < indentation; i++)
|
||||
{
|
||||
stream << " ";
|
||||
}
|
||||
|
||||
PrintTagWithAttributes(node);
|
||||
if (!node.HasChildNodes())
|
||||
{
|
||||
stream << L"<\\" << node.NodeName().c_str() << ">" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.ChildNodes().Size() == 1 && !node.FirstChild().HasChildNodes())
|
||||
{
|
||||
stream << node.InnerText().c_str() << L"<\\" << node.NodeName().c_str() << ">" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
stream << std::endl;
|
||||
auto child = node.FirstChild();
|
||||
do
|
||||
{
|
||||
Print(child, indentation + 2);
|
||||
} while (child = child.NextSibling());
|
||||
|
||||
for (int i = 0; i < indentation; i++)
|
||||
{
|
||||
stream << " ";
|
||||
}
|
||||
stream << L"<\\" << node.NodeName().c_str() << ">" << std::endl;
|
||||
}
|
||||
|
||||
void XmlDocumentEx::PrintTagWithAttributes(winrt::Windows::Data::Xml::Dom::IXmlNode node)
|
||||
{
|
||||
stream << L"<" << node.NodeName().c_str();
|
||||
for (int i = 0; i < (int)node.Attributes().Size(); i++)
|
||||
{
|
||||
auto attr = node.Attributes().GetAt(i);
|
||||
stream << L" " << attr.NodeName().c_str() << L"='" << attr.InnerText().c_str() << L"'";
|
||||
}
|
||||
|
||||
stream << L">";
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
#pragma once
|
||||
#include <winrt/Windows.Data.Xml.Dom.h>
|
||||
|
||||
class XmlDocumentEx : public winrt::Windows::Data::Xml::Dom::XmlDocument
|
||||
{
|
||||
private:
|
||||
std::wstringstream stream;
|
||||
void Print(winrt::Windows::Data::Xml::Dom::IXmlNode node, int indentation);
|
||||
void PrintTagWithAttributes(winrt::Windows::Data::Xml::Dom::IXmlNode node);
|
||||
|
||||
public:
|
||||
std::wstring GetFormatedXml();
|
||||
};
|
Загрузка…
Ссылка в новой задаче