terminal/src/host/telemetry.hpp

198 lines
7.4 KiB
C++

/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
Module Name:
- telemetry.hpp
Abstract:
- This module is used for recording all telemetry feedback from the console
Author(s):
- Evan Wirt (EvanWi) 09-Jul-2014
- Kourosh Mehrain (KMehrain) 09-Jul-2014
- Stephen Somuah (StSomuah) 09-Jul-2014
- Anup Manandhar (AnupM) 09-Jul-2014
--*/
#pragma once
#include <TraceLoggingActivity.h>
class Telemetry
{
public:
// Implement this as a singleton class.
static Telemetry& Instance()
{
static Telemetry s_Instance;
return s_Instance;
}
void SetUserInteractive();
void SetWindowSizeChanged();
void SetContextMenuUsed();
void SetKeyboardTextSelectionUsed();
void SetKeyboardTextEditingUsed();
void SetCtrlPgUpPgDnUsed();
void LogCtrlShiftCProcUsed();
void LogCtrlShiftCRawUsed();
void LogCtrlShiftVProcUsed();
void LogCtrlShiftVRawUsed();
void LogQuickEditCopyProcUsed();
void LogQuickEditCopyRawUsed();
void LogQuickEditPasteProcUsed();
void LogQuickEditPasteRawUsed();
void LogColorSelectionUsed();
void LogFindDialogNextClicked(const unsigned int iStringLength, const bool fDirectionDown, const bool fMatchCase);
void LogProcessConnected(const HANDLE hProcess);
void FindDialogClosed();
void WriteFinalTraceLog();
void LogRipMessage(_In_z_ const char* pszMessage, ...) const;
// Names are from the external API call names. Note that some names can be different
// than the internal API calls.
// Don't worry about the following APIs, because they are external to our conhost codebase and hard to track through
// telemetry: GetStdHandle, SetConsoleCtrlHandler, SetStdHandle
// We can't differentiate between these apis, so just log the "-Ex" versions: GetConsoleScreenBufferInfo / GetConsoleScreenBufferInfoEx,
// GetCurrentConsoleFontEx / GetCurrentConsoleFont
enum ApiCall
{
AddConsoleAlias = 0,
AllocConsole,
AttachConsole,
CreateConsoleScreenBuffer,
FillConsoleOutputAttribute,
FillConsoleOutputCharacter,
FlushConsoleInputBuffer,
FreeConsole,
GenerateConsoleCtrlEvent,
GetConsoleAlias,
GetConsoleAliases,
GetConsoleAliasesLength,
GetConsoleAliasExes,
GetConsoleAliasExesLength,
GetConsoleCP,
GetConsoleCursorInfo,
GetConsoleDisplayMode,
GetConsoleFontSize,
GetConsoleHistoryInfo,
GetConsoleMode,
GetConsoleLangId,
GetConsoleOriginalTitle,
GetConsoleOutputCP,
GetConsoleProcessList,
GetConsoleScreenBufferInfoEx,
GetConsoleSelectionInfo,
GetConsoleTitle,
GetConsoleWindow,
GetCurrentConsoleFontEx,
GetLargestConsoleWindowSize,
GetNumberOfConsoleInputEvents,
GetNumberOfConsoleMouseButtons,
PeekConsoleInput,
ReadConsole,
ReadConsoleInput,
ReadConsoleOutput,
ReadConsoleOutputAttribute,
ReadConsoleOutputCharacter,
ScrollConsoleScreenBuffer,
SetConsoleActiveScreenBuffer,
SetConsoleCP,
SetConsoleCursorInfo,
SetConsoleCursorPosition,
SetConsoleDisplayMode,
SetConsoleHistoryInfo,
SetConsoleMode,
SetConsoleOutputCP,
SetConsoleScreenBufferInfoEx,
SetConsoleScreenBufferSize,
SetConsoleTextAttribute,
SetConsoleTitle,
SetConsoleWindowInfo,
SetCurrentConsoleFontEx,
WriteConsole,
WriteConsoleInput,
WriteConsoleOutput,
WriteConsoleOutputAttribute,
WriteConsoleOutputCharacter,
// Only use this last enum as a count of the number of api enums.
NUMBER_OF_APIS
};
void LogApiCall(const ApiCall api);
void LogApiCall(const ApiCall api, const BOOLEAN fUnicode);
private:
// Used to prevent multiple instances
Telemetry();
~Telemetry();
Telemetry(Telemetry const&);
void operator=(Telemetry const&);
bool FindProcessName(const WCHAR* pszProcessName, _Out_ size_t* iPosition) const;
void TotalCodesForPreviousProcess();
static const int c_iMaxProcessesConnected = 100;
TraceLoggingActivity<g_hConhostV2EventTraceProvider> _activity;
float _fpFindStringLengthAverage;
float _fpDirectionDownAverage;
float _fpMatchCaseAverage;
unsigned int _uiFindNextClickedTotal;
unsigned int _uiColorSelectionUsed;
time_t _tStartedAt;
WCHAR const* const c_pwszBashExeName = L"bash.exe";
// The current recommendation is to keep telemetry events 4KB or less, so let's keep our array at less than 2KB (1000 * 2 bytes).
WCHAR _wchProcessFileNames[1000];
// Index into our specially packed string, where to insert the next string.
size_t _iProcessFileNamesNext;
// Index for the currently connected process.
size_t _iProcessConnectedCurrently;
// An array of indexes into the _wchProcessFileNames array, which point to the individual process names.
size_t _rgiProcessFileNameIndex[c_iMaxProcessesConnected];
// Number of times each process has connected to the console.
unsigned int _rguiProcessFileNamesCount[c_iMaxProcessesConnected];
// To speed up searching the Process Names, create an alphabetically sorted index.
size_t _rgiAlphabeticalIndex[c_iMaxProcessesConnected];
// Total of how many codes each process used
unsigned int _rguiProcessFileNamesCodesCount[c_iMaxProcessesConnected];
// Total of how many failed codes each process used
unsigned int _rguiProcessFileNamesFailedCodesCount[c_iMaxProcessesConnected];
// Total of how many failed codes each process used outside the valid range.
unsigned int _rguiProcessFileNamesFailedOutsideCodesCount[c_iMaxProcessesConnected];
unsigned int _rguiTimesApiUsed[NUMBER_OF_APIS];
// Most of this array will be empty, and is only used if an API has an ansi specific variant.
unsigned int _rguiTimesApiUsedAnsi[NUMBER_OF_APIS];
// Total number of file names we've added.
UINT16 _uiNumberProcessFileNames;
bool _fBashUsed;
bool _fKeyboardTextEditingUsed;
bool _fKeyboardTextSelectionUsed;
bool _fUserInteractiveForTelemetry;
bool _fCtrlPgUpPgDnUsed;
// Linux copy and paste keyboard shortcut telemetry
unsigned int _uiCtrlShiftCProcUsed;
unsigned int _uiCtrlShiftCRawUsed;
unsigned int _uiCtrlShiftVProcUsed;
unsigned int _uiCtrlShiftVRawUsed;
// Quick edit copy and paste usage telemetry
unsigned int _uiQuickEditCopyProcUsed;
unsigned int _uiQuickEditCopyRawUsed;
unsigned int _uiQuickEditPasteProcUsed;
unsigned int _uiQuickEditPasteRawUsed;
};
// Log the RIPMSG through telemetry, and also through a normal OutputDebugStringW call.
// These are drop-in substitutes for the RIPMSG0-4 macros from /windows/Core/ntcon2/conhost/consrv.h
#define RIPMSG0(flags, msg) Telemetry::Instance().LogRipMessage(msg);
#define RIPMSG1(flags, msg, a) Telemetry::Instance().LogRipMessage(msg, a);
#define RIPMSG2(flags, msg, a, b) Telemetry::Instance().LogRipMessage(msg, a, b);
#define RIPMSG3(flags, msg, a, b, c) Telemetry::Instance().LogRipMessage(msg, a, b, c);
#define RIPMSG4(flags, msg, a, b, c, d) Telemetry::Instance().LogRipMessage(msg, a, b, c, d);