From 18a1f82035289a19d999a61459f0fa4d56fda73a Mon Sep 17 00:00:00 2001 From: Stephanie Anderl <46726333+sanderl@users.noreply.github.com> Date: Thu, 12 Mar 2020 14:05:47 -0700 Subject: [PATCH] Graphing Calculator Diagnostics Instrumentation (#1041) * Add telemetry for keyboard button usage in graphing mode * Added the diagnostics for EquationAdded and FunctionAnalysis * Added remaining diagnostics events for graphing calculator * Fix proj files to include the IsStoreBuild condition. Move the Delayer class to the Calculator/Utils folder * Ensure the variable textbox has focus before logging diagnostics * Move maxVariableCount check into the tracelogger class * Created enums and updated the slider value changed method to remove the variable from the map after the log method is called * Re-enable hidden lines when the expression is updated * Fixed extra line in grapher.h and removed the conditional logging for variable count * Updated logging per PR feedback * Updated variable logging and fixed issues in the IsEquationLineDisabled binding the EditTextBox control. * Update per PR feedback * Added TraceLogging project to contain shared logging logic. * Updated TraceLogging project and updated tracelogger classes to use the TraceLogging project methods * Updated VariableLogging to log variable name. And updated per PR comments * Updated Variables logging to log count changed instead of variable added and fixed issue with variableSliders not being initialized * Remove outdated tracelogging call caused by rebase * Updated Delayer class to DispatcherTimerDelayer and fixed some small formatting issues * Fixed missing Dalyer class name updates * Removed extra line in traceloger.h --- src/CalcViewModel/CalcViewModel.vcxproj | 4 +- .../CalcViewModel.vcxproj.filters | 5 +- .../Common/CalculatorButtonUser.h | 3 +- src/CalcViewModel/Common/TraceActivity.h | 55 ---- src/CalcViewModel/Common/TraceLogger.cpp | 305 +++++++----------- src/CalcViewModel/Common/TraceLogger.h | 58 ++-- .../GraphingSettingsViewModel.cpp | 2 + .../GraphingSettingsViewModel.h | 10 + src/Calculator.sln | 18 ++ src/Calculator/Calculator.vcxproj | 4 +- src/Calculator/Calculator.vcxproj.filters | 4 + src/Calculator/Controls/EquationTextBox.cpp | 16 +- src/Calculator/Controls/EquationTextBox.h | 2 + .../EquationStylePanelControl.xaml.cpp | 2 + .../EquationStylePanelControl.xaml.h | 1 + .../Utils/DispatcherTimerDelayer.cpp | 39 +++ src/Calculator/Utils/DispatcherTimerDelayer.h | 26 ++ src/Calculator/Views/Calculator.xaml.cpp | 8 +- .../GraphingCalculator/EquationInputArea.xaml | 6 +- .../EquationInputArea.xaml.cpp | 51 +++ .../EquationInputArea.xaml.h | 5 +- .../GraphingCalculator.xaml | 2 +- .../GraphingCalculator.xaml.cpp | 12 + .../GraphingCalculator.xaml.h | 2 + .../GraphingNumPad.xaml.cpp | 4 + .../GraphingCalculator/GraphingNumPad.xaml.h | 1 + src/Calculator/pch.h | 1 + src/GraphControl/Control/Grapher.cpp | 36 ++- src/GraphControl/Control/Grapher.h | 4 + src/GraphControl/GraphControl.vcxproj | 12 + src/GraphControl/GraphControl.vcxproj.filters | 7 +- src/GraphControl/Logger/TraceLogger.cpp | 89 +++++ src/GraphControl/Logger/TraceLogger.h | 27 ++ .../Models/KeyGraphFeaturesInfo.cpp | 4 + src/GraphControl/pch.h | 3 + src/GraphControl/winrtHeaders.h | 1 + src/TraceLogging/TraceLogging.vcxproj | 294 +++++++++++++++++ src/TraceLogging/TraceLogging.vcxproj.filters | 17 + src/TraceLogging/TraceLoggingCommon.cpp | 88 +++++ src/TraceLogging/TraceLoggingCommon.h | 31 ++ src/TraceLogging/pch.cpp | 4 + src/TraceLogging/pch.h | 10 + 42 files changed, 981 insertions(+), 292 deletions(-) delete mode 100644 src/CalcViewModel/Common/TraceActivity.h create mode 100644 src/Calculator/Utils/DispatcherTimerDelayer.cpp create mode 100644 src/Calculator/Utils/DispatcherTimerDelayer.h create mode 100644 src/GraphControl/Logger/TraceLogger.cpp create mode 100644 src/GraphControl/Logger/TraceLogger.h create mode 100644 src/TraceLogging/TraceLogging.vcxproj create mode 100644 src/TraceLogging/TraceLogging.vcxproj.filters create mode 100644 src/TraceLogging/TraceLoggingCommon.cpp create mode 100644 src/TraceLogging/TraceLoggingCommon.h create mode 100644 src/TraceLogging/pch.cpp create mode 100644 src/TraceLogging/pch.h diff --git a/src/CalcViewModel/CalcViewModel.vcxproj b/src/CalcViewModel/CalcViewModel.vcxproj index db212ad..c2a69b5 100644 --- a/src/CalcViewModel/CalcViewModel.vcxproj +++ b/src/CalcViewModel/CalcViewModel.vcxproj @@ -314,7 +314,6 @@ - @@ -383,6 +382,9 @@ {e727a92b-f149-492c-8117-c039a298719b} + + {fc81ff41-02cd-4cd9-9bc5-45a1e39ac6ed} + diff --git a/src/CalcViewModel/CalcViewModel.vcxproj.filters b/src/CalcViewModel/CalcViewModel.vcxproj.filters index 0b3507f..7a0619e 100644 --- a/src/CalcViewModel/CalcViewModel.vcxproj.filters +++ b/src/CalcViewModel/CalcViewModel.vcxproj.filters @@ -169,9 +169,6 @@ DataLoaders - - Common - DataLoaders @@ -200,7 +197,7 @@ GraphingCalculator - Common + Common diff --git a/src/CalcViewModel/Common/CalculatorButtonUser.h b/src/CalcViewModel/Common/CalculatorButtonUser.h index 8afd0fe..bc03b0a 100644 --- a/src/CalcViewModel/Common/CalculatorButtonUser.h +++ b/src/CalcViewModel/Common/CalculatorButtonUser.h @@ -202,6 +202,7 @@ public GreaterThan, GreaterThanOrEqualTo, X, - Y + Y, + Submit }; } diff --git a/src/CalcViewModel/Common/TraceActivity.h b/src/CalcViewModel/Common/TraceActivity.h deleted file mode 100644 index 003bf6b..0000000 --- a/src/CalcViewModel/Common/TraceActivity.h +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once -#include - -namespace CalculatorApp -{ - // RAII wrapper that automatically sends the Stop event when the class gets destructed. - class TraceActivity - { - public: - TraceActivity() - : m_channel(nullptr) - , m_activity(nullptr) - , m_fields(nullptr) - { - } - - TraceActivity( - winrt::Windows::Foundation::Diagnostics::LoggingChannel channel, - std::wstring_view activityName, - winrt::Windows::Foundation::Diagnostics::LoggingFields fields) - : m_channel(channel) - , m_activityName(activityName) - , m_fields(fields) - , m_activity(nullptr) - { - // Write the activity's START event. Note that you must not specify keyword - // or level for START and STOP events because they always use the activity's - // keyword and level. - m_activity = m_channel.StartActivity( - m_activityName, - m_fields, - winrt::Windows::Foundation::Diagnostics::LoggingLevel::Verbose, - winrt::Windows::Foundation::Diagnostics::LoggingOptions(WINEVENT_KEYWORD_RESPONSE_TIME)); - } - - ~TraceActivity() - { - if (m_activity != nullptr) - { - // Write the activity's STOP event. - m_activity.StopActivity(m_activityName, m_fields); - m_activity = nullptr; - } - } - - private: - std::wstring m_activityName; - winrt::Windows::Foundation::Diagnostics::LoggingChannel m_channel; - winrt::Windows::Foundation::Diagnostics::LoggingFields m_fields; - winrt::Windows::Foundation::Diagnostics::LoggingActivity m_activity; - }; -} diff --git a/src/CalcViewModel/Common/TraceLogger.cpp b/src/CalcViewModel/Common/TraceLogger.cpp index 845b010..64a99cb 100644 --- a/src/CalcViewModel/Common/TraceLogger.cpp +++ b/src/CalcViewModel/Common/TraceLogger.cpp @@ -8,15 +8,15 @@ using namespace CalculatorApp; using namespace CalculatorApp::Common; +using namespace TraceLogging; using namespace Concurrency; using namespace std; using namespace Platform; -using namespace winrt; -using namespace winrt::Windows::Foundation; -using namespace winrt::Windows::Foundation::Diagnostics; -using namespace winrt::Windows::Globalization; -using namespace winrt::Windows::Globalization::DateTimeFormatting; -using namespace winrt::Windows::System::UserProfile; +using namespace Windows::Foundation; +using namespace Windows::Foundation::Diagnostics; +using namespace Windows::Globalization; +using namespace Windows::Globalization::DateTimeFormatting; +using namespace Windows::System::UserProfile; namespace CalculatorApp { @@ -35,36 +35,22 @@ namespace CalculatorApp constexpr auto EVENT_NAME_VISUAL_STATE_CHANGED = L"VisualStateChanged"; constexpr auto EVENT_NAME_CONVERTER_INPUT_RECEIVED = L"ConverterInputReceived"; constexpr auto EVENT_NAME_INPUT_PASTED = L"InputPasted"; + constexpr auto EVENT_NAME_SHOW_HIDE_BUTTON_CLICKED = L"ShowHideButtonClicked"; + constexpr auto EVENT_NAME_GRAPH_BUTTON_CLICKED = L"GraphButtonClicked"; + constexpr auto EVENT_NAME_GRAPH_LINE_STYLE_CHANGED = L"GraphLineStyleChanged"; + constexpr auto EVENT_NAME_VARIABLE_CHANGED = L"VariableChanged"; + constexpr auto EVENT_NAME_VARIABLE_SETTING_CHANGED = L"VariableSettingChanged"; + constexpr auto EVENT_NAME_GRAPH_SETTINGS_CHANGED = L"GraphSettingsChanged"; constexpr auto EVENT_NAME_EXCEPTION = L"Exception"; - constexpr auto PDT_PRIVACY_DATA_TAG = L"PartA_PrivTags"; - constexpr auto PDT_PRODUCT_AND_SERVICE_USAGE = 0x0000'0000'0200'0000u; - -#ifdef SEND_DIAGNOSTICS - // c.f. WINEVENT_KEYWORD_RESERVED_63-56 0xFF00000000000000 // Bits 63-56 - channel keywords - // c.f. WINEVENT_KEYWORD_* 0x00FF000000000000 // Bits 55-48 - system-reserved keywords - constexpr int64_t MICROSOFT_KEYWORD_LEVEL_1 = 0x0000800000000000; // Bit 47 - constexpr int64_t MICROSOFT_KEYWORD_LEVEL_2 = 0x0000400000000000; // Bit 46 - constexpr int64_t MICROSOFT_KEYWORD_LEVEL_3 = 0x0000200000000000; // Bit 45 -#else - // define all Keyword options as 0 when we do not want to upload app diagnostics - constexpr int64_t MICROSOFT_KEYWORD_LEVEL_1 = 0; - constexpr int64_t MICROSOFT_KEYWORD_LEVEL_2 = 0; - constexpr int64_t MICROSOFT_KEYWORD_LEVEL_3 = 0; -#endif + constexpr auto CALC_MODE = L"CalcMode"; + constexpr auto GRAPHING_MODE = L"Graphing"; #pragma region TraceLogger setup and cleanup TraceLogger::TraceLogger() - : g_calculatorProvider( - L"MicrosoftCalculator", - LoggingChannelOptions(GUID{ 0x4f50731a, 0x89cf, 0x4782, 0xb3, 0xe0, 0xdc, 0xe8, 0xc9, 0x4, 0x76, 0xba }), - GUID{ 0x905ca09, 0x610e, 0x401e, 0xb6, 0x50, 0x2f, 0x21, 0x29, 0x80, 0xb9, 0xe0 }) - , // Unique providerID {0905CA09-610E-401E-B650-2F212980B9E0} - m_appLaunchActivity{ nullptr } { - CoCreateGuid(&sessionGuid); } TraceLogger ^ TraceLogger::GetInstance() @@ -73,33 +59,6 @@ namespace CalculatorApp return s_selfInstance; } - bool TraceLogger::GetTraceLoggingProviderEnabled() - { - return g_calculatorProvider.Enabled(); - } - -#pragma region Tracing methods - void TraceLogger::LogLevel1Event(wstring_view eventName, LoggingFields fields) - { - g_calculatorProvider.LogEvent(eventName, fields, LoggingLevel::Verbose, LoggingOptions(MICROSOFT_KEYWORD_LEVEL_1)); - } - - void TraceLogger::LogLevel2Event(wstring_view eventName, LoggingFields fields) - { - g_calculatorProvider.LogEvent(eventName, fields, LoggingLevel::Verbose, LoggingOptions(MICROSOFT_KEYWORD_LEVEL_2)); - } - - void TraceLogger::LogLevel3Event(wstring_view eventName, LoggingFields fields) - { - g_calculatorProvider.LogEvent(eventName, fields, LoggingLevel::Verbose, LoggingOptions(MICROSOFT_KEYWORD_LEVEL_3)); - } - - unique_ptr TraceLogger::CreateTraceActivity(wstring_view eventName, LoggingFields fields) - { - return make_unique(g_calculatorProvider, eventName, fields); - } -#pragma endregion - // return true if windowId is logged once else return false bool TraceLogger::IsWindowIdInLog(int windowId) { @@ -116,18 +75,12 @@ namespace CalculatorApp void TraceLogger::LogVisualStateChanged(ViewMode mode, String ^ state, bool isAlwaysOnTop) { - if (!GetTraceLoggingProviderEnabled()) - { - return; - } + auto fields = ref new LoggingFields(); - LoggingFields fields{}; - fields.AddGuid(L"SessionGuid", sessionGuid); - fields.AddString(L"CalcMode", NavCategory::GetFriendlyName(mode)->Data()); - fields.AddString(L"VisualState", state->Data()); - fields.AddBoolean(L"IsAlwaysOnTop", isAlwaysOnTop); - fields.AddUInt64(PDT_PRIVACY_DATA_TAG, PDT_PRODUCT_AND_SERVICE_USAGE); - LogLevel2Event(EVENT_NAME_VISUAL_STATE_CHANGED, fields); + fields->AddString(StringReference(CALC_MODE), NavCategory::GetFriendlyName(mode)); + fields->AddString(StringReference(L"VisualState"), state); + fields->AddBoolean(StringReference(L"IsAlwaysOnTop"), isAlwaysOnTop); + TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_VISUAL_STATE_CHANGED), fields); } void TraceLogger::LogWindowCreated(ViewMode mode, int windowId) @@ -138,122 +91,69 @@ namespace CalculatorApp windowIdLog.push_back(windowId); } - if (!GetTraceLoggingProviderEnabled()) - return; - - LoggingFields fields{}; - fields.AddGuid(L"SessionGuid", sessionGuid); - fields.AddString(L"CalcMode", NavCategory::GetFriendlyName(mode)->Data()); - fields.AddUInt64(L"NumOfOpenWindows", currentWindowCount); - fields.AddUInt64(PDT_PRIVACY_DATA_TAG, PDT_PRODUCT_AND_SERVICE_USAGE); - LogLevel2Event(EVENT_NAME_WINDOW_ON_CREATED, fields); + auto fields = ref new LoggingFields(); + fields->AddString(StringReference(CALC_MODE), NavCategory::GetFriendlyName(mode)); + fields->AddUInt64(StringReference(L"NumOfOpenWindows"), currentWindowCount); + TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_WINDOW_ON_CREATED), fields); } void TraceLogger::LogModeChange(ViewMode mode) { - if (!GetTraceLoggingProviderEnabled()) - return; - if (NavCategory::IsValidViewMode(mode)) { - LoggingFields fields{}; - fields.AddGuid(L"SessionGuid", sessionGuid); - fields.AddString(L"CalcMode", NavCategory::GetFriendlyName(mode)->Data()); - fields.AddUInt64(PDT_PRIVACY_DATA_TAG, PDT_PRODUCT_AND_SERVICE_USAGE); - LogLevel2Event(EVENT_NAME_MODE_CHANGED, fields); + auto fields = ref new LoggingFields(); + ; + fields->AddString(StringReference(CALC_MODE), NavCategory::GetFriendlyName(mode)); + TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_MODE_CHANGED), fields); } } void TraceLogger::LogHistoryItemLoad(ViewMode mode, int historyListSize, int loadedIndex) { - if (!GetTraceLoggingProviderEnabled()) - { - return; - } - - LoggingFields fields{}; - fields.AddGuid(L"SessionGuid", sessionGuid); - fields.AddString(L"CalcMode", NavCategory::GetFriendlyName(mode)->Data()); - fields.AddInt32(L"HistoryListSize", historyListSize); - fields.AddInt32(L"HistoryItemIndex", loadedIndex); - fields.AddUInt64(PDT_PRIVACY_DATA_TAG, PDT_PRODUCT_AND_SERVICE_USAGE); - LogLevel2Event(EVENT_NAME_HISTORY_ITEM_LOAD, fields); + auto fields = ref new LoggingFields(); + fields->AddString(StringReference(CALC_MODE), NavCategory::GetFriendlyName(mode)); + fields->AddInt32(StringReference(L"HistoryListSize"), historyListSize); + fields->AddInt32(StringReference(L"HistoryItemIndex"), loadedIndex); + TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_HISTORY_ITEM_LOAD), fields); } void TraceLogger::LogMemoryItemLoad(ViewMode mode, int memoryListSize, int loadedIndex) { - if (!GetTraceLoggingProviderEnabled()) - { - return; - } - - LoggingFields fields{}; - fields.AddGuid(L"SessionGuid", sessionGuid); - fields.AddString(L"CalcMode", NavCategory::GetFriendlyName(mode)->Data()); - fields.AddInt32(L"MemoryListSize", memoryListSize); - fields.AddInt32(L"MemoryItemIndex", loadedIndex); - fields.AddUInt64(PDT_PRIVACY_DATA_TAG, PDT_PRODUCT_AND_SERVICE_USAGE); - LogLevel2Event(EVENT_NAME_MEMORY_ITEM_LOAD, fields); + auto fields = ref new LoggingFields(); + fields->AddString(StringReference(CALC_MODE), NavCategory::GetFriendlyName(mode)); + fields->AddInt32(StringReference(L"MemoryListSize"), memoryListSize); + fields->AddInt32(StringReference(L"MemoryItemIndex"), loadedIndex); + TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_MEMORY_ITEM_LOAD), fields); } void TraceLogger::LogError(ViewMode mode, Platform::String ^ functionName, Platform::String ^ errorString) { - if (!GetTraceLoggingProviderEnabled()) - return; - - LoggingFields fields{}; - fields.AddGuid(L"SessionGuid", sessionGuid); - fields.AddString(L"CalcMode", NavCategory::GetFriendlyName(mode)->Data()); - fields.AddString(L"FunctionName", functionName->Data()); - fields.AddString(L"Message", errorString->Data()); - fields.AddUInt64(PDT_PRIVACY_DATA_TAG, PDT_PRODUCT_AND_SERVICE_USAGE); - LogLevel2Event(EVENT_NAME_EXCEPTION, fields); + auto fields = ref new LoggingFields(); + fields->AddString(StringReference(CALC_MODE), NavCategory::GetFriendlyName(mode)); + fields->AddString(StringReference(L"FunctionName"), functionName); + fields->AddString(StringReference(L"Message"), errorString); + TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_EXCEPTION), fields); } void TraceLogger::LogStandardException(ViewMode mode, wstring_view functionName, const exception& e) { - if (!GetTraceLoggingProviderEnabled()) - return; - - LoggingFields fields{}; - fields.AddGuid(L"SessionGuid", sessionGuid); - fields.AddString(L"CalcMode", NavCategory::GetFriendlyName(mode)->Data()); - fields.AddString(L"FunctionName", functionName); + auto fields = ref new LoggingFields(); + fields->AddString(StringReference(CALC_MODE), NavCategory::GetFriendlyName(mode)); + fields->AddString(StringReference(L"FunctionName"), StringReference(functionName.data())); wstringstream exceptionMessage; exceptionMessage << e.what(); - fields.AddString(L"Message", exceptionMessage.str()); - fields.AddUInt64(PDT_PRIVACY_DATA_TAG, PDT_PRODUCT_AND_SERVICE_USAGE); - LogLevel2Event(EVENT_NAME_EXCEPTION, fields); - } - - void TraceLogger::LogWinRTException(ViewMode mode, wstring_view functionName, hresult_error const& e) - { - if (!GetTraceLoggingProviderEnabled()) - return; - - LoggingFields fields{}; - fields.AddGuid(L"SessionGuid", sessionGuid); - fields.AddString(L"CalcMode", NavCategory::GetFriendlyName(mode)->Data()); - fields.AddString(L"FunctionName", functionName); - fields.AddString(L"Message", e.message()); - fields.AddInt32(L"HRESULT", e.code()); - fields.AddUInt64(PDT_PRIVACY_DATA_TAG, PDT_PRODUCT_AND_SERVICE_USAGE); - LogLevel2Event(EVENT_NAME_EXCEPTION, fields); + fields->AddString(StringReference(L"Message"), StringReference(exceptionMessage.str().data())); + TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_EXCEPTION), fields); } void TraceLogger::LogPlatformException(ViewMode mode, wstring_view functionName, Platform::Exception ^ e) { - if (!GetTraceLoggingProviderEnabled()) - return; - - LoggingFields fields{}; - fields.AddGuid(L"SessionGuid", sessionGuid); - fields.AddString(L"CalcMode", NavCategory::GetFriendlyName(mode)->Data()); - fields.AddString(L"FunctionName", functionName); - fields.AddString(L"Message", e->Message->Data()); - fields.AddInt32(L"HRESULT", e->HResult); - fields.AddUInt64(PDT_PRIVACY_DATA_TAG, PDT_PRODUCT_AND_SERVICE_USAGE); - LogLevel2Event(EVENT_NAME_EXCEPTION, fields); + auto fields = ref new LoggingFields(); + fields->AddString(StringReference(CALC_MODE), NavCategory::GetFriendlyName(mode)); + fields->AddString(StringReference(L"FunctionName"), StringReference(functionName.data())); + fields->AddString(StringReference(L"Message"), e->Message); + fields->AddInt32(StringReference(L"HRESULT"), e->HResult); + TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_EXCEPTION), fields); } void TraceLogger::UpdateButtonUsage(NumbersAndOperatorsEnum button, ViewMode mode) @@ -305,9 +205,6 @@ namespace CalculatorApp void TraceLogger::LogButtonUsage() { - if (!GetTraceLoggingProviderEnabled()) - return; - // Writer lock for the buttonLog resource reader_writer_lock::scoped_lock lock(s_traceLoggerLock); @@ -330,11 +227,9 @@ namespace CalculatorApp } } - LoggingFields fields{}; - fields.AddGuid(L"SessionGuid", sessionGuid); - fields.AddString(L"ButtonUsage", buttonUsageString->Data()); - fields.AddUInt64(PDT_PRIVACY_DATA_TAG, PDT_PRODUCT_AND_SERVICE_USAGE); - LogLevel2Event(EVENT_NAME_BUTTON_USAGE, fields); + auto fields = ref new LoggingFields(); + fields->AddString(StringReference(L"ButtonUsage"), buttonUsageString); + TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_BUTTON_USAGE), fields); buttonLog.clear(); } @@ -342,46 +237,78 @@ namespace CalculatorApp void TraceLogger::LogDateCalculationModeUsed(bool AddSubtractMode) { const wchar_t* calculationType = AddSubtractMode ? L"AddSubtractMode" : L"DateDifferenceMode"; - LoggingFields fields{}; - fields.AddGuid(L"SessionGuid", sessionGuid); - fields.AddString(L"CalcMode", NavCategory::GetFriendlyName(ViewMode::Date)->Data()); - fields.AddString(L"CalculationType", calculationType); - fields.AddUInt64(PDT_PRIVACY_DATA_TAG, PDT_PRODUCT_AND_SERVICE_USAGE); - LogLevel2Event(EVENT_NAME_DATE_CALCULATION_MODE_USED, fields); + auto fields = ref new LoggingFields(); + fields->AddString(StringReference(CALC_MODE), NavCategory::GetFriendlyName(ViewMode::Date)); + fields->AddString(StringReference(L"CalculationType"), StringReference(calculationType)); + TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_DATE_CALCULATION_MODE_USED), fields); } void TraceLogger::LogConverterInputReceived(ViewMode mode) { - if (!GetTraceLoggingProviderEnabled()) - return; - - LoggingFields fields{}; - fields.AddGuid(L"SessionGuid", sessionGuid); - fields.AddString(L"CalcMode", NavCategory::GetFriendlyName(mode)->Data()); - fields.AddUInt64(PDT_PRIVACY_DATA_TAG, PDT_PRODUCT_AND_SERVICE_USAGE); - LogLevel2Event(EVENT_NAME_CONVERTER_INPUT_RECEIVED, fields); + auto fields = ref new LoggingFields(); + fields->AddString(StringReference(CALC_MODE), NavCategory::GetFriendlyName(mode)); + TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_CONVERTER_INPUT_RECEIVED), fields); } void TraceLogger::LogNavBarOpened() { - if (!GetTraceLoggingProviderEnabled()) - return; - - LoggingFields fields{}; - fields.AddGuid(L"SessionGuid", sessionGuid); - fields.AddUInt64(PDT_PRIVACY_DATA_TAG, PDT_PRODUCT_AND_SERVICE_USAGE); - LogLevel2Event(EVENT_NAME_NAV_BAR_OPENED, fields); + auto fields = ref new LoggingFields(); + TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_NAV_BAR_OPENED), fields); } void TraceLogger::LogInputPasted(ViewMode mode) { - if (!GetTraceLoggingProviderEnabled()) - return; + auto fields = ref new LoggingFields(); + fields->AddString(StringReference(CALC_MODE), NavCategory::GetFriendlyName(mode)); + TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_INPUT_PASTED), fields); + } - LoggingFields fields{}; - fields.AddGuid(L"SessionGuid", sessionGuid); - fields.AddString(L"Mode", NavCategory::GetFriendlyName(mode)->Data()); - fields.AddUInt64(PDT_PRIVACY_DATA_TAG, PDT_PRODUCT_AND_SERVICE_USAGE); - LogLevel2Event(EVENT_NAME_INPUT_PASTED, fields); + void TraceLogger::LogShowHideButtonClicked(bool isHideButton) + { + auto fields = ref new LoggingFields(); + fields->AddString(StringReference(CALC_MODE), StringReference(GRAPHING_MODE)); + fields->AddBoolean(StringReference(L"IsHideButton"), isHideButton); + TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_SHOW_HIDE_BUTTON_CLICKED), fields); + } + + void TraceLogger::LogGraphButtonClicked(GraphButton buttonName) + { + auto fields = ref new LoggingFields(); + fields->AddString(StringReference(CALC_MODE), StringReference(GRAPHING_MODE)); + fields->AddInt16(StringReference(L"ButtonName"), static_cast(buttonName)); + TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_GRAPH_BUTTON_CLICKED), fields); + } + + void TraceLogger::LogGraphLineStyleChanged(LineStyleType style) + { + auto fields = ref new LoggingFields(); + fields->AddString(StringReference(CALC_MODE), StringReference(GRAPHING_MODE)); + fields->AddInt16(StringReference(L"StyleType"), static_cast(style)); + TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_GRAPH_LINE_STYLE_CHANGED), fields); + } + + void TraceLogger::LogVariableChanged(String ^ inputChangedType, String ^ variableName) + { + auto fields = ref new LoggingFields(); + fields->AddString(StringReference(CALC_MODE), StringReference(GRAPHING_MODE)); + fields->AddString(StringReference(L"InputChangedType"), inputChangedType); + fields->AddString(StringReference(L"VariableName"), variableName); + TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_VARIABLE_CHANGED), fields); + } + void TraceLogger::LogVariableSettingsChanged(String ^ setting) + { + auto fields = ref new LoggingFields(); + fields->AddString(StringReference(CALC_MODE), StringReference(GRAPHING_MODE)); + fields->AddString(StringReference(L"SettingChanged"), setting); + TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_VARIABLE_SETTING_CHANGED), fields); + } + + void TraceLogger::LogGraphSettingsChanged(GraphSettingsType settingType) + { + auto fields = ref new LoggingFields(); + fields->AddString(StringReference(CALC_MODE), StringReference(GRAPHING_MODE)); + fields->AddInt16(L"SettingType", static_cast(settingType)); + + TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_GRAPH_SETTINGS_CHANGED), fields); } } diff --git a/src/CalcViewModel/Common/TraceLogger.h b/src/CalcViewModel/Common/TraceLogger.h index fa24f8e..37e4b2b 100644 --- a/src/CalcViewModel/Common/TraceLogger.h +++ b/src/CalcViewModel/Common/TraceLogger.h @@ -3,13 +3,9 @@ #pragma once -#include "CalcManager/Command.h" -#include "TraceActivity.h" #include "NavCategory.h" #include "CalculatorButtonUser.h" -static const int maxFunctionSize = (int)CalculationManager::Command::CommandBINEDITEND; - // A trace logging provider can only be instantiated and registered once per module. // This class implements a singleton model ensure that only one instance is created. namespace CalculatorApp @@ -28,12 +24,35 @@ namespace CalculatorApp } }; -public - ref class TraceLogger sealed + public enum class GraphSettingsType + { + Grid, + TrigUnits + }; + + public enum class GraphButton + { + StylePicker, + RemoveFunction, + ActiveTracingChecked, + ActiveTracingUnchecked, + GraphSettings, + Share, + ZoomIn, + ZoomOut, + ZoomReset + }; + + public enum class LineStyleType + { + Color + }; + + public ref class TraceLogger sealed { public: static TraceLogger ^ GetInstance(); - bool GetTraceLoggingProviderEnabled(); + void LogModeChange(CalculatorApp::Common::ViewMode mode); void LogHistoryItemLoad(CalculatorApp::Common::ViewMode mode, int historyListSize, int loadedIndex); void LogMemoryItemLoad(CalculatorApp::Common::ViewMode mode, int memoryListSize, int loadedIndex); @@ -48,9 +67,14 @@ public void LogConverterInputReceived(CalculatorApp::Common::ViewMode mode); void LogNavBarOpened(); void LogError(CalculatorApp::Common::ViewMode mode, Platform::String ^ functionName, Platform::String ^ errorString); - internal : + void LogShowHideButtonClicked(bool isHideButton); + void LogGraphButtonClicked(GraphButton buttonName); + void LogGraphLineStyleChanged(LineStyleType style); + void LogVariableChanged(Platform::String ^ inputChangedType, Platform::String ^ variableName); + void LogVariableSettingsChanged(Platform::String ^ setting); + void LogGraphSettingsChanged(GraphSettingsType settingsType); + internal: void LogStandardException(CalculatorApp::Common::ViewMode mode, std::wstring_view functionName, _In_ const std::exception& e); - void LogWinRTException(CalculatorApp::Common::ViewMode mode, std::wstring_view functionName, _In_ winrt::hresult_error const& e); void LogPlatformException(CalculatorApp::Common::ViewMode mode, std::wstring_view functionName, _In_ Platform::Exception ^ e); void LogInputPasted(CalculatorApp::Common::ViewMode mode); @@ -58,24 +82,8 @@ public // Create an instance of TraceLogger TraceLogger(); - // As mentioned in Microsoft's Privacy Statement(https://privacy.microsoft.com/en-US/privacystatement#maindiagnosticsmodule), - // sampling is involved in Microsoft's diagnostic data collection process. - // These keywords provide additional input into how frequently an event might be sampled. - // The lower the level of the keyword, the higher the possibility that the corresponding event may be sampled. - void LogLevel1Event(std::wstring_view eventName, winrt::Windows::Foundation::Diagnostics::LoggingFields fields); - void LogLevel2Event(std::wstring_view eventName, winrt::Windows::Foundation::Diagnostics::LoggingFields fields); - void LogLevel3Event(std::wstring_view eventName, winrt::Windows::Foundation::Diagnostics::LoggingFields fields); - - std::unique_ptr CreateTraceActivity(std::wstring_view activityName, winrt::Windows::Foundation::Diagnostics::LoggingFields fields); - - winrt::Windows::Foundation::Diagnostics::LoggingChannel g_calculatorProvider; - std::vector buttonLog; std::vector windowIdLog; - - GUID sessionGuid; uint64 currentWindowCount = 0; - - winrt::Windows::Foundation::Diagnostics::LoggingActivity m_appLaunchActivity; }; } diff --git a/src/CalcViewModel/GraphingCalculator/GraphingSettingsViewModel.cpp b/src/CalcViewModel/GraphingCalculator/GraphingSettingsViewModel.cpp index a1031a1..4313e26 100644 --- a/src/CalcViewModel/GraphingCalculator/GraphingSettingsViewModel.cpp +++ b/src/CalcViewModel/GraphingCalculator/GraphingSettingsViewModel.cpp @@ -99,6 +99,8 @@ void GraphingSettingsViewModel::UpdateDisplayRange() } m_Graph->SetDisplayRanges(m_XMinValue, m_XMaxValue, m_YMinValue, m_YMaxValue); + + TraceLogger::GetInstance()->LogGraphSettingsChanged(GraphSettingsType::Grid); } bool GraphingSettingsViewModel::HasError() diff --git a/src/CalcViewModel/GraphingCalculator/GraphingSettingsViewModel.h b/src/CalcViewModel/GraphingCalculator/GraphingSettingsViewModel.h index 60c5e16..cdead6f 100644 --- a/src/CalcViewModel/GraphingCalculator/GraphingSettingsViewModel.h +++ b/src/CalcViewModel/GraphingCalculator/GraphingSettingsViewModel.h @@ -2,6 +2,7 @@ // Licensed under the MIT License. #include "../Common/Utils.h" +#include "CalcViewModel/Common/TraceLogger.h" namespace CalculatorApp::ViewModel { @@ -226,9 +227,12 @@ namespace CalculatorApp::ViewModel if (value && m_Graph != nullptr && m_Graph->TrigUnitMode != (int)Graphing::EvalTrigUnitMode::Radians) { m_Graph->TrigUnitMode = (int)Graphing::EvalTrigUnitMode::Radians; + RaisePropertyChanged(L"TrigModeRadians"); RaisePropertyChanged(L"TrigModeDegrees"); RaisePropertyChanged(L"TrigModeGradians"); + + TraceLogger::GetInstance()->LogGraphSettingsChanged(GraphSettingsType::TrigUnits); } } } @@ -244,9 +248,12 @@ namespace CalculatorApp::ViewModel if (value && m_Graph != nullptr && m_Graph->TrigUnitMode != (int)Graphing::EvalTrigUnitMode::Degrees) { m_Graph->TrigUnitMode = (int)Graphing::EvalTrigUnitMode::Degrees; + RaisePropertyChanged(L"TrigModeDegrees"); RaisePropertyChanged(L"TrigModeRadians"); RaisePropertyChanged(L"TrigModeGradians"); + + TraceLogger::GetInstance()->LogGraphSettingsChanged(GraphSettingsType::TrigUnits); } } } @@ -262,9 +269,12 @@ namespace CalculatorApp::ViewModel if (value && m_Graph != nullptr && m_Graph->TrigUnitMode != (int)Graphing::EvalTrigUnitMode::Grads) { m_Graph->TrigUnitMode = (int)Graphing::EvalTrigUnitMode::Grads; + RaisePropertyChanged(L"TrigModeGradians"); RaisePropertyChanged(L"TrigModeDegrees"); RaisePropertyChanged(L"TrigModeRadians"); + + TraceLogger::GetInstance()->LogGraphSettingsChanged(GraphSettingsType::TrigUnits); } } } diff --git a/src/Calculator.sln b/src/Calculator.sln index 717c6b8..ce6eb3b 100644 --- a/src/Calculator.sln +++ b/src/Calculator.sln @@ -25,6 +25,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GraphingImpl", "GraphingImp EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GraphControl", "GraphControl\GraphControl.vcxproj", "{E727A92B-F149-492C-8117-C039A298719B}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TraceLogging", "TraceLogging\TraceLogging.vcxproj", "{FC81FF41-02CD-4CD9-9BC5-45A1E39AC6ED}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|ARM = Debug|ARM @@ -173,6 +175,22 @@ Global {E727A92B-F149-492C-8117-C039A298719B}.Release|x64.Build.0 = Release|x64 {E727A92B-F149-492C-8117-C039A298719B}.Release|x86.ActiveCfg = Release|Win32 {E727A92B-F149-492C-8117-C039A298719B}.Release|x86.Build.0 = Release|Win32 + {FC81FF41-02CD-4CD9-9BC5-45A1E39AC6ED}.Debug|ARM.ActiveCfg = Debug|ARM + {FC81FF41-02CD-4CD9-9BC5-45A1E39AC6ED}.Debug|ARM.Build.0 = Debug|ARM + {FC81FF41-02CD-4CD9-9BC5-45A1E39AC6ED}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {FC81FF41-02CD-4CD9-9BC5-45A1E39AC6ED}.Debug|ARM64.Build.0 = Debug|ARM64 + {FC81FF41-02CD-4CD9-9BC5-45A1E39AC6ED}.Debug|x64.ActiveCfg = Debug|x64 + {FC81FF41-02CD-4CD9-9BC5-45A1E39AC6ED}.Debug|x64.Build.0 = Debug|x64 + {FC81FF41-02CD-4CD9-9BC5-45A1E39AC6ED}.Debug|x86.ActiveCfg = Debug|Win32 + {FC81FF41-02CD-4CD9-9BC5-45A1E39AC6ED}.Debug|x86.Build.0 = Debug|Win32 + {FC81FF41-02CD-4CD9-9BC5-45A1E39AC6ED}.Release|ARM.ActiveCfg = Release|ARM + {FC81FF41-02CD-4CD9-9BC5-45A1E39AC6ED}.Release|ARM.Build.0 = Release|ARM + {FC81FF41-02CD-4CD9-9BC5-45A1E39AC6ED}.Release|ARM64.ActiveCfg = Release|ARM64 + {FC81FF41-02CD-4CD9-9BC5-45A1E39AC6ED}.Release|ARM64.Build.0 = Release|ARM64 + {FC81FF41-02CD-4CD9-9BC5-45A1E39AC6ED}.Release|x64.ActiveCfg = Release|x64 + {FC81FF41-02CD-4CD9-9BC5-45A1E39AC6ED}.Release|x64.Build.0 = Release|x64 + {FC81FF41-02CD-4CD9-9BC5-45A1E39AC6ED}.Release|x86.ActiveCfg = Release|Win32 + {FC81FF41-02CD-4CD9-9BC5-45A1E39AC6ED}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/Calculator/Calculator.vcxproj b/src/Calculator/Calculator.vcxproj index ae19536..98f041c 100644 --- a/src/Calculator/Calculator.vcxproj +++ b/src/Calculator/Calculator.vcxproj @@ -17,7 +17,7 @@ black Always TemporaryKey.pfx - true + True False @@ -262,6 +262,7 @@ + App.xaml @@ -431,6 +432,7 @@ + Create Create diff --git a/src/Calculator/Calculator.vcxproj.filters b/src/Calculator/Calculator.vcxproj.filters index 5b6e9ec..6365b6f 100644 --- a/src/Calculator/Calculator.vcxproj.filters +++ b/src/Calculator/Calculator.vcxproj.filters @@ -328,6 +328,7 @@ Common + @@ -435,6 +436,7 @@ Common + @@ -1537,5 +1539,7 @@ + + \ No newline at end of file diff --git a/src/Calculator/Controls/EquationTextBox.cpp b/src/Calculator/Controls/EquationTextBox.cpp index 48f84ec..5a607eb 100644 --- a/src/Calculator/Controls/EquationTextBox.cpp +++ b/src/Calculator/Controls/EquationTextBox.cpp @@ -27,6 +27,7 @@ DEPENDENCY_PROPERTY_INITIALIZATION(EquationTextBox, EquationButtonContentIndex); DEPENDENCY_PROPERTY_INITIALIZATION(EquationTextBox, HasError); DEPENDENCY_PROPERTY_INITIALIZATION(EquationTextBox, IsAddEquationMode); DEPENDENCY_PROPERTY_INITIALIZATION(EquationTextBox, MathEquation); +DEPENDENCY_PROPERTY_INITIALIZATION(EquationTextBox, IsEquationLineDisabled); EquationTextBox::EquationTextBox() { @@ -69,9 +70,8 @@ void EquationTextBox::OnApplyTemplate() auto toolTip = ref new ToolTip(); auto equationButtonMessage = LocalizationStringUtil::GetLocalizedString( - m_equationButton->IsChecked->Value ? resProvider->GetResourceString(L"showEquationButtonToolTip") - : resProvider->GetResourceString(L"hideEquationButtonToolTip"), - EquationButtonContentIndex); + IsEquationLineDisabled ? resProvider->GetResourceString(L"showEquationButtonToolTip") + : resProvider->GetResourceString(L"hideEquationButtonToolTip"), EquationButtonContentIndex); toolTip->Content = equationButtonMessage; ToolTipService::SetToolTip(m_equationButton, toolTip); @@ -238,9 +238,8 @@ void EquationTextBox::OnEquationButtonClicked(Object ^ sender, RoutedEventArgs ^ auto resProvider = AppResourceProvider::GetInstance(); auto equationButtonMessage = LocalizationStringUtil::GetLocalizedString( - m_equationButton->IsChecked->Value ? resProvider->GetResourceString(L"showEquationButtonToolTip") - : resProvider->GetResourceString(L"hideEquationButtonToolTip"), - EquationButtonContentIndex); + IsEquationLineDisabled ? resProvider->GetResourceString(L"showEquationButtonToolTip") + : resProvider->GetResourceString(L"hideEquationButtonToolTip"), EquationButtonContentIndex); toolTip->Content = equationButtonMessage; ToolTipService::SetToolTip(m_equationButton, toolTip); @@ -269,9 +268,11 @@ void EquationTextBox::OnRemoveButtonClicked(Object ^ sender, RoutedEventArgs ^ e if (m_equationButton) { - m_equationButton->IsChecked = false; + IsEquationLineDisabled = false; } + TraceLogger::GetInstance()->LogGraphButtonClicked(GraphButton::RemoveFunction); + VisualStateManager::GoToState(this, "Normal", true); } @@ -280,6 +281,7 @@ void EquationTextBox::OnColorChooserButtonClicked(Object ^ sender, RoutedEventAr if (ColorChooserFlyout != nullptr && m_richEditBox != nullptr) { ColorChooserFlyout->ShowAt(m_richEditBox); + TraceLogger::GetInstance()->LogGraphButtonClicked(GraphButton::StylePicker); } } diff --git a/src/Calculator/Controls/EquationTextBox.h b/src/Calculator/Controls/EquationTextBox.h index 1a5e881..cb768a6 100644 --- a/src/Calculator/Controls/EquationTextBox.h +++ b/src/Calculator/Controls/EquationTextBox.h @@ -6,6 +6,7 @@ #include "CalcViewModel/Common/Utils.h" #include "CalcViewModel/GraphingCalculator/EquationViewModel.h" #include "Calculator/Controls/MathRichEditBox.h" +#include "CalcViewModel/Common/TraceLogger.h" namespace CalculatorApp { @@ -24,6 +25,7 @@ namespace CalculatorApp DEPENDENCY_PROPERTY(Platform::String ^, MathEquation); DEPENDENCY_PROPERTY_WITH_CALLBACK(bool, HasError); DEPENDENCY_PROPERTY_WITH_CALLBACK(bool, IsAddEquationMode); + DEPENDENCY_PROPERTY(bool, IsEquationLineDisabled); PROPERTY_R(bool, HasFocus); diff --git a/src/Calculator/EquationStylePanelControl.xaml.cpp b/src/Calculator/EquationStylePanelControl.xaml.cpp index e143d07..f35861b 100644 --- a/src/Calculator/EquationStylePanelControl.xaml.cpp +++ b/src/Calculator/EquationStylePanelControl.xaml.cpp @@ -41,6 +41,8 @@ void EquationStylePanelControl::SelectionChanged(Object ^ /*sender */, Selection { SelectedColor = brush->Color; } + + TraceLogger::GetInstance()->LogGraphLineStyleChanged(LineStyleType::Color); } } diff --git a/src/Calculator/EquationStylePanelControl.xaml.h b/src/Calculator/EquationStylePanelControl.xaml.h index b3c3aab..4876e7b 100644 --- a/src/Calculator/EquationStylePanelControl.xaml.h +++ b/src/Calculator/EquationStylePanelControl.xaml.h @@ -5,6 +5,7 @@ #include "EquationStylePanelControl.g.h" #include "CalcViewModel/Common/Utils.h" +#include "CalcViewModel/Common/TraceLogger.h" namespace CalculatorApp { diff --git a/src/Calculator/Utils/DispatcherTimerDelayer.cpp b/src/Calculator/Utils/DispatcherTimerDelayer.cpp new file mode 100644 index 0000000..219b416 --- /dev/null +++ b/src/Calculator/Utils/DispatcherTimerDelayer.cpp @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "pch.h" +#include "DispatcherTimerDelayer.h" + +using namespace CalculatorApp; +using namespace Windows::UI::Xaml; +using namespace Windows::Foundation; + +DispatcherTimerDelayer::DispatcherTimerDelayer(TimeSpan timeSpan) +{ + m_timer = ref new DispatcherTimer(); + m_timer->Interval = timeSpan; + auto interval = m_timer->Interval; + m_timer->Tick += ref new EventHandler(this, &DispatcherTimerDelayer::Timer_Tick); +} + +void DispatcherTimerDelayer::Timer_Tick(Object ^ sender, Object ^ e) +{ + m_timer->Stop(); + Action(this, nullptr); +} + +void DispatcherTimerDelayer::Start() +{ + m_timer->Start(); +} + +void DispatcherTimerDelayer::ResetAndStart() +{ + m_timer->Stop(); + m_timer->Start(); +} + +void DispatcherTimerDelayer::Stop() +{ + m_timer->Stop(); +} diff --git a/src/Calculator/Utils/DispatcherTimerDelayer.h b/src/Calculator/Utils/DispatcherTimerDelayer.h new file mode 100644 index 0000000..8b47918 --- /dev/null +++ b/src/Calculator/Utils/DispatcherTimerDelayer.h @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "pch.h" + +namespace CalculatorApp +{ + public ref class DispatcherTimerDelayer sealed + { + public: + DispatcherTimerDelayer(Windows::Foundation::TimeSpan timeSpan); + + void Start(); + void ResetAndStart(); + void Stop(); + + event Windows::Foundation::EventHandler ^ Action; + + private: + void Timer_Tick(Platform::Object ^ sender, Platform::Object ^ e); + + Windows::UI::Xaml::DispatcherTimer ^ m_timer; + }; +} diff --git a/src/Calculator/Views/Calculator.xaml.cpp b/src/Calculator/Views/Calculator.xaml.cpp index af854d6..b272740 100644 --- a/src/Calculator/Views/Calculator.xaml.cpp +++ b/src/Calculator/Views/Calculator.xaml.cpp @@ -150,7 +150,6 @@ void Calculator::OnLoaded(_In_ Object ^, _In_ RoutedEventArgs ^) Platform::String ^ Calculator::GetCurrentLayoutState() { - if (IsProgrammer) { return L"Programmer"; @@ -195,7 +194,7 @@ void Calculator::UpdateViewState() void Calculator::AnimateCalculator(bool resultAnimate) { - static auto uiSettings = ref new UISettings(); + static auto uiSettings = ref new UISettings(); if (uiSettings->AnimationsEnabled) { m_doAnimate = true; @@ -703,6 +702,11 @@ void Calculator::OnMemoryAccessKeyInvoked(_In_ UIElement ^ sender, _In_ AccessKe void CalculatorApp::Calculator::OnVisualStateChanged(Platform::Object ^ sender, Windows::UI::Xaml::VisualStateChangedEventArgs ^ e) { + if (!IsStandard && !IsScientific && !IsProgrammer) + { + return; + } + auto mode = IsStandard ? ViewMode::Standard : IsScientific ? ViewMode::Scientific : ViewMode::Programmer; TraceLogger::GetInstance()->LogVisualStateChanged(mode, e->NewState->Name, IsAlwaysOnTop); } diff --git a/src/Calculator/Views/GraphingCalculator/EquationInputArea.xaml b/src/Calculator/Views/GraphingCalculator/EquationInputArea.xaml index 6820754..b2fd608 100644 --- a/src/Calculator/Views/GraphingCalculator/EquationInputArea.xaml +++ b/src/Calculator/Views/GraphingCalculator/EquationInputArea.xaml @@ -15,6 +15,7 @@ + @@ -130,9 +131,11 @@ + VerticalAlignment="Stretch" + IsChecked="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=IsEquationLineDisabled, Mode=TwoWay}"> Source == EquationSubmissionSource::FOCUS_LOST && submission->HasTextChanged && eq->Expression != nullptr && eq->Expression->Length() > 0)) { + eq->IsLineEnabled = true; unsigned int index = 0; if (Equations->IndexOf(eq, &index)) { @@ -219,6 +220,8 @@ void EquationInputArea::EquationTextBox_EquationButtonClicked(Object ^ sender, R { auto eq = GetViewModelFromEquationTextBox(sender); eq->IsLineEnabled = !eq->IsLineEnabled; + + TraceLogger::GetInstance()->LogShowHideButtonClicked(eq->IsLineEnabled ? false : true); } void EquationInputArea::EquationTextBox_Loaded(Object ^ sender, RoutedEventArgs ^ e) @@ -333,21 +336,25 @@ void EquationInputArea::SubmitTextbox(TextBox ^ sender) { val = validateDouble(sender->Text, variableViewModel->Value); variableViewModel->Value = val; + TraceLogger::GetInstance()->LogVariableChanged(L"ValueTextBox", variableViewModel->Name); } else if (sender->Name == "MinTextBox") { val = validateDouble(sender->Text, variableViewModel->Min); variableViewModel->Min = val; + TraceLogger::GetInstance()->LogVariableSettingsChanged(L"MinTextBox"); } else if (sender->Name == "MaxTextBox") { val = validateDouble(sender->Text, variableViewModel->Max); variableViewModel->Max = val; + TraceLogger::GetInstance()->LogVariableSettingsChanged(L"MaxTextBox"); } else if (sender->Name == "StepTextBox") { val = validateDouble(sender->Text, variableViewModel->Step); variableViewModel->Step = val; + TraceLogger::GetInstance()->LogVariableSettingsChanged(L"StepTextBox"); } else { @@ -419,6 +426,50 @@ void EquationInputArea::EquationTextBox_EquationFormatRequested(Object ^ sender, EquationFormatRequested(sender, e); } +void EquationInputArea::Slider_ValueChanged(Object ^ sender, RangeBaseValueChangedEventArgs ^ e) +{ + if (variableSliders == nullptr) + { + variableSliders = ref new Map(); + } + + auto slider = static_cast(sender); + + // The slider value updates when the user uses the TextBox to change the variable value. + // Check the focus state so that we don't trigger the event when the user used the textbox to change the variable value. + if (slider->FocusState == Windows::UI::Xaml::FocusState::Unfocused) + { + return; + } + + auto variableVM = static_cast(slider->DataContext); + if (variableVM == nullptr) + { + return; + } + + auto name = variableVM->Name; + + if (!variableSliders->HasKey(name)) + { + TimeSpan timeSpan; + timeSpan.Duration = 10000000; // The duration is 1 second. TimeSpan durations are expressed in 100 nanosecond units. + DispatcherTimerDelayer ^ delayer = ref new DispatcherTimerDelayer(timeSpan); + delayer->Action += ref new EventHandler([this, name](Platform::Object ^ sender, Platform::Object ^ e) { + TraceLogger::GetInstance()->LogVariableChanged("Slider", name); + variableSliders->Remove(name); + }); + delayer->Start(); + variableSliders->Insert(name, delayer); + } + + else + { + auto delayer = variableSliders->Lookup(name); + delayer->ResetAndStart(); + } +} + EquationViewModel ^ EquationInputArea::GetViewModelFromEquationTextBox(Object ^ sender) { auto tb = static_cast(sender); diff --git a/src/Calculator/Views/GraphingCalculator/EquationInputArea.xaml.h b/src/Calculator/Views/GraphingCalculator/EquationInputArea.xaml.h index bc86845..ac30b58 100644 --- a/src/Calculator/Views/GraphingCalculator/EquationInputArea.xaml.h +++ b/src/Calculator/Views/GraphingCalculator/EquationInputArea.xaml.h @@ -12,6 +12,8 @@ #include "Controls/EquationTextBox.h" #include "Converters/BooleanNegationConverter.h" #include "Controls/MathRichEditBox.h" +#include "CalcViewModel/Common/TraceLogger.h" +#include "Utils/DispatcherTimerDelayer.h" namespace CalculatorApp { @@ -36,7 +38,6 @@ public static Windows::UI::Xaml::Media::SolidColorBrush ^ ToSolidColorBrush(Windows::UI::Color color) { return ref new Windows::UI::Xaml::Media::SolidColorBrush(color); } - private: void OnPropertyChanged(Platform::String ^ propertyName); void OnEquationsPropertyChanged(); @@ -65,6 +66,7 @@ public void SubmitTextbox(Windows::UI::Xaml::Controls::TextBox ^ textbox); void VariableAreaTapped(Platform::Object ^ sender, Windows::UI::Xaml::Input::TappedRoutedEventArgs ^ e); void EquationTextBox_EquationFormatRequested(Platform::Object ^ sender, CalculatorApp::Controls::MathRichEditBoxFormatRequest ^ e); + void Slider_ValueChanged(Platform::Object ^ sender, Windows::UI::Xaml::Controls::Primitives::RangeBaseValueChangedEventArgs ^ e); CalculatorApp::ViewModel::EquationViewModel ^ GetViewModelFromEquationTextBox(Platform::Object ^ sender); @@ -72,5 +74,6 @@ public int m_lastLineColorIndex; int m_lastFunctionLabelIndex; ViewModel::EquationViewModel ^ m_equationToFocus; + Platform::Collections::Map ^ variableSliders; }; } diff --git a/src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml b/src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml index 432b6bc..4682c27 100644 --- a/src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml +++ b/src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml @@ -390,7 +390,7 @@ MaxWidth="420"/> - + diff --git a/src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml.cpp b/src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml.cpp index 0a64613..1a2096f 100644 --- a/src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml.cpp +++ b/src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml.cpp @@ -217,6 +217,7 @@ void CalculatorApp::GraphingCalculator::OnShareClick(Platform::Object ^ sender, { // Ask the OS to start a share action. DataTransferManager::ShowShareUI(); + TraceLogger::GetInstance()->LogGraphButtonClicked(GraphButton::Share); } // When share is invoked (by the user or programmatically) the event handler we registered will be called to populate the data package with the @@ -348,16 +349,19 @@ void GraphingCalculator::OnVariableChanged(Platform::Object ^ sender, VariableCh void GraphingCalculator::OnZoomInCommand(Object ^ /* parameter */) { GraphingControl->ZoomFromCenter(zoomInScale); + TraceLogger::GetInstance()->LogGraphButtonClicked(GraphButton::ZoomIn); } void GraphingCalculator::OnZoomOutCommand(Object ^ /* parameter */) { GraphingControl->ZoomFromCenter(zoomOutScale); + TraceLogger::GetInstance()->LogGraphButtonClicked(GraphButton::ZoomOut); } void GraphingCalculator::OnZoomResetCommand(Object ^ /* parameter */) { GraphingControl->ResetGrid(); + TraceLogger::GetInstance()->LogGraphButtonClicked(GraphButton::ZoomReset); } String ^ GraphingCalculator::GetTracingLegend(Platform::IBox ^ isTracing) @@ -525,6 +529,7 @@ void CalculatorApp::GraphingCalculator::ActiveTracing_Checked(Platform::Object ^ KeyboardShortcutManager::IgnoreEscape(false); TracePointer->Visibility = ::Visibility::Visible; + TraceLogger::GetInstance()->LogGraphButtonClicked(GraphButton::ActiveTracingChecked); } void CalculatorApp::GraphingCalculator::ActiveTracing_Unchecked(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e) @@ -543,6 +548,7 @@ void CalculatorApp::GraphingCalculator::ActiveTracing_Unchecked(Platform::Object KeyboardShortcutManager::HonorEscape(); TracePointer->Visibility = ::Visibility::Collapsed; + TraceLogger::GetInstance()->LogGraphButtonClicked(GraphButton::ActiveTracingUnchecked); } void CalculatorApp::GraphingCalculator::ActiveTracing_KeyUp(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Core::KeyEventArgs ^ args) @@ -557,6 +563,7 @@ void CalculatorApp::GraphingCalculator::ActiveTracing_KeyUp(Windows::UI::Core::C void GraphingCalculator::GraphSettingsButton_Click(Object ^ sender, RoutedEventArgs ^ e) { DisplayGraphSettings(); + TraceLogger::GetInstance()->LogGraphButtonClicked(GraphButton::GraphSettings); } void GraphingCalculator::DisplayGraphSettings() @@ -676,3 +683,8 @@ void GraphingCalculator::GraphMenuFlyoutItem_Click(Object ^ sender, RoutedEventA dataPackage->SetBitmap(bitmapStream); ::Clipboard::SetContent(dataPackage); } + +void GraphingCalculator::OnVisualStateChanged(Object ^ sender, VisualStateChangedEventArgs ^ e) +{ + TraceLogger::GetInstance()->LogVisualStateChanged(ViewMode::Graphing, e->NewState->Name, false); +} diff --git a/src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml.h b/src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml.h index e1662cc..9810ce8 100644 --- a/src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml.h +++ b/src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml.h @@ -9,6 +9,7 @@ #include "Views\GraphingCalculator\KeyGraphFeaturesPanel.xaml.h" #include "Views\GraphingCalculator\GraphingNumPad.xaml.h" #include "Views\GraphingCalculator\GraphingSettings.xaml.h" +#include "CalcViewModel/Common/TraceLogger.h" namespace CalculatorApp { @@ -97,6 +98,7 @@ public ref class GraphingCalculator sealed : public Windows::UI::Xaml::Data::INo void OnHighContrastChanged(Windows::UI::ViewManagement::AccessibilitySettings ^ sender, Platform::Object ^ args); void OnEquationFormatRequested(Platform::Object ^ sender, CalculatorApp::Controls::MathRichEditBoxFormatRequest ^ e); void GraphMenuFlyoutItem_Click(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e); + void OnVisualStateChanged(Platform::Object ^ sender, Windows::UI::Xaml::VisualStateChangedEventArgs ^ e); }; } diff --git a/src/Calculator/Views/GraphingCalculator/GraphingNumPad.xaml.cpp b/src/Calculator/Views/GraphingCalculator/GraphingNumPad.xaml.cpp index d3235af..5c2fb55 100644 --- a/src/Calculator/Views/GraphingCalculator/GraphingNumPad.xaml.cpp +++ b/src/Calculator/Views/GraphingCalculator/GraphingNumPad.xaml.cpp @@ -203,6 +203,7 @@ void GraphingNumPad::Button_Clicked(Platform::Object ^ sender, DependencyPropert if (mathRichEdit != nullptr && sender != nullptr) { auto id = button->ButtonId; + TraceLogger::GetInstance()->UpdateButtonUsage(id, CalculatorApp::Common::ViewMode::Graphing); auto output = buttonOutput.find(id); mathRichEdit->InsertText(std::get<0>(output->second), std::get<1>(output->second), std::get<2>(output->second)); } @@ -214,6 +215,7 @@ void GraphingNumPad::SubmitButton_Clicked(Platform::Object ^ /*sender*/, RoutedE if (mathRichEdit != nullptr) { mathRichEdit->SubmitEquation(CalculatorApp::Controls::EquationSubmissionSource::ENTER_KEY); + TraceLogger::GetInstance()->UpdateButtonUsage(NumbersAndOperatorsEnum::Submit, CalculatorApp::Common::ViewMode::Graphing); } } @@ -224,6 +226,7 @@ void GraphingNumPad::ClearButton_Clicked(Platform::Object ^ /*sender*/, RoutedEv { mathRichEdit->MathText = L""; mathRichEdit->SubmitEquation(CalculatorApp::Controls::EquationSubmissionSource::PROGRAMMATIC); + TraceLogger::GetInstance()->UpdateButtonUsage(NumbersAndOperatorsEnum::Clear, CalculatorApp::Common::ViewMode::Graphing); } } @@ -233,6 +236,7 @@ void GraphingNumPad::BackSpaceButton_Clicked(Platform::Object ^ /*sender*/, Rout if (mathRichEdit != nullptr) { mathRichEdit->BackSpace(); + TraceLogger::GetInstance()->UpdateButtonUsage(NumbersAndOperatorsEnum::Backspace, CalculatorApp::Common::ViewMode::Graphing); } } diff --git a/src/Calculator/Views/GraphingCalculator/GraphingNumPad.xaml.h b/src/Calculator/Views/GraphingCalculator/GraphingNumPad.xaml.h index 37ec8a3..35f4d78 100644 --- a/src/Calculator/Views/GraphingCalculator/GraphingNumPad.xaml.h +++ b/src/Calculator/Views/GraphingCalculator/GraphingNumPad.xaml.h @@ -7,6 +7,7 @@ #include "CalcViewModel/GraphingCalculator/GraphingCalculatorViewModel.h" #include "Views/GraphingCalculator/EquationInputArea.xaml.h" #include "CalcViewModel/Common/CalculatorButtonUser.h" +#include "CalcViewModel/Common/TraceLogger.h" namespace CalculatorApp { diff --git a/src/Calculator/pch.h b/src/Calculator/pch.h index 4bf2fe6..13812fe 100644 --- a/src/Calculator/pch.h +++ b/src/Calculator/pch.h @@ -41,6 +41,7 @@ #include "winrt/Windows.System.UserProfile.h" #include "winrt/Windows.UI.ViewManagement.h" #include "winrt/Windows.UI.Xaml.h" +#include "winrt/Windows.Foundation.h" // Project Headers #include "App.xaml.h" diff --git a/src/GraphControl/Control/Grapher.cpp b/src/GraphControl/Control/Grapher.cpp index a1fca8e..4696cba 100644 --- a/src/GraphControl/Control/Grapher.cpp +++ b/src/GraphControl/Control/Grapher.cpp @@ -197,7 +197,16 @@ namespace GraphControl return; } - PlotGraph(true); + bool keepCurrentView = true; + + // If the equation has changed, the IsLineEnabled state is reset. + // This checks if the equation has been reset and sets keepCurrentView to false in this case. + if (!equation->HasGraphError && !equation->IsValidated && equation->IsLineEnabled) + { + keepCurrentView = false; + } + + PlotGraph(keepCurrentView); } KeyGraphFeaturesInfo ^ Grapher::AnalyzeEquation(Equation ^ equation) @@ -254,6 +263,25 @@ namespace GraphControl } } + int valid = 0; + int invalid = 0; + for (Equation ^ eq : Equations) + { + if (eq->HasGraphError) + { + invalid++; + } + if (eq->IsValidated) + { + valid++; + } + } + if (!m_trigUnitsChanged) + { + TraceLogger::GetInstance()->LogEquationCountChanged(valid, invalid); + } + + m_trigUnitsChanged = false; GraphPlottedEvent(this, ref new RoutedEventArgs()); } @@ -457,6 +485,11 @@ namespace GraphControl } } + if (Variables->Size != updatedVariables->Size) + { + TraceLogger::GetInstance()->LogVariableCountChanged(updatedVariables->Size); + } + Variables = updatedVariables; VariablesUpdated(this, Variables); } @@ -968,6 +1001,7 @@ optional>> Grapher::TryInitializeGraph(bo m_graph->GetRenderer()->GetDisplayRanges(xMin, xMax, yMin, yMax); auto initResult = m_graph->TryInitialize(graphingExp); m_graph->GetRenderer()->SetDisplayRanges(xMin, xMax, yMin, yMax); + return initResult; } else diff --git a/src/GraphControl/Control/Grapher.h b/src/GraphControl/Control/Grapher.h index e6cdedf..3cbaf1d 100644 --- a/src/GraphControl/Control/Grapher.h +++ b/src/GraphControl/Control/Grapher.h @@ -12,6 +12,7 @@ #include "Common.h" #include "Models/KeyGraphFeaturesInfo.h" #include +#include "Logger/TraceLogger.h" namespace GraphControl { @@ -126,6 +127,7 @@ public if (value != (int)m_solver->EvalOptions().GetTrigUnitMode()) { m_solver->EvalOptions().SetTrigUnitMode((Graphing::EvalTrigUnitMode)value); + m_trigUnitsChanged = true; PlotGraph(true); } } @@ -296,6 +298,7 @@ public void SetEquationsAsValid(); void SetEquationErrors(); std::optional>> TryInitializeGraph(bool keepCurrentView, _In_ const Graphing::IExpression* graphingExp = nullptr); + private: DX::RenderMain ^ m_renderMain = nullptr; @@ -317,6 +320,7 @@ public const std::shared_ptr m_graph; bool m_calculatedForceProportional = false; bool m_tracingTracking; + bool m_trigUnitsChanged; enum KeysPressedSlots { Left, diff --git a/src/GraphControl/GraphControl.vcxproj b/src/GraphControl/GraphControl.vcxproj index 460cbdc..0cf32b1 100644 --- a/src/GraphControl/GraphControl.vcxproj +++ b/src/GraphControl/GraphControl.vcxproj @@ -283,12 +283,18 @@ $(GraphingImplLibDir);%(AdditionalLibraryDirectories) + + + /DSEND_DIAGNOSTICS %(AdditionalOptions) + + + @@ -301,6 +307,7 @@ + @@ -322,6 +329,11 @@ {52E03A58-B378-4F50-8BFB-F659FB85E790} + + + {fc81ff41-02cd-4cd9-9bc5-45a1e39ac6ed} + + \ No newline at end of file diff --git a/src/GraphControl/GraphControl.vcxproj.filters b/src/GraphControl/GraphControl.vcxproj.filters index 2b7c4e9..e9d9d8f 100644 --- a/src/GraphControl/GraphControl.vcxproj.filters +++ b/src/GraphControl/GraphControl.vcxproj.filters @@ -32,6 +32,7 @@ Models + @@ -59,6 +60,7 @@ Models + @@ -66,9 +68,8 @@ - - - + + diff --git a/src/GraphControl/Logger/TraceLogger.cpp b/src/GraphControl/Logger/TraceLogger.cpp new file mode 100644 index 0000000..8654f2e --- /dev/null +++ b/src/GraphControl/Logger/TraceLogger.cpp @@ -0,0 +1,89 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "pch.h" +#include "TraceLogger.h" + +using namespace TraceLogging; +using namespace Concurrency; +using namespace std; +using namespace Platform; +using namespace Windows::Foundation; +using namespace Windows::Foundation::Diagnostics; +using namespace Windows::Globalization; + +namespace GraphControl +{ + static reader_writer_lock s_traceLoggerLock; + + constexpr auto GRAPHING_MODE = L"Graphing"; + constexpr auto CALC_MODE = L"CalcMode"; + + // Diagnostics events. Uploaded to asimov. + constexpr auto EVENT_NAME_EQUATION_COUNT_CHANGED = L"EquationCountChanged"; + constexpr auto EVENT_NAME_FUNCTION_ANALYSIS_PERFORMED = L"FunctionAnalysisPerformed"; + constexpr auto EVENT_NAME_VARIABLES_COUNT_CHANGED = L"VariablesCountChanged"; + + TraceLogger ^ TraceLogger::GetInstance() + { + static TraceLogger ^ s_selfInstance = ref new TraceLogger(); + return s_selfInstance; + } + + void TraceLogger::LogEquationCountChanged(int currentValidEquations, int currentInvalidEquations) + { + static bool firstRun = true; + if (firstRun) + { + firstRun = false; + return; + } + + // Update the total valid/invalid equations to record the max value. + // Equations are added/removed/updated one at a time, so we know either + // currentValidEquations or currentInvalidEquations increased, + // but they cannot both increase at the same time + // If an equation was removed, do not decrement the total count. + static uint64 TotalValidEquations = 0; + static uint64 TotalInvalidEquations = 0; + static uint64 PreviousValidEquations = 0; + static uint64 PreviousInvalidEquations = 0; + + if (currentValidEquations > PreviousValidEquations) + { + TotalValidEquations++; + } + else if (currentInvalidEquations > PreviousInvalidEquations) + { + TotalInvalidEquations++; + } + + PreviousValidEquations = currentValidEquations; + PreviousInvalidEquations = currentInvalidEquations; + + auto fields = ref new LoggingFields(); + fields->AddString(StringReference(CALC_MODE), StringReference(GRAPHING_MODE)); + fields->AddUInt64(StringReference(L"ConcurrentValidFunctions"), currentValidEquations); + fields->AddUInt64(StringReference(L"ConcurrentInvalidFunctions"), currentInvalidEquations); + fields->AddUInt64(StringReference(L"TotalValidFunctions"), TotalValidEquations); + fields->AddUInt64(StringReference(L"TotalInvalidFunctions"), TotalInvalidEquations); + TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_EQUATION_COUNT_CHANGED), fields); + } + + void TraceLogger::LogFunctionAnalysisPerformed(int analysisErrorType, uint32 tooComplexFlag) + { + auto fields = ref new LoggingFields(); + fields->AddString(StringReference(CALC_MODE), StringReference(GRAPHING_MODE)); + fields->AddInt32(StringReference(L"AnalysisErrorType"), analysisErrorType); + fields->AddUInt32(StringReference(L"TooComplexFeatures"), tooComplexFlag); + TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_FUNCTION_ANALYSIS_PERFORMED), fields); + } + + void TraceLogger::LogVariableCountChanged(int variablesCount) + { + auto fields = ref new LoggingFields(); + fields->AddString(StringReference(CALC_MODE), StringReference(GRAPHING_MODE)); + fields->AddInt64(StringReference(L"VariableCount"), variablesCount); + TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_VARIABLES_COUNT_CHANGED), fields); + } +} diff --git a/src/GraphControl/Logger/TraceLogger.h b/src/GraphControl/Logger/TraceLogger.h new file mode 100644 index 0000000..682c668 --- /dev/null +++ b/src/GraphControl/Logger/TraceLogger.h @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "Common.h" + +// A trace logging provider can only be instantiated and registered once per module. +// This class implements a singleton model ensure that only one instance is created. +namespace GraphControl +{ + + public ref class TraceLogger sealed + { + internal: + static TraceLogger ^ GetInstance(); + + void LogEquationCountChanged(int currentValidEquations, int currentInvalidEquations); + void LogFunctionAnalysisPerformed(int analysisErrorType, uint32 tooComplexFlag); + void LogVariableCountChanged(int variablesCount); + + private: + TraceLogger() + { + } + }; +} diff --git a/src/GraphControl/Models/KeyGraphFeaturesInfo.cpp b/src/GraphControl/Models/KeyGraphFeaturesInfo.cpp index 3d5a7d2..ca48f5c 100644 --- a/src/GraphControl/Models/KeyGraphFeaturesInfo.cpp +++ b/src/GraphControl/Models/KeyGraphFeaturesInfo.cpp @@ -59,6 +59,8 @@ KeyGraphFeaturesInfo ^ KeyGraphFeaturesInfo::Create(IGraphFunctionAnalysisData d res->ObliqueAsymptotes = ConvertWStringVector(data.ObliqueAsymptotes); res->TooComplexFeatures = data.TooComplexFeatures; res->AnalysisError = CalculatorApp::AnalysisErrorType::NoError; + + TraceLogger::GetInstance()->LogFunctionAnalysisPerformed(CalculatorApp::AnalysisErrorType::NoError, res->TooComplexFeatures); return res; } @@ -66,5 +68,7 @@ KeyGraphFeaturesInfo ^ KeyGraphFeaturesInfo::Create(CalculatorApp::AnalysisError { auto res = ref new KeyGraphFeaturesInfo(); res->AnalysisError = type; + + TraceLogger::GetInstance()->LogFunctionAnalysisPerformed(type, 0); return res; } diff --git a/src/GraphControl/pch.h b/src/GraphControl/pch.h index 2861384..7906103 100644 --- a/src/GraphControl/pch.h +++ b/src/GraphControl/pch.h @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + #pragma once //C4453: A '[WebHostHidden]' type should not be used on the published surface of a public type that is not '[WebHostHidden]' diff --git a/src/GraphControl/winrtHeaders.h b/src/GraphControl/winrtHeaders.h index 971dfd3..3730cb5 100644 --- a/src/GraphControl/winrtHeaders.h +++ b/src/GraphControl/winrtHeaders.h @@ -3,6 +3,7 @@ #include #include #include +#include #include template diff --git a/src/TraceLogging/TraceLogging.vcxproj b/src/TraceLogging/TraceLogging.vcxproj new file mode 100644 index 0000000..ba0a960 --- /dev/null +++ b/src/TraceLogging/TraceLogging.vcxproj @@ -0,0 +1,294 @@ + + + + + Debug + ARM + + + Debug + ARM64 + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM + + + Release + ARM64 + + + Release + Win32 + + + Release + x64 + + + + {fc81ff41-02cd-4cd9-9bc5-45a1e39ac6ed} + WindowsRuntimeComponent + TraceLogging + en-US + 14.0 + true + Windows Store + 10.0.18362.0 + 10.0.17134.0 + 10.0 + + + + DynamicLibrary + true + v142 + + + DynamicLibrary + true + v142 + + + DynamicLibrary + true + v142 + + + DynamicLibrary + true + v142 + + + DynamicLibrary + false + true + v142 + + + DynamicLibrary + false + true + v142 + + + DynamicLibrary + false + true + v142 + + + DynamicLibrary + false + true + v142 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + false + + + + Use + _WINRT_DLL;%(PreprocessorDefinitions) + pch.h + $(IntDir)pch.pch + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + /bigobj /await /std:c++17 /utf-8 %(AdditionalOptions) + 28204 + + + Console + false + + + + + Use + _WINRT_DLL;NDEBUG;%(PreprocessorDefinitions) + pch.h + $(IntDir)pch.pch + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + /bigobj %(AdditionalOptions) + 28204 + + + Console + false + + + + + Use + _WINRT_DLL;%(PreprocessorDefinitions) + pch.h + $(IntDir)pch.pch + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + /bigobj %(AdditionalOptions) + 28204 + + + Console + false + + + + + Use + _WINRT_DLL;NDEBUG;%(PreprocessorDefinitions) + pch.h + $(IntDir)pch.pch + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + /bigobj %(AdditionalOptions) + 28204 + + + Console + false + + + + + Use + _WINRT_DLL;%(PreprocessorDefinitions) + pch.h + $(IntDir)pch.pch + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + /bigobj %(AdditionalOptions) + 28204 + + + Console + false + + + + + Use + _WINRT_DLL;NDEBUG;%(PreprocessorDefinitions) + pch.h + $(IntDir)pch.pch + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + /bigobj %(AdditionalOptions) + 28204 + + + Console + false + + + + + Use + _WINRT_DLL;%(PreprocessorDefinitions) + pch.h + $(IntDir)pch.pch + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + /bigobj %(AdditionalOptions) + 28204 + + + Console + false + + + + + Use + _WINRT_DLL;NDEBUG;%(PreprocessorDefinitions) + pch.h + $(IntDir)pch.pch + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + /bigobj %(AdditionalOptions) + 28204 + + + Console + false + + + + + /DSEND_DIAGNOSTICS %(AdditionalOptions) + + + + + + + + + Create + Create + Create + Create + Create + Create + Create + Create + + + + + + + \ No newline at end of file diff --git a/src/TraceLogging/TraceLogging.vcxproj.filters b/src/TraceLogging/TraceLogging.vcxproj.filters new file mode 100644 index 0000000..23e4274 --- /dev/null +++ b/src/TraceLogging/TraceLogging.vcxproj.filters @@ -0,0 +1,17 @@ + + + + + 32f35fa0-613c-4f4e-b062-c61ab420e23b + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms + + + + + + + + + + + \ No newline at end of file diff --git a/src/TraceLogging/TraceLoggingCommon.cpp b/src/TraceLogging/TraceLoggingCommon.cpp new file mode 100644 index 0000000..715bb8c --- /dev/null +++ b/src/TraceLogging/TraceLoggingCommon.cpp @@ -0,0 +1,88 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "pch.h" +#include "TraceLoggingCommon.h" + +using namespace TraceLogging; +using namespace std; +using namespace Platform;; +using namespace Windows::Foundation; +using namespace Windows::Foundation::Diagnostics; + +#ifdef SEND_DIAGNOSTICS +// c.f. WINEVENT_KEYWORD_RESERVED_63-56 0xFF00000000000000 // Bits 63-56 - channel keywords +// c.f. WINEVENT_KEYWORD_* 0x00FF000000000000 // Bits 55-48 - system-reserved keywords +constexpr int64_t MICROSOFT_KEYWORD_LEVEL_1 = 0x0000800000000000; // Bit 47 +constexpr int64_t MICROSOFT_KEYWORD_LEVEL_2 = 0x0000400000000000; // Bit 46 +constexpr int64_t MICROSOFT_KEYWORD_LEVEL_3 = 0x0000200000000000; // Bit 45 +#else +// define all Keyword options as 0 when we do not want to upload app diagnostics +constexpr int64_t MICROSOFT_KEYWORD_LEVEL_1 = 0; +constexpr int64_t MICROSOFT_KEYWORD_LEVEL_2 = 0; +constexpr int64_t MICROSOFT_KEYWORD_LEVEL_3 = 0; +#endif + +constexpr auto SESSION_GUID = L"SessionGuid"; +constexpr auto PDT_PRIVACY_DATA_TAG = L"PartA_PrivTags"; +constexpr auto PDT_PRODUCT_AND_SERVICE_USAGE = 0x0000'0000'0200'0000u; + +TraceLoggingCommon::TraceLoggingCommon() + : g_calculatorProvider( + ref new LoggingChannel( + L"MicrosoftCalculator", + ref new LoggingChannelOptions(GUID{ 0x4f50731a, 0x89cf, 0x4782, 0xb3, 0xe0, 0xdc, 0xe8, 0xc9, 0x4, 0x76, 0xba }), + GUID{ 0x905ca09, 0x610e, 0x401e, 0xb6, 0x50, 0x2f, 0x21, 0x29, 0x80, 0xb9, 0xe0 })) + , // Unique providerID {0905CA09-610E-401E-B650-2F212980B9E0} + m_appLaunchActivity{ nullptr } +{ + CoCreateGuid(&sessionGuid); +} + + TraceLoggingCommon ^ TraceLoggingCommon::GetInstance() +{ + static TraceLoggingCommon ^ s_selfInstance = ref new TraceLoggingCommon(); + return s_selfInstance; +} + +bool TraceLoggingCommon::GetTraceLoggingProviderEnabled() +{ + return g_calculatorProvider->Enabled; +} + +void TraceLoggingCommon::LogLevel1Event(String ^ eventName, LoggingFields ^ fields) +{ + if (!GetTraceLoggingProviderEnabled()) + { + return; + } + + fields->AddGuid(ref new String(SESSION_GUID), sessionGuid); + fields->AddUInt64(ref new String(PDT_PRIVACY_DATA_TAG), PDT_PRODUCT_AND_SERVICE_USAGE); + + g_calculatorProvider->LogEvent(eventName, fields, LoggingLevel::Verbose, ref new LoggingOptions(MICROSOFT_KEYWORD_LEVEL_1)); +} + +void TraceLoggingCommon::LogLevel2Event(String ^ eventName, LoggingFields ^ fields) +{ + if (!GetTraceLoggingProviderEnabled()) + { + return; + } + + fields->AddGuid(ref new String(SESSION_GUID), sessionGuid); + fields->AddUInt64(ref new String(PDT_PRIVACY_DATA_TAG), PDT_PRODUCT_AND_SERVICE_USAGE); + g_calculatorProvider->LogEvent(eventName, fields, LoggingLevel::Verbose, ref new LoggingOptions(MICROSOFT_KEYWORD_LEVEL_2)); +} + +void TraceLoggingCommon::LogLevel3Event(String ^ eventName, LoggingFields ^ fields) +{ + if (!GetTraceLoggingProviderEnabled()) + { + return; + } + + fields->AddGuid(ref new String(SESSION_GUID), sessionGuid); + fields->AddUInt64(ref new String(PDT_PRIVACY_DATA_TAG), PDT_PRODUCT_AND_SERVICE_USAGE); + g_calculatorProvider->LogEvent(eventName, fields, LoggingLevel::Verbose, ref new LoggingOptions(MICROSOFT_KEYWORD_LEVEL_3)); +} diff --git a/src/TraceLogging/TraceLoggingCommon.h b/src/TraceLogging/TraceLoggingCommon.h new file mode 100644 index 0000000..c81253d --- /dev/null +++ b/src/TraceLogging/TraceLoggingCommon.h @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +namespace TraceLogging +{ + public ref class TraceLoggingCommon sealed + { + public: + static TraceLoggingCommon ^ GetInstance(); + + // As mentioned in Microsoft's Privacy Statement(https://privacy.microsoft.com/en-US/privacystatement#maindiagnosticsmodule), + // sampling is involved in Microsoft's diagnostic data collection process. + // These keywords provide additional input into how frequently an event might be sampled. + // The lower the level of the keyword, the higher the possibility that the corresponding event may be sampled. + void LogLevel1Event(Platform::String ^ eventName, Windows::Foundation::Diagnostics::LoggingFields ^ fields); + void LogLevel2Event(Platform::String ^ eventName, Windows::Foundation::Diagnostics::LoggingFields ^ fields); + void LogLevel3Event(Platform::String ^ eventName, Windows::Foundation::Diagnostics::LoggingFields ^ fields); + + bool GetTraceLoggingProviderEnabled(); + + private: + TraceLoggingCommon(); + + + Windows::Foundation::Diagnostics::LoggingChannel ^ g_calculatorProvider; + Windows::Foundation::Diagnostics::LoggingActivity ^ m_appLaunchActivity; + GUID sessionGuid; + }; +} diff --git a/src/TraceLogging/pch.cpp b/src/TraceLogging/pch.cpp new file mode 100644 index 0000000..b175e3f --- /dev/null +++ b/src/TraceLogging/pch.cpp @@ -0,0 +1,4 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "pch.h" diff --git a/src/TraceLogging/pch.h b/src/TraceLogging/pch.h new file mode 100644 index 0000000..f1d2ac3 --- /dev/null +++ b/src/TraceLogging/pch.h @@ -0,0 +1,10 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include +#include + +// C++\WinRT Headers +#include "Windows.Foundation.Diagnostics.h"