mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-06-11 12:14:53 +08:00
[Bug Report Tool] Report event viewer logs (#11458)
This commit is contained in:
parent
208e1701d0
commit
0b13c4d6a5
6
.github/actions/spell-check/expect.txt
vendored
6
.github/actions/spell-check/expect.txt
vendored
@ -541,6 +541,7 @@ EUQ
|
|||||||
evenodd
|
evenodd
|
||||||
eventlog
|
eventlog
|
||||||
everytime
|
everytime
|
||||||
|
evt
|
||||||
EWXFORCE
|
EWXFORCE
|
||||||
EWXFORCEIFHUNG
|
EWXFORCEIFHUNG
|
||||||
EWXLOGOFF
|
EWXLOGOFF
|
||||||
@ -954,6 +955,7 @@ IVector
|
|||||||
IView
|
IView
|
||||||
IVirtual
|
IVirtual
|
||||||
IWeb
|
IWeb
|
||||||
|
IXml
|
||||||
ixx
|
ixx
|
||||||
IZone
|
IZone
|
||||||
IZoom
|
IZoom
|
||||||
@ -1785,6 +1787,7 @@ sln
|
|||||||
SMALLICON
|
SMALLICON
|
||||||
SMTO
|
SMTO
|
||||||
snd
|
snd
|
||||||
|
snwprintf
|
||||||
softline
|
softline
|
||||||
somil
|
somil
|
||||||
Soref
|
Soref
|
||||||
@ -1944,6 +1947,7 @@ THISCOMPONENT
|
|||||||
thre
|
thre
|
||||||
tif
|
tif
|
||||||
TILEDWINDOW
|
TILEDWINDOW
|
||||||
|
timediff
|
||||||
TIMERID
|
TIMERID
|
||||||
timeunion
|
timeunion
|
||||||
timeutil
|
timeutil
|
||||||
@ -2127,6 +2131,7 @@ webpack
|
|||||||
webpage
|
webpage
|
||||||
website
|
website
|
||||||
wekyb
|
wekyb
|
||||||
|
Wevtapi
|
||||||
Whichdoes
|
Whichdoes
|
||||||
whitespaces
|
whitespaces
|
||||||
WIC
|
WIC
|
||||||
@ -2156,6 +2161,7 @@ windowwalker
|
|||||||
winerror
|
winerror
|
||||||
WINEVENT
|
WINEVENT
|
||||||
winexe
|
winexe
|
||||||
|
winevt
|
||||||
winforms
|
winforms
|
||||||
winfx
|
winfx
|
||||||
winget
|
winget
|
||||||
|
@ -30,15 +30,18 @@
|
|||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Console</SubSystem>
|
<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>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="..\..\..\deps\cziplib\src\zip.c">
|
<ClCompile Include="..\..\..\deps\cziplib\src\zip.c">
|
||||||
<WarningLevel>TurnOffAllWarnings</WarningLevel>
|
<WarningLevel>TurnOffAllWarnings</WarningLevel>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="EventViewer.cpp" />
|
||||||
<ClCompile Include="ReportMonitorInfo.cpp" />
|
<ClCompile Include="ReportMonitorInfo.cpp" />
|
||||||
<ClCompile Include="Main.cpp" />
|
<ClCompile Include="Main.cpp" />
|
||||||
<ClCompile Include="RegistryUtils.cpp" />
|
<ClCompile Include="RegistryUtils.cpp" />
|
||||||
|
<ClCompile Include="XmlDocumentEx.cpp" />
|
||||||
<ClCompile Include="ZipTools\ZipFolder.cpp" />
|
<ClCompile Include="ZipTools\ZipFolder.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@ -52,9 +55,11 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\..\..\deps\cziplib\src\miniz.h" />
|
<ClInclude Include="..\..\..\deps\cziplib\src\miniz.h" />
|
||||||
<ClInclude Include="..\..\..\deps\cziplib\src\zip.h" />
|
<ClInclude Include="..\..\..\deps\cziplib\src\zip.h" />
|
||||||
|
<ClInclude Include="EventViewer.h" />
|
||||||
<ClInclude Include="ReportMonitorInfo.h" />
|
<ClInclude Include="ReportMonitorInfo.h" />
|
||||||
<ClInclude Include="..\..\..\common\utils\json.h" />
|
<ClInclude Include="..\..\..\common\utils\json.h" />
|
||||||
<ClInclude Include="RegistryUtils.h" />
|
<ClInclude Include="RegistryUtils.h" />
|
||||||
|
<ClInclude Include="XmlDocumentEx.h" />
|
||||||
<ClInclude Include="ZipTools\ZipFolder.h" />
|
<ClInclude Include="ZipTools\ZipFolder.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
<ClCompile Include="..\..\..\deps\cziplib\src\zip.c" />
|
<ClCompile Include="..\..\..\deps\cziplib\src\zip.c" />
|
||||||
<ClCompile Include="ReportMonitorInfo.cpp" />
|
<ClCompile Include="ReportMonitorInfo.cpp" />
|
||||||
<ClCompile Include="RegistryUtils.cpp" />
|
<ClCompile Include="RegistryUtils.cpp" />
|
||||||
|
<ClCompile Include="EventViewer.cpp" />
|
||||||
|
<ClCompile Include="XmlDocumentEx.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Filter Include="ZipTools">
|
<Filter Include="ZipTools">
|
||||||
@ -26,5 +28,7 @@
|
|||||||
<ClInclude Include="..\..\..\deps\cziplib\src\zip.h" />
|
<ClInclude Include="..\..\..\deps\cziplib\src\zip.h" />
|
||||||
<ClInclude Include="ReportMonitorInfo.h" />
|
<ClInclude Include="ReportMonitorInfo.h" />
|
||||||
<ClInclude Include="RegistryUtils.h" />
|
<ClInclude Include="RegistryUtils.h" />
|
||||||
|
<ClInclude Include="EventViewer.h" />
|
||||||
|
<ClInclude Include="XmlDocumentEx.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
189
tools/BugReportTool/BugReportTool/EventViewer.cpp
Normal file
189
tools/BugReportTool/BugReportTool/EventViewer.cpp
Normal file
@ -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();
|
||||||
|
}
|
||||||
|
}
|
7
tools/BugReportTool/BugReportTool/EventViewer.h
Normal file
7
tools/BugReportTool/BugReportTool/EventViewer.h
Normal file
@ -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 "ReportMonitorInfo.h"
|
||||||
#include "RegistryUtils.h"
|
#include "RegistryUtils.h"
|
||||||
|
#include "EventViewer.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace std::filesystem;
|
using namespace std::filesystem;
|
||||||
using namespace winrt::Windows::Data::Json;
|
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
|
// Write compatibility tab info to the temporary folder
|
||||||
ReportCompatibilityTab(tmpDir);
|
ReportCompatibilityTab(tmpDir);
|
||||||
|
|
||||||
|
// Write event viewer logs info to the temporary folder
|
||||||
|
EventViewer::ReportEventViewerInfo(tmpDir);
|
||||||
|
|
||||||
ReportBootstrapperLog(tmpDir);
|
ReportBootstrapperLog(tmpDir);
|
||||||
|
|
||||||
// Zip folder
|
// Zip folder
|
||||||
|
56
tools/BugReportTool/BugReportTool/XmlDocumentEx.cpp
Normal file
56
tools/BugReportTool/BugReportTool/XmlDocumentEx.cpp
Normal file
@ -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">";
|
||||||
|
}
|
13
tools/BugReportTool/BugReportTool/XmlDocumentEx.h
Normal file
13
tools/BugReportTool/BugReportTool/XmlDocumentEx.h
Normal file
@ -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();
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user