diff --git a/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/AzPredictorTelemetryTests.cs b/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/AzPredictorTelemetryTests.cs index b652256f759c..32b179f9eaa8 100644 --- a/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/AzPredictorTelemetryTests.cs +++ b/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/AzPredictorTelemetryTests.cs @@ -623,7 +623,13 @@ public async Task VerifyOnCommandLineAcceptedException() [InlineData("start_of_snippet", @"-StorageAccountKey""xxx""New-AzStorageContainer -context xxx")] [InlineData("start_of_snippet", @"New-AzureStorageContext-StorageAccountName ""xxx"" -StorageAccountKey ""xxx""")] [InlineData("start_of_snippet", @"sig=xxxxxxxxxxx/Sensor-Azure")] + [InlineData("start_of_snippet", @"sig=xxxxxxxxxxx/Get-az")] [InlineData("start_of_snippet", @"sig=Signature/Test-Sensor-Azu")] + [InlineData("start_of_snippet", @"sig=Signature/Set-azstorage")] + [InlineData("start_of_snippet", "New-AzStorage\"key=value\"")] + [InlineData("start_of_snippet", "New-az\\\"key=value\\\"")] + [InlineData("start_of_snippet", "git")] + [InlineData("start_of_snippet", "Get-Key -Key abcd")] public void VerifyUserInputInGetSuggestionEvent(string expectedUserInput, string input) { var expectedTelemetryCount = 1; @@ -637,8 +643,8 @@ public void VerifyUserInputInGetSuggestionEvent(string expectedUserInput, string Assert.EndsWith("Aggregation", telemetryClient.RecordedTelemetry[0].EventName); var suggestionSessions = JsonSerializer.Deserialize>>(telemetryClient.RecordedTelemetry[0].Properties[GetSuggestionTelemetryData.PropertyNamePrediction]); - Assert.Equal(expectedUserInput, ((JsonElement)(suggestionSessions[0][GetSuggestionTelemetryData.PropertyNameUserInput])).GetString()); - Assert.Equal(expectedUserInput, telemetryClient.RecordedTelemetry[0].Properties[GetSuggestionTelemetryData.PropertyNameUserInput]); + Assert.Equal(expectedUserInput, ((JsonElement)(suggestionSessions[0][GetSuggestionTelemetryData.PropertyNameInnerUserInput])).GetString()); + Assert.Equal(expectedUserInput, telemetryClient.RecordedTelemetry[0].Properties[GetSuggestionTelemetryData.PropertyNameOuterUserInput]); } /// @@ -678,7 +684,7 @@ public void VerifySeparateUserInput() VerifyTelemetryDispatchCount(expectedTelemetryCount, telemetryClient); Assert.EndsWith("Aggregation", telemetryClient.RecordedTelemetry[0].EventName); - Assert.Equal(string.Join(AzPredictorTelemetryClient._StringValueConcatenator, expectedUserInputValue), telemetryClient.RecordedTelemetry[0].Properties[GetSuggestionTelemetryData.PropertyNameUserInput]); + Assert.Equal(string.Join(AzPredictorTelemetryClient._StringValueConcatenator, expectedUserInputValue), telemetryClient.RecordedTelemetry[0].Properties[GetSuggestionTelemetryData.PropertyNameOuterUserInput]); } /// @@ -703,7 +709,7 @@ private void VerifySameSuggestionSessionId() Assert.EndsWith("Aggregation", telemetryClient.RecordedTelemetry[0].EventName); Assert.Equal(MockObjects.PredictionClient.Name, telemetryClient.RecordedTelemetry[0].Properties["ClientId"]); var suggestionSessions = JsonSerializer.Deserialize>>(telemetryClient.RecordedTelemetry[0].Properties[GetSuggestionTelemetryData.PropertyNamePrediction]); - Assert.Equal("Clear-Content -Filter *** -Path ***", ((JsonElement)(suggestionSessions[0][GetSuggestionTelemetryData.PropertyNameUserInput])).GetString()); + Assert.Equal("Clear-Content -Filter *** -Path ***", ((JsonElement)(suggestionSessions[0][GetSuggestionTelemetryData.PropertyNameInnerUserInput])).GetString()); Assert.Equal(1, ((JsonElement)suggestionSessions[0][GetSuggestionTelemetryData.PropertyNameFound]).GetArrayLength()); var displayCountOrIndex = 3; @@ -870,7 +876,7 @@ public void VerifyExceptionInGetSuggestion() Assert.EndsWith("Exception", telemetryClient.RecordedTelemetry[0].EventName); Assert.Equal(MockObjects.PredictionClient.Name, telemetryClient.RecordedTelemetry[0].Properties["ClientId"]); - Assert.Equal(AzPredictorConstants.CommandPlaceholder, telemetryClient.RecordedTelemetry[0].Properties["UserInput"]); + Assert.Equal(AzPredictorConstants.CommandPlaceholder, telemetryClient.RecordedTelemetry[0].Properties[GetSuggestionTelemetryData.PropertyNameOuterUserInput]); Assert.StartsWith($"Type: {typeof(MockTestException)}\nStack Trace: ", telemetryClient.RecordedTelemetry[0].Properties["Exception"]); Assert.EndsWith("Aggregation", telemetryClient.RecordedTelemetry[1].EventName); @@ -1093,7 +1099,7 @@ public void VerifyAggregationDataSplitAtDisplaySuggestion() var recordedTelemetry = telemetryClient.RecordedTelemetry[0]; var suggestionSessions = JsonSerializer.Deserialize>>(recordedTelemetry.Properties[GetSuggestionTelemetryData.PropertyNamePrediction]); Assert.Equal(expectedSuggestionSessionInFirstBatch, suggestionSessions.Count()); - Assert.True(suggestionSessions.All((s) => s.ContainsKey(GetSuggestionTelemetryData.PropertyNameFound) && s.ContainsKey(GetSuggestionTelemetryData.PropertyNameUserInput))); + Assert.True(suggestionSessions.All((s) => s.ContainsKey(GetSuggestionTelemetryData.PropertyNameFound) && s.ContainsKey(GetSuggestionTelemetryData.PropertyNameInnerUserInput))); Assert.True(suggestionSessions.All((s) => !s.ContainsKey(SuggestionAcceptedTelemetryData.PropertyNameAccepted))); Assert.True(suggestionSessions.All((s) => !s.ContainsKey(SuggestionDisplayedTelemetryData.PropertyNameDisplayed))); Assert.Equal(suggestionPackage.Session.Value, ((JsonElement)suggestionSessions.Last()[GetSuggestionTelemetryData.PropertyNameSuggestionSessionId]).GetUInt32()); @@ -1102,7 +1108,7 @@ public void VerifyAggregationDataSplitAtDisplaySuggestion() suggestionSessions = JsonSerializer.Deserialize>>(recordedTelemetry.Properties[GetSuggestionTelemetryData.PropertyNamePrediction]); Assert.Equal(expectedSuggestionSessionInSecondBatch, suggestionSessions.Count()); Assert.False(suggestionSessions[0].ContainsKey(GetSuggestionTelemetryData.PropertyNameFound)); - Assert.False(suggestionSessions[0].ContainsKey(GetSuggestionTelemetryData.PropertyNameUserInput)); + Assert.False(suggestionSessions[0].ContainsKey(GetSuggestionTelemetryData.PropertyNameInnerUserInput)); Assert.False(suggestionSessions[0].ContainsKey(GetSuggestionTelemetryData.PropertyNameIsCancelled)); Assert.Equal(suggestionPackage.Session.Value, ((JsonElement)suggestionSessions[0][GetSuggestionTelemetryData.PropertyNameSuggestionSessionId]).GetUInt32()); Assert.Equal(1, ((JsonElement)suggestionSessions[0][SuggestionDisplayedTelemetryData.PropertyNameDisplayed])[0].GetInt32()); @@ -1151,7 +1157,7 @@ public void VerifyAggregationDataSplitAtAcceptSuggestion() var recordedTelemetry = telemetryClient.RecordedTelemetry[0]; var suggestionSessions = JsonSerializer.Deserialize>>(recordedTelemetry.Properties[GetSuggestionTelemetryData.PropertyNamePrediction]); Assert.Equal(expectedSuggestionSessionInFirstBatch, suggestionSessions.Count()); - Assert.True(suggestionSessions.All((s) => s.ContainsKey(GetSuggestionTelemetryData.PropertyNameFound) && s.ContainsKey(GetSuggestionTelemetryData.PropertyNameUserInput))); + Assert.True(suggestionSessions.All((s) => s.ContainsKey(GetSuggestionTelemetryData.PropertyNameFound) && s.ContainsKey(GetSuggestionTelemetryData.PropertyNameInnerUserInput))); Assert.True(suggestionSessions.All((s) => !s.ContainsKey(SuggestionAcceptedTelemetryData.PropertyNameAccepted))); Assert.True(suggestionSessions.SkipLast(1).All((s) => !s.ContainsKey(SuggestionDisplayedTelemetryData.PropertyNameDisplayed) && !s.ContainsKey(GetSuggestionTelemetryData.PropertyNameSuggestionSessionId))); Assert.Equal(suggestionPackage.Session.Value, ((JsonElement)suggestionSessions.Last()[GetSuggestionTelemetryData.PropertyNameSuggestionSessionId]).GetUInt32()); @@ -1162,7 +1168,7 @@ public void VerifyAggregationDataSplitAtAcceptSuggestion() suggestionSessions = JsonSerializer.Deserialize>>(recordedTelemetry.Properties[GetSuggestionTelemetryData.PropertyNamePrediction]); Assert.Equal(expectedSuggestionSessionInSecondBatch, suggestionSessions.Count()); Assert.False(suggestionSessions[0].ContainsKey(GetSuggestionTelemetryData.PropertyNameFound)); - Assert.False(suggestionSessions[0].ContainsKey(GetSuggestionTelemetryData.PropertyNameUserInput)); + Assert.False(suggestionSessions[0].ContainsKey(GetSuggestionTelemetryData.PropertyNameInnerUserInput)); Assert.False(suggestionSessions[0].ContainsKey(GetSuggestionTelemetryData.PropertyNameIsCancelled)); Assert.Equal(suggestionPackage.Session.Value, ((JsonElement)suggestionSessions[0][GetSuggestionTelemetryData.PropertyNameSuggestionSessionId]).GetUInt32()); Assert.Equal(acceptedSuggestion, ((JsonElement)suggestionSessions[0][SuggestionAcceptedTelemetryData.PropertyNameAccepted]).GetString()); diff --git a/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/SuggestionSessionTests.cs b/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/SuggestionSessionTests.cs index 7c96bbe90726..05350e273234 100644 --- a/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/SuggestionSessionTests.cs +++ b/tools/Az.Tools.Predictor/Az.Tools.Predictor.Test/SuggestionSessionTests.cs @@ -62,7 +62,7 @@ public void TestSizeForOneSuggestion(string suggestion, SuggestionSource source, + 1 // For the one digit of source + SuggestionSessionTests._AdditionalSizeForTwoElementArray // for [,] + SuggestionSessionTests._AdditionalSizeForArrayBracket // for [] in Found - + GetSuggestionTelemetryData.PropertyNameUserInput.Length + SuggestionSessionTests._AdditionalSizeForKey + + GetSuggestionTelemetryData.PropertyNameInnerUserInput.Length + SuggestionSessionTests._AdditionalSizeForKey + userInput.Length + SuggestionSessionTests._AdditionalSizeForString + GetSuggestionTelemetryData.PropertyNameIsCancelled.Length + SuggestionSessionTests._AdditionalSizeForKey + isCancelled.ToString(CultureInfo.InvariantCulture).Length; @@ -99,7 +99,7 @@ public void TestSizeForTwoSuggestions(string suggestion1, SuggestionSource sourc + 1 // for the one digit of source2 + SuggestionSessionTests._AdditionalSizeForTwoElementArray // for [,] + SuggestionSessionTests._AdditionalSizeForTwoElementArray // for [,] in Found - + GetSuggestionTelemetryData.PropertyNameUserInput.Length + SuggestionSessionTests._AdditionalSizeForKey + + GetSuggestionTelemetryData.PropertyNameInnerUserInput.Length + SuggestionSessionTests._AdditionalSizeForKey + userInput.Length + SuggestionSessionTests._AdditionalSizeForString + GetSuggestionTelemetryData.PropertyNameIsCancelled.Length + SuggestionSessionTests._AdditionalSizeForKey + isCancelled.ToString(CultureInfo.InvariantCulture).Length; @@ -135,7 +135,7 @@ public void TestSizeForDisplaySuggestion(string suggestion, SuggestionSource sou + 1 // For the one digit of source + SuggestionSessionTests._AdditionalSizeForTwoElementArray // for [,] + SuggestionSessionTests._AdditionalSizeForArrayBracket // for [] in Found - + GetSuggestionTelemetryData.PropertyNameUserInput.Length + SuggestionSessionTests._AdditionalSizeForKey + + GetSuggestionTelemetryData.PropertyNameInnerUserInput.Length + SuggestionSessionTests._AdditionalSizeForKey + userInput.Length + SuggestionSessionTests._AdditionalSizeForString + GetSuggestionTelemetryData.PropertyNameIsCancelled.Length + SuggestionSessionTests._AdditionalSizeForKey + isCancelled.ToString(CultureInfo.InvariantCulture).Length @@ -172,7 +172,7 @@ public void TestSizeForAcceptSuggestion(string suggestion, SuggestionSource sour + 1 // For the one digit of source + SuggestionSessionTests._AdditionalSizeForTwoElementArray // for [,] + SuggestionSessionTests._AdditionalSizeForArrayBracket // for [] in Found - + GetSuggestionTelemetryData.PropertyNameUserInput.Length + SuggestionSessionTests._AdditionalSizeForKey + + GetSuggestionTelemetryData.PropertyNameInnerUserInput.Length + SuggestionSessionTests._AdditionalSizeForKey + userInput.Length + SuggestionSessionTests._AdditionalSizeForString + GetSuggestionTelemetryData.PropertyNameIsCancelled.Length + SuggestionSessionTests._AdditionalSizeForKey + isCancelled.ToString(CultureInfo.InvariantCulture).Length diff --git a/tools/Az.Tools.Predictor/Az.Tools.Predictor/Az.Tools.Predictor.psd1 b/tools/Az.Tools.Predictor/Az.Tools.Predictor/Az.Tools.Predictor.psd1 index 3e3d085632a8..a2dd1f891e4c 100644 --- a/tools/Az.Tools.Predictor/Az.Tools.Predictor/Az.Tools.Predictor.psd1 +++ b/tools/Az.Tools.Predictor/Az.Tools.Predictor/Az.Tools.Predictor.psd1 @@ -11,7 +11,7 @@ RootModule = 'Az.Tools.Predictor.psm1' # Version number of this module. -ModuleVersion = '1.1.2' +ModuleVersion = '1.1.3' # Supported PSEditions CompatiblePSEditions = 'Core' @@ -67,8 +67,7 @@ PrivateData = @{ # IconUri = '' # ReleaseNotes of this module - ReleaseNotes = '* Data collection mechnanism updated -* Improvements in command parsing mechanism' + ReleaseNotes = '* Data collection mechnanism updated' # Prerelease string of this module # Prerelease = '' diff --git a/tools/Az.Tools.Predictor/Az.Tools.Predictor/AzPredictorConstants.cs b/tools/Az.Tools.Predictor/Az.Tools.Predictor/AzPredictorConstants.cs index e9420a490965..8d1094e2c3bc 100644 --- a/tools/Az.Tools.Predictor/Az.Tools.Predictor/AzPredictorConstants.cs +++ b/tools/Az.Tools.Predictor/Az.Tools.Predictor/AzPredictorConstants.cs @@ -16,6 +16,8 @@ using System.Collections; using System.Collections.Generic; using System.Collections.Immutable; +using System.Text; +using System.Text.RegularExpressions; namespace Microsoft.Azure.PowerShell.Tools.AzPredictor { @@ -226,6 +228,15 @@ internal static class AzPredictorConstants // Other Verbs "Use" }, StringComparer.OrdinalIgnoreCase); + + /// + /// The regex pattern to match the noun in an Az cmdlet. + /// + public static readonly Regex AzNounPattern = new Regex($"^{AzCommandMoniker}[a-zA-Z]*$", + RegexOptions.Compiled + | RegexOptions.Singleline + | RegexOptions.IgnoreCase, + TimeSpan.FromMilliseconds(10)); } } diff --git a/tools/Az.Tools.Predictor/Az.Tools.Predictor/AzPredictorService.cs b/tools/Az.Tools.Predictor/Az.Tools.Predictor/AzPredictorService.cs index 830f54f21a21..11c85bd8050b 100644 --- a/tools/Az.Tools.Predictor/Az.Tools.Predictor/AzPredictorService.cs +++ b/tools/Az.Tools.Predictor/Az.Tools.Predictor/AzPredictorService.cs @@ -346,10 +346,10 @@ public virtual bool IsSupportedCommand(string cmd) // There must be two parts (verb and noun) to be a valid PowerShell commands. // The first part must be an approved PowerShell verb and the second part must begin with "Az". - if (commandParts?.Length == 2 ) + if (commandParts?.Length == 2) { return AzPredictorConstants.ApprovedPowerShellVerbs.Contains(commandParts[0]) - && commandParts[1].StartsWith(AzPredictorConstants.AzCommandMoniker, StringComparison.OrdinalIgnoreCase); + && AzPredictorConstants.AzNounPattern.IsMatch(commandParts[1]); } return false; diff --git a/tools/Az.Tools.Predictor/Az.Tools.Predictor/ChangeLog.md b/tools/Az.Tools.Predictor/Az.Tools.Predictor/ChangeLog.md index 51836157184d..3a19208c0acf 100644 --- a/tools/Az.Tools.Predictor/Az.Tools.Predictor/ChangeLog.md +++ b/tools/Az.Tools.Predictor/Az.Tools.Predictor/ChangeLog.md @@ -19,6 +19,9 @@ --> ## Upcoming Release +## Version 1.1.3 +* Updated data collection mechanism + ## Version 1.1.2 * Updated data collection mechanism * Improvements in command parsing mechanism diff --git a/tools/Az.Tools.Predictor/Az.Tools.Predictor/Telemetry/AggregatedTelemetryData.cs b/tools/Az.Tools.Predictor/Az.Tools.Predictor/Telemetry/AggregatedTelemetryData.cs index d10290e6729a..6dba9d82179e 100644 --- a/tools/Az.Tools.Predictor/Az.Tools.Predictor/Telemetry/AggregatedTelemetryData.cs +++ b/tools/Az.Tools.Predictor/Az.Tools.Predictor/Telemetry/AggregatedTelemetryData.cs @@ -54,7 +54,7 @@ public string UserInput get { return _userInput; } set { - int keySize = SuggestionSession.GetKeySize(GetSuggestionTelemetryData.PropertyNameUserInput.Length); + int keySize = SuggestionSession.GetKeySize(GetSuggestionTelemetryData.PropertyNameInnerUserInput.Length); if (_userInput is not null) { diff --git a/tools/Az.Tools.Predictor/Az.Tools.Predictor/Telemetry/AzPredictorTelemetryClient.cs b/tools/Az.Tools.Predictor/Az.Tools.Predictor/Telemetry/AzPredictorTelemetryClient.cs index 470e39f6a6b1..8895996d9846 100644 --- a/tools/Az.Tools.Predictor/Az.Tools.Predictor/Telemetry/AzPredictorTelemetryClient.cs +++ b/tools/Az.Tools.Predictor/Az.Tools.Predictor/Telemetry/AzPredictorTelemetryClient.cs @@ -291,7 +291,7 @@ protected void SendAggregatedTelemetryData() if (suggestionSession.UserInput != null) { - toAddSuggestion.Add(GetSuggestionTelemetryData.PropertyNameUserInput, suggestionSession.UserInput); + toAddSuggestion.Add(GetSuggestionTelemetryData.PropertyNameInnerUserInput, suggestionSession.UserInput); _uniqueUserInput.Add(suggestionSession.UserInput); } @@ -324,7 +324,7 @@ protected void SendAggregatedTelemetryData() if (suggestions.Count > 0) { properties.Add(GetSuggestionTelemetryData.PropertyNamePrediction, JsonSerializer.Serialize(suggestions, JsonUtilities.TelemetrySerializerOptions)); - properties.Add(GetSuggestionTelemetryData.PropertyNameUserInput, string.Join(_StringValueConcatenator, _uniqueUserInput)); + properties.Add(GetSuggestionTelemetryData.PropertyNameOuterUserInput, string.Join(_StringValueConcatenator, _uniqueUserInput)); } if (aggregatedData.CommandLine != null) @@ -494,7 +494,7 @@ private void ProcessTelemetryData(GetSuggestionTelemetryData telemetryData) telemetryData.Exception, new Dictionary() { - { GetSuggestionTelemetryData.PropertyNameUserInput, maskedUserInput }, + { GetSuggestionTelemetryData.PropertyNameOuterUserInput, maskedUserInput }, }); } } diff --git a/tools/Az.Tools.Predictor/Az.Tools.Predictor/Telemetry/GetSuggestionTelemetryData.cs b/tools/Az.Tools.Predictor/Az.Tools.Predictor/Telemetry/GetSuggestionTelemetryData.cs index 8deb48b3322d..836e0013121b 100644 --- a/tools/Az.Tools.Predictor/Az.Tools.Predictor/Telemetry/GetSuggestionTelemetryData.cs +++ b/tools/Az.Tools.Predictor/Az.Tools.Predictor/Telemetry/GetSuggestionTelemetryData.cs @@ -36,7 +36,7 @@ public sealed class GetSuggestionTelemetryData : ITelemetryData /// /// The telemetry property name for "Prediction". /// - public const string PropertyNamePrediction = "Prediction2"; + public const string PropertyNamePrediction = "Prediction_a"; /// /// The telemetry property name for "SuggestionSessionId". @@ -44,9 +44,14 @@ public sealed class GetSuggestionTelemetryData : ITelemetryData public const string PropertyNameSuggestionSessionId = "SuggestionSessionId"; /// - /// The telemetry property name fo "userInput". + /// The telemetry property name fo "userInput" used as the nested property. /// - public const string PropertyNameUserInput = "UserInput"; + public const string PropertyNameInnerUserInput = "UserInput"; + + /// + /// The telemetry property name fo "userInput" used as a top-level property. + /// + public const string PropertyNameOuterUserInput = "UserInput_a"; /// public PredictionClient Client { get; init; } diff --git a/tools/Az.Tools.Predictor/Directory.Build.props b/tools/Az.Tools.Predictor/Directory.Build.props index bd7021d07aba..e7f18581fabb 100644 --- a/tools/Az.Tools.Predictor/Directory.Build.props +++ b/tools/Az.Tools.Predictor/Directory.Build.props @@ -4,7 +4,7 @@ net6.0 false true - 1.1.2 + 1.1.3 Microsoft Corporation Microsoft Corporation Microsoft Corporation. All rights reserved.