a13ccfd0f5
Generated by https://github.com/jsoref/spelling `f`; to maintain your repo, please consider `fchurn` I generally try to ignore upstream bits. I've accidentally included some items from the `deps/` directory. I expect someone will give me a list of items to drop, I'm happy to drop whole files/directories, or to split the PR into multiple items (E.g. comments/locals/public). Closes #4294
590 lines
36 KiB
C++
590 lines
36 KiB
C++
// Copyright (c) Microsoft Corporation.
|
|
// Licensed under the MIT license.
|
|
|
|
#include "precomp.h"
|
|
|
|
#include <Intsafe.h>
|
|
#include "Shlwapi.h"
|
|
#include "telemetry.hpp"
|
|
#include <time.h>
|
|
|
|
#include "history.h"
|
|
|
|
#include "..\interactivity\inc\ServiceLocator.hpp"
|
|
|
|
TRACELOGGING_DEFINE_PROVIDER(g_hConhostV2EventTraceProvider,
|
|
"Microsoft.Windows.Console.Host",
|
|
// {fe1ff234-1f09-50a8-d38d-c44fab43e818}
|
|
(0xfe1ff234, 0x1f09, 0x50a8, 0xd3, 0x8d, 0xc4, 0x4f, 0xab, 0x43, 0xe8, 0x18),
|
|
TraceLoggingOptionMicrosoftTelemetry());
|
|
#pragma warning(push)
|
|
// Disable 4351 so we can initialize the arrays to 0 without a warning.
|
|
#pragma warning(disable : 4351)
|
|
Telemetry::Telemetry() :
|
|
_fpFindStringLengthAverage(0),
|
|
_fpDirectionDownAverage(0),
|
|
_fpMatchCaseAverage(0),
|
|
_uiFindNextClickedTotal(0),
|
|
_uiColorSelectionUsed(0),
|
|
_tStartedAt(0),
|
|
_wchProcessFileNames(),
|
|
// Start at position 1, since the first 2 bytes contain the number of strings.
|
|
_iProcessFileNamesNext(1),
|
|
_iProcessConnectedCurrently(SIZE_MAX),
|
|
_rgiProcessFileNameIndex(),
|
|
_rguiProcessFileNamesCount(),
|
|
_rgiAlphabeticalIndex(),
|
|
_rguiProcessFileNamesCodesCount(),
|
|
_rguiProcessFileNamesFailedCodesCount(),
|
|
_rguiProcessFileNamesFailedOutsideCodesCount(),
|
|
_rguiTimesApiUsed(),
|
|
_rguiTimesApiUsedAnsi(),
|
|
_uiNumberProcessFileNames(0),
|
|
_fBashUsed(false),
|
|
_fKeyboardTextEditingUsed(false),
|
|
_fKeyboardTextSelectionUsed(false),
|
|
_fUserInteractiveForTelemetry(false),
|
|
_fCtrlPgUpPgDnUsed(false),
|
|
_uiCtrlShiftCProcUsed(0),
|
|
_uiCtrlShiftCRawUsed(0),
|
|
_uiCtrlShiftVProcUsed(0),
|
|
_uiCtrlShiftVRawUsed(0),
|
|
_uiQuickEditCopyProcUsed(0),
|
|
_uiQuickEditCopyRawUsed(0),
|
|
_uiQuickEditPasteProcUsed(0),
|
|
_uiQuickEditPasteRawUsed(0)
|
|
{
|
|
time(&_tStartedAt);
|
|
TraceLoggingRegister(g_hConhostV2EventTraceProvider);
|
|
TraceLoggingWriteStart(_activity, "ActivityStart");
|
|
// initialize wil tracelogging
|
|
wil::SetResultLoggingCallback(&Tracing::TraceFailure);
|
|
}
|
|
#pragma warning(pop)
|
|
|
|
Telemetry::~Telemetry()
|
|
{
|
|
TraceLoggingWriteStop(_activity, "ActivityStop");
|
|
TraceLoggingUnregister(g_hConhostV2EventTraceProvider);
|
|
}
|
|
|
|
void Telemetry::SetUserInteractive()
|
|
{
|
|
_fUserInteractiveForTelemetry = true;
|
|
}
|
|
|
|
void Telemetry::SetCtrlPgUpPgDnUsed()
|
|
{
|
|
_fCtrlPgUpPgDnUsed = true;
|
|
SetUserInteractive();
|
|
}
|
|
|
|
void Telemetry::LogCtrlShiftCProcUsed()
|
|
{
|
|
_uiCtrlShiftCProcUsed++;
|
|
SetUserInteractive();
|
|
}
|
|
|
|
void Telemetry::LogCtrlShiftCRawUsed()
|
|
{
|
|
_uiCtrlShiftCRawUsed++;
|
|
SetUserInteractive();
|
|
}
|
|
|
|
void Telemetry::LogCtrlShiftVProcUsed()
|
|
{
|
|
_uiCtrlShiftVProcUsed++;
|
|
SetUserInteractive();
|
|
}
|
|
|
|
void Telemetry::LogCtrlShiftVRawUsed()
|
|
{
|
|
_uiCtrlShiftVRawUsed++;
|
|
SetUserInteractive();
|
|
}
|
|
|
|
void Telemetry::LogQuickEditCopyProcUsed()
|
|
{
|
|
_uiQuickEditCopyProcUsed++;
|
|
SetUserInteractive();
|
|
}
|
|
|
|
void Telemetry::LogQuickEditCopyRawUsed()
|
|
{
|
|
_uiQuickEditCopyRawUsed++;
|
|
SetUserInteractive();
|
|
}
|
|
|
|
void Telemetry::LogQuickEditPasteProcUsed()
|
|
{
|
|
_uiQuickEditPasteProcUsed++;
|
|
SetUserInteractive();
|
|
}
|
|
|
|
void Telemetry::LogQuickEditPasteRawUsed()
|
|
{
|
|
_uiQuickEditPasteRawUsed++;
|
|
SetUserInteractive();
|
|
}
|
|
|
|
// Log usage of the Color Selection option.
|
|
void Telemetry::LogColorSelectionUsed()
|
|
{
|
|
_uiColorSelectionUsed++;
|
|
SetUserInteractive();
|
|
}
|
|
|
|
void Telemetry::SetWindowSizeChanged()
|
|
{
|
|
SetUserInteractive();
|
|
}
|
|
|
|
void Telemetry::SetContextMenuUsed()
|
|
{
|
|
SetUserInteractive();
|
|
}
|
|
|
|
void Telemetry::SetKeyboardTextSelectionUsed()
|
|
{
|
|
_fKeyboardTextSelectionUsed = true;
|
|
SetUserInteractive();
|
|
}
|
|
|
|
void Telemetry::SetKeyboardTextEditingUsed()
|
|
{
|
|
_fKeyboardTextEditingUsed = true;
|
|
SetUserInteractive();
|
|
}
|
|
|
|
// Log an API call was used.
|
|
void Telemetry::LogApiCall(const ApiCall api, const BOOLEAN fUnicode)
|
|
{
|
|
// Initially we thought about passing over a string (ex. "XYZ") and use a dictionary data type to hold the counts.
|
|
// However we would have to search through the dictionary every time we called this method, so we decided
|
|
// to use an array which has very quick access times.
|
|
// The downside is we have to create an enum type, and then convert them to strings when we finally
|
|
// send out the telemetry, but the upside is we should have very good performance.
|
|
if (fUnicode)
|
|
{
|
|
_rguiTimesApiUsed[api]++;
|
|
}
|
|
else
|
|
{
|
|
_rguiTimesApiUsedAnsi[api]++;
|
|
}
|
|
}
|
|
|
|
// Log an API call was used.
|
|
void Telemetry::LogApiCall(const ApiCall api)
|
|
{
|
|
_rguiTimesApiUsed[api]++;
|
|
}
|
|
|
|
// Log usage of the Find Dialog.
|
|
void Telemetry::LogFindDialogNextClicked(const unsigned int uiStringLength, const bool fDirectionDown, const bool fMatchCase)
|
|
{
|
|
// Don't send telemetry for every time it's used, as this will help reduce the load on our servers.
|
|
// Instead just create a running average of the string length, the direction down radio
|
|
// button, and match case checkbox.
|
|
_fpFindStringLengthAverage = ((_fpFindStringLengthAverage * _uiFindNextClickedTotal + uiStringLength) / (_uiFindNextClickedTotal + 1));
|
|
_fpDirectionDownAverage = ((_fpDirectionDownAverage * _uiFindNextClickedTotal + (fDirectionDown ? 1 : 0)) / (_uiFindNextClickedTotal + 1));
|
|
_fpMatchCaseAverage = ((_fpMatchCaseAverage * _uiFindNextClickedTotal + (fMatchCase ? 1 : 0)) / (_uiFindNextClickedTotal + 1));
|
|
_uiFindNextClickedTotal++;
|
|
}
|
|
|
|
// Find dialog was closed, now send out the telemetry.
|
|
void Telemetry::FindDialogClosed()
|
|
{
|
|
// clang-format off
|
|
#pragma prefast(suppress: __WARNING_NONCONST_LOCAL, "Activity can't be const, since it's set to a random value on startup.")
|
|
// clang-format on
|
|
TraceLoggingWriteTagged(_activity,
|
|
"FindDialogUsed",
|
|
TraceLoggingValue(_fpFindStringLengthAverage, "StringLengthAverage"),
|
|
TraceLoggingValue(_fpDirectionDownAverage, "DirectionDownAverage"),
|
|
TraceLoggingValue(_fpMatchCaseAverage, "MatchCaseAverage"),
|
|
TraceLoggingValue(_uiFindNextClickedTotal, "FindNextButtonClickedTotal"),
|
|
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
|
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
|
|
|
// Get ready for the next time the dialog is used.
|
|
_fpFindStringLengthAverage = 0;
|
|
_fpDirectionDownAverage = 0;
|
|
_fpMatchCaseAverage = 0;
|
|
_uiFindNextClickedTotal = 0;
|
|
}
|
|
|
|
// Total up all the used VT100 codes and assign them to the last process that was attached.
|
|
// We originally did this when each process disconnected, but some processes don't
|
|
// disconnect when the conhost process exits. So we have to remember the last process that connected.
|
|
void Telemetry::TotalCodesForPreviousProcess()
|
|
{
|
|
using namespace Microsoft::Console::VirtualTerminal;
|
|
// Get the values even if we aren't recording the previously connected process, since we want to reset them to 0.
|
|
unsigned int _uiTimesUsedCurrent = TermTelemetry::Instance().GetAndResetTimesUsedCurrent();
|
|
unsigned int _uiTimesFailedCurrent = TermTelemetry::Instance().GetAndResetTimesFailedCurrent();
|
|
unsigned int _uiTimesFailedOutsideRangeCurrent = TermTelemetry::Instance().GetAndResetTimesFailedOutsideRangeCurrent();
|
|
|
|
if (_iProcessConnectedCurrently < c_iMaxProcessesConnected)
|
|
{
|
|
_rguiProcessFileNamesCodesCount[_iProcessConnectedCurrently] += _uiTimesUsedCurrent;
|
|
_rguiProcessFileNamesFailedCodesCount[_iProcessConnectedCurrently] += _uiTimesFailedCurrent;
|
|
_rguiProcessFileNamesFailedOutsideCodesCount[_iProcessConnectedCurrently] += _uiTimesFailedOutsideRangeCurrent;
|
|
|
|
// Don't total any more process connected telemetry, unless a new processes attaches that we want to gather.
|
|
_iProcessConnectedCurrently = SIZE_MAX;
|
|
}
|
|
}
|
|
|
|
// Tries to find the process name amongst our previous process names by doing a binary search.
|
|
// The main difference between this and the standard bsearch library call, is that if this
|
|
// can't find the string, it returns the position the new string should be inserted at. This saves
|
|
// us from having an additional search through the array, and improves performance.
|
|
bool Telemetry::FindProcessName(const WCHAR* pszProcessName, _Out_ size_t* iPosition) const
|
|
{
|
|
int iMin = 0;
|
|
int iMid = 0;
|
|
int iMax = _uiNumberProcessFileNames - 1;
|
|
int result = 0;
|
|
|
|
while (iMin <= iMax)
|
|
{
|
|
iMid = (iMax + iMin) / 2;
|
|
// Use a case-insensitive comparison. We do support running Linux binaries now, but we haven't seen them connect
|
|
// as processes, and even if they did, we don't care about the difference in running emacs vs. Emacs.
|
|
result = _wcsnicmp(pszProcessName, _wchProcessFileNames + _rgiProcessFileNameIndex[_rgiAlphabeticalIndex[iMid]], MAX_PATH);
|
|
if (result < 0)
|
|
{
|
|
iMax = iMid - 1;
|
|
}
|
|
else if (result > 0)
|
|
{
|
|
iMin = iMid + 1;
|
|
}
|
|
else
|
|
{
|
|
// Found the string.
|
|
*iPosition = iMid;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Let them know which position to insert the string at.
|
|
*iPosition = (result > 0) ? iMid + 1 : iMid;
|
|
return false;
|
|
}
|
|
|
|
// Log a process name and number of times it has connected to the console in preparation to send through telemetry.
|
|
// We were considering sending out a log of telemetry when each process connects, but then the telemetry can get
|
|
// complicated and spammy, especially since command line utilities like help.exe and where.exe are considered processes.
|
|
// Don't send telemetry for every time a process connects, as this will help reduce the load on our servers.
|
|
// Just save the name and count, and send the telemetry before the console exits.
|
|
void Telemetry::LogProcessConnected(const HANDLE hProcess)
|
|
{
|
|
// This is a bit of processing, so don't do it for the 95% of machines that aren't being sampled.
|
|
if (TraceLoggingProviderEnabled(g_hConhostV2EventTraceProvider, 0, MICROSOFT_KEYWORD_MEASURES))
|
|
{
|
|
TotalCodesForPreviousProcess();
|
|
|
|
// Don't initialize wszFilePathAndName, QueryFullProcessImageName does that for us. Use QueryFullProcessImageName instead of
|
|
// GetProcessImageFileName because we need the path to begin with a drive letter and not a device name.
|
|
WCHAR wszFilePathAndName[MAX_PATH];
|
|
DWORD dwSize = ARRAYSIZE(wszFilePathAndName);
|
|
if (QueryFullProcessImageName(hProcess, 0, wszFilePathAndName, &dwSize))
|
|
{
|
|
// Stripping out the path also helps with PII issues in case they launched the program
|
|
// from a path containing their username.
|
|
PWSTR pwszFileName = PathFindFileName(wszFilePathAndName);
|
|
|
|
size_t iFileName;
|
|
if (FindProcessName(pwszFileName, &iFileName))
|
|
{
|
|
// We already logged this process name, so just increment the count.
|
|
_iProcessConnectedCurrently = _rgiAlphabeticalIndex[iFileName];
|
|
_rguiProcessFileNamesCount[_iProcessConnectedCurrently]++;
|
|
}
|
|
else if ((_uiNumberProcessFileNames < ARRAYSIZE(_rguiProcessFileNamesCount)) &&
|
|
(_iProcessFileNamesNext < ARRAYSIZE(_wchProcessFileNames) - 10))
|
|
{
|
|
// Check if the MS released bash was used. MS bash is installed under windows\system32, and it's possible somebody else
|
|
// could be installing their bash into that directory, but not likely. If the user first runs a non-MS bash,
|
|
// and then runs MS bash, we won't detect the MS bash as running, but it's an acceptable compromise.
|
|
if (!_fBashUsed && !_wcsnicmp(c_pwszBashExeName, pwszFileName, MAX_PATH))
|
|
{
|
|
// We could have gotten the system directory once when this class starts, but we'd have to hold the memory for it
|
|
// plus we're not sure we'd ever need it, so just get it when we know we're running bash.exe.
|
|
WCHAR wszSystemDirectory[MAX_PATH] = L"";
|
|
if (GetSystemDirectory(wszSystemDirectory, ARRAYSIZE(wszSystemDirectory)))
|
|
{
|
|
_fBashUsed = (PathIsSameRoot(wszFilePathAndName, wszSystemDirectory) == TRUE);
|
|
}
|
|
}
|
|
|
|
// In order to send out a dynamic array of strings through telemetry, we have to pack the strings into a single WCHAR array.
|
|
// There currently aren't any helper functions for this, and we have to pack it manually.
|
|
// To understand the format of the single string, consult the documentation in the traceloggingprovider.h file.
|
|
if (SUCCEEDED(StringCchCopyW(_wchProcessFileNames + _iProcessFileNamesNext, ARRAYSIZE(_wchProcessFileNames) - _iProcessFileNamesNext - 1, pwszFileName)))
|
|
{
|
|
// As each FileName comes in, it's appended to the end. However to improve searching speed, we have an array of indexes
|
|
// that is alphabetically sorted. We could call qsort, but that would be a waste in performance since we're just adding one string
|
|
// at a time and we always keep the array sorted, so just shift everything over one.
|
|
for (size_t n = _uiNumberProcessFileNames; n > iFileName; n--)
|
|
{
|
|
_rgiAlphabeticalIndex[n] = _rgiAlphabeticalIndex[n - 1];
|
|
}
|
|
|
|
// Now point to the string, and set the count to 1.
|
|
_rgiAlphabeticalIndex[iFileName] = _uiNumberProcessFileNames;
|
|
_rgiProcessFileNameIndex[_uiNumberProcessFileNames] = _iProcessFileNamesNext;
|
|
_rguiProcessFileNamesCount[_uiNumberProcessFileNames] = 1;
|
|
_iProcessFileNamesNext += wcslen(pwszFileName) + 1;
|
|
_iProcessConnectedCurrently = _uiNumberProcessFileNames++;
|
|
|
|
// Packed arrays start with a UINT16 value indicating the number of elements in the array.
|
|
BYTE* pbFileNames = reinterpret_cast<BYTE*>(_wchProcessFileNames);
|
|
pbFileNames[0] = (BYTE)_uiNumberProcessFileNames;
|
|
pbFileNames[1] = (BYTE)(_uiNumberProcessFileNames >> 8);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// This Function sends final Trace log before session closes.
|
|
// We're primarily sending this telemetry once at the end, and only when the user interacted with the console
|
|
// so we don't overwhelm our servers by sending a constant stream of telemetry while the console is being used.
|
|
void Telemetry::WriteFinalTraceLog()
|
|
{
|
|
const CONSOLE_INFORMATION& gci = Microsoft::Console::Interactivity::ServiceLocator::LocateGlobals().getConsoleInformation();
|
|
// This is a bit of processing, so don't do it for the 95% of machines that aren't being sampled.
|
|
if (TraceLoggingProviderEnabled(g_hConhostV2EventTraceProvider, 0, MICROSOFT_KEYWORD_MEASURES))
|
|
{
|
|
// Normally we would set the activity Id earlier, but since we know the parser only sends
|
|
// one final log at the end, setting the activity this late should be fine.
|
|
Microsoft::Console::VirtualTerminal::TermTelemetry::Instance().SetActivityId(_activity.Id());
|
|
Microsoft::Console::VirtualTerminal::TermTelemetry::Instance().SetShouldWriteFinalLog(_fUserInteractiveForTelemetry);
|
|
|
|
if (_fUserInteractiveForTelemetry)
|
|
{
|
|
TotalCodesForPreviousProcess();
|
|
|
|
// Send this back using "measures" since we want a good sampling of our entire userbase.
|
|
time_t tEndedAt;
|
|
time(&tEndedAt);
|
|
// clang-format off
|
|
#pragma prefast(suppress: __WARNING_NONCONST_LOCAL, "Activity can't be const, since it's set to a random value on startup.")
|
|
// clang-format on
|
|
TraceLoggingWriteTagged(_activity,
|
|
"SessionEnding",
|
|
TraceLoggingBool(_fBashUsed, "BashUsed"),
|
|
TraceLoggingBool(_fCtrlPgUpPgDnUsed, "CtrlPgUpPgDnUsed"),
|
|
TraceLoggingBool(_fKeyboardTextEditingUsed, "KeyboardTextEditingUsed"),
|
|
TraceLoggingBool(_fKeyboardTextSelectionUsed, "KeyboardTextSelectionUsed"),
|
|
TraceLoggingUInt32(_uiCtrlShiftCProcUsed, "CtrlShiftCProcUsed"),
|
|
TraceLoggingUInt32(_uiCtrlShiftCRawUsed, "CtrlShiftCRawUsed"),
|
|
TraceLoggingUInt32(_uiCtrlShiftVProcUsed, "CtrlShiftVProcUsed"),
|
|
TraceLoggingUInt32(_uiCtrlShiftVRawUsed, "CtrlShiftVRawUsed"),
|
|
TraceLoggingUInt32(_uiQuickEditCopyProcUsed, "QuickEditCopyProcUsed"),
|
|
TraceLoggingUInt32(_uiQuickEditCopyRawUsed, "QuickEditCopyRawUsed"),
|
|
TraceLoggingUInt32(_uiQuickEditPasteProcUsed, "QuickEditPasteProcUsed"),
|
|
TraceLoggingUInt32(_uiQuickEditPasteRawUsed, "QuickEditPasteRawUsed"),
|
|
TraceLoggingBool(gci.GetLinkTitle().length() == 0, "LaunchedFromShortcut"),
|
|
// Normally we would send out a single array containing the name and count,
|
|
// but that's difficult to do with our telemetry system, so send out two separate arrays.
|
|
// Casting to UINT should be fine, since our array size is only 2K.
|
|
TraceLoggingPackedField(_wchProcessFileNames, static_cast<UINT>(sizeof(WCHAR) * _iProcessFileNamesNext), TlgInUNICODESTRING | TlgInVcount, "ProcessesConnected"),
|
|
TraceLoggingUInt32Array(_rguiProcessFileNamesCount, _uiNumberProcessFileNames, "ProcessesConnectedCount"),
|
|
TraceLoggingUInt32Array(_rguiProcessFileNamesCodesCount, _uiNumberProcessFileNames, "ProcessesConnectedCodesCount"),
|
|
TraceLoggingUInt32Array(_rguiProcessFileNamesFailedCodesCount, _uiNumberProcessFileNames, "ProcessesConnectedFailedCodesCount"),
|
|
TraceLoggingUInt32Array(_rguiProcessFileNamesFailedOutsideCodesCount, _uiNumberProcessFileNames, "ProcessesConnectedFailedOutsideCount"),
|
|
// Send back both starting and ending times separately instead just usage time (ending - starting).
|
|
// This can help us determine if they were using multiple consoles at the same time.
|
|
TraceLoggingInt32(static_cast<int>(_tStartedAt), "StartedUsingAtSeconds"),
|
|
TraceLoggingInt32(static_cast<int>(tEndedAt), "EndedUsingAtSeconds"),
|
|
TraceLoggingUInt32(_uiColorSelectionUsed, "ColorSelectionUsed"),
|
|
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
|
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
|
|
|
// Always send this back. We could only send this back when they click "OK" in the settings dialog, but sending it
|
|
// back every time should give us a good idea of their current, final settings, and not just only when they change a setting.
|
|
// clang-format off
|
|
#pragma prefast(suppress: __WARNING_NONCONST_LOCAL, "Activity can't be const, since it's set to a random value on startup.")
|
|
// clang-format on
|
|
TraceLoggingWriteTagged(_activity,
|
|
"Settings",
|
|
TraceLoggingBool(gci.GetAutoPosition(), "AutoPosition"),
|
|
TraceLoggingBool(gci.GetHistoryNoDup(), "HistoryNoDuplicates"),
|
|
TraceLoggingBool(gci.GetInsertMode(), "InsertMode"),
|
|
TraceLoggingBool(gci.GetLineSelection(), "LineSelection"),
|
|
TraceLoggingBool(gci.GetQuickEdit(), "QuickEdit"),
|
|
TraceLoggingValue(gci.GetWindowAlpha(), "WindowAlpha"),
|
|
TraceLoggingBool(gci.GetWrapText(), "WrapText"),
|
|
TraceLoggingUInt32Array((UINT32 const*)gci.GetColorTable(), (UINT16)gci.GetColorTableSize(), "ColorTable"),
|
|
TraceLoggingValue(gci.CP, "CodePageInput"),
|
|
TraceLoggingValue(gci.OutputCP, "CodePageOutput"),
|
|
TraceLoggingValue(gci.GetFontSize().X, "FontSizeX"),
|
|
TraceLoggingValue(gci.GetFontSize().Y, "FontSizeY"),
|
|
TraceLoggingValue(gci.GetHotKey(), "HotKey"),
|
|
TraceLoggingValue(gci.GetScreenBufferSize().X, "ScreenBufferSizeX"),
|
|
TraceLoggingValue(gci.GetScreenBufferSize().Y, "ScreenBufferSizeY"),
|
|
TraceLoggingValue(gci.GetStartupFlags(), "StartupFlags"),
|
|
TraceLoggingValue(gci.GetVirtTermLevel(), "VirtualTerminalLevel"),
|
|
TraceLoggingValue(gci.GetWindowSize().X, "WindowSizeX"),
|
|
TraceLoggingValue(gci.GetWindowSize().Y, "WindowSizeY"),
|
|
TraceLoggingValue(gci.GetWindowOrigin().X, "WindowOriginX"),
|
|
TraceLoggingValue(gci.GetWindowOrigin().Y, "WindowOriginY"),
|
|
TraceLoggingValue(gci.GetFaceName(), "FontName"),
|
|
TraceLoggingBool(gci.IsAltF4CloseAllowed(), "AllowAltF4Close"),
|
|
TraceLoggingBool(gci.GetCtrlKeyShortcutsDisabled(), "ControlKeyShortcutsDisabled"),
|
|
TraceLoggingBool(gci.GetEnableColorSelection(), "EnabledColorSelection"),
|
|
TraceLoggingBool(gci.GetFilterOnPaste(), "FilterOnPaste"),
|
|
TraceLoggingBool(gci.GetTrimLeadingZeros(), "TrimLeadingZeros"),
|
|
TraceLoggingValue(gci.GetLaunchFaceName().data(), "LaunchFontName"),
|
|
TraceLoggingValue(CommandHistory::s_CountOfHistories(), "CommandHistoriesNumber"),
|
|
TraceLoggingValue(gci.GetCodePage(), "CodePage"),
|
|
TraceLoggingValue(gci.GetCursorSize(), "CursorSize"),
|
|
TraceLoggingValue(gci.GetFontFamily(), "FontFamily"),
|
|
TraceLoggingValue(gci.GetFontWeight(), "FontWeight"),
|
|
TraceLoggingValue(gci.GetHistoryBufferSize(), "HistoryBufferSize"),
|
|
TraceLoggingValue(gci.GetNumberOfHistoryBuffers(), "HistoryBuffersNumber"),
|
|
TraceLoggingValue(gci.GetScrollScale(), "ScrollScale"),
|
|
TraceLoggingValue(gci.GetFillAttribute(), "FillAttribute"),
|
|
TraceLoggingValue(gci.GetPopupFillAttribute(), "PopupFillAttribute"),
|
|
TraceLoggingValue(gci.GetShowWindow(), "ShowWindow"),
|
|
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
|
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
|
static_assert(sizeof(UINT32) == sizeof(*gci.GetColorTable()), "gci.GetColorTable()");
|
|
|
|
// I could use the TraceLoggingUIntArray, but then we would have to know the order of the enums on the backend.
|
|
// So just log each enum count separately with its string representation which makes it more human readable.
|
|
// clang-format off
|
|
#pragma prefast(suppress: __WARNING_NONCONST_LOCAL, "Activity can't be const, since it's set to a random value on startup.")
|
|
// clang-format on
|
|
TraceLoggingWriteTagged(_activity,
|
|
"ApiUsed",
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[AddConsoleAlias], "AddConsoleAlias"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[AllocConsole], "AllocConsole"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[AttachConsole], "AttachConsole"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[CreateConsoleScreenBuffer], "CreateConsoleScreenBuffer"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[GenerateConsoleCtrlEvent], "GenerateConsoleCtrlEvent"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[FillConsoleOutputAttribute], "FillConsoleOutputAttribute"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[FillConsoleOutputCharacter], "FillConsoleOutputCharacter"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[FlushConsoleInputBuffer], "FlushConsoleInputBuffer"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[FreeConsole], "FreeConsole"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[GetConsoleAlias], "GetConsoleAlias"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[GetConsoleAliases], "GetConsoleAliases"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[GetConsoleAliasExesLength], "GetConsoleAliasExesLength"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[GetConsoleAliasesLength], "GetConsoleAliasesLength"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[GetConsoleAliasExes], "GetConsoleAliasExes"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[GetConsoleCP], "GetConsoleCP"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[GetConsoleCursorInfo], "GetConsoleCursorInfo"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[GetConsoleDisplayMode], "GetConsoleDisplayMode"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[GetConsoleFontSize], "GetConsoleFontSize"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[GetConsoleHistoryInfo], "GetConsoleHistoryInfo"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[GetConsoleLangId], "GetConsoleLangId"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[GetConsoleMode], "GetConsoleMode"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[GetConsoleOriginalTitle], "GetConsoleOriginalTitle"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[GetConsoleOutputCP], "GetConsoleOutputCP"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[GetConsoleProcessList], "GetConsoleProcessList"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[GetConsoleScreenBufferInfoEx], "GetConsoleScreenBufferInfoEx"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[GetConsoleSelectionInfo], "GetConsoleSelectionInfo"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[GetConsoleTitle], "GetConsoleTitle"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[GetConsoleWindow], "GetConsoleWindow"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[GetCurrentConsoleFontEx], "GetCurrentConsoleFontEx"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[GetLargestConsoleWindowSize], "GetLargestConsoleWindowSize"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[GetNumberOfConsoleInputEvents], "GetNumberOfConsoleInputEvents"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[GetNumberOfConsoleMouseButtons], "GetNumberOfConsoleMouseButtons"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[PeekConsoleInput], "PeekConsoleInput"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[ReadConsole], "ReadConsole"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[ReadConsoleInput], "ReadConsoleInput"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[ReadConsoleOutput], "ReadConsoleOutput"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[ReadConsoleOutputAttribute], "ReadConsoleOutputAttribute"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[ReadConsoleOutputCharacter], "ReadConsoleOutputCharacter"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[ScrollConsoleScreenBuffer], "ScrollConsoleScreenBuffer"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[SetConsoleActiveScreenBuffer], "SetConsoleActiveScreenBuffer"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[SetConsoleCP], "SetConsoleCP"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[SetConsoleCursorInfo], "SetConsoleCursorInfo"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[SetConsoleCursorPosition], "SetConsoleCursorPosition"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[SetConsoleDisplayMode], "SetConsoleDisplayMode"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[SetConsoleHistoryInfo], "SetConsoleHistoryInfo"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[SetConsoleMode], "SetConsoleMode"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[SetConsoleOutputCP], "SetConsoleOutputCP"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[SetConsoleScreenBufferInfoEx], "SetConsoleScreenBufferInfoEx"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[SetConsoleScreenBufferSize], "SetConsoleScreenBufferSize"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[SetConsoleTextAttribute], "SetConsoleTextAttribute"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[SetConsoleTitle], "SetConsoleTitle"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[SetConsoleWindowInfo], "SetConsoleWindowInfo"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[SetCurrentConsoleFontEx], "SetCurrentConsoleFontEx"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[WriteConsole], "WriteConsole"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[WriteConsoleInput], "WriteConsoleInput"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[WriteConsoleOutput], "WriteConsoleOutput"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[WriteConsoleOutputAttribute], "WriteConsoleOutputAttribute"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsed[WriteConsoleOutputCharacter], "WriteConsoleOutputCharacter"),
|
|
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
|
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
|
|
|
for (int n = 0; n < ARRAYSIZE(_rguiTimesApiUsedAnsi); n++)
|
|
{
|
|
if (_rguiTimesApiUsedAnsi[n])
|
|
{
|
|
// Ansi specific API's are used less, so check if we have anything to send back.
|
|
// Also breaking it up into a separate TraceLoggingWriteTagged fixes a compilation warning that
|
|
// the heap is too small.
|
|
// clang-format off
|
|
#pragma prefast(suppress: __WARNING_NONCONST_LOCAL, "Activity can't be const, since it's set to a random value on startup.")
|
|
// clang-format on
|
|
TraceLoggingWriteTagged(_activity,
|
|
"ApiAnsiUsed",
|
|
TraceLoggingUInt32(_rguiTimesApiUsedAnsi[AddConsoleAlias], "AddConsoleAlias"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsedAnsi[FillConsoleOutputCharacter], "FillConsoleOutputCharacter"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsedAnsi[GetConsoleAlias], "GetConsoleAlias"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsedAnsi[GetConsoleAliases], "GetConsoleAliases"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsedAnsi[GetConsoleAliasesLength], "GetConsoleAliasesLength"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsedAnsi[GetConsoleAliasExes], "GetConsoleAliasExes"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsedAnsi[GetConsoleAliasExesLength], "GetConsoleAliasExesLength"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsedAnsi[GetConsoleOriginalTitle], "GetConsoleOriginalTitle"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsedAnsi[GetConsoleTitle], "GetConsoleTitle"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsedAnsi[PeekConsoleInput], "PeekConsoleInput"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsedAnsi[ReadConsole], "ReadConsole"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsedAnsi[ReadConsoleInput], "ReadConsoleInput"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsedAnsi[ReadConsoleOutput], "ReadConsoleOutput"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsedAnsi[ReadConsoleOutputCharacter], "ReadConsoleOutputCharacter"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsedAnsi[SetConsoleTitle], "SetConsoleTitle"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsedAnsi[WriteConsole], "WriteConsole"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsedAnsi[WriteConsoleInput], "WriteConsoleInput"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsedAnsi[WriteConsoleOutput], "WriteConsoleOutput"),
|
|
TraceLoggingUInt32(_rguiTimesApiUsedAnsi[WriteConsoleOutputCharacter], "WriteConsoleOutputCharacter"),
|
|
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
|
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// These are legacy error messages with limited value, so don't send them back as telemetry.
|
|
void Telemetry::LogRipMessage(_In_z_ const char* pszMessage, ...) const
|
|
{
|
|
// Code needed for passing variable parameters to the vsprintf function.
|
|
va_list args;
|
|
va_start(args, pszMessage);
|
|
char szMessageEvaluated[200] = "";
|
|
int cCharsWritten = vsprintf_s(szMessageEvaluated, ARRAYSIZE(szMessageEvaluated), pszMessage, args);
|
|
va_end(args);
|
|
|
|
#if DBG
|
|
OutputDebugStringA(szMessageEvaluated);
|
|
#endif
|
|
|
|
if (cCharsWritten > 0)
|
|
{
|
|
// clang-format off
|
|
#pragma prefast(suppress: __WARNING_NONCONST_LOCAL, "Activity can't be const, since it's set to a random value on startup.")
|
|
// clang-format on
|
|
TraceLoggingWriteTagged(_activity,
|
|
"RipMessage",
|
|
TraceLoggingString(szMessageEvaluated, "Message"));
|
|
}
|
|
}
|