diff --git a/src/Authentication.Abstractions/AuthenticationInfo.cs b/src/Authentication.Abstractions/AuthTelemetryRecord.cs similarity index 81% rename from src/Authentication.Abstractions/AuthenticationInfo.cs rename to src/Authentication.Abstractions/AuthTelemetryRecord.cs index 95fa6374e6..a45707ad53 100644 --- a/src/Authentication.Abstractions/AuthenticationInfo.cs +++ b/src/Authentication.Abstractions/AuthTelemetryRecord.cs @@ -12,15 +12,18 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using System.Collections.Concurrent; +using Newtonsoft.Json; + using System; +using System.Collections.Concurrent; using System.Collections.Generic; -using System.Xml.Serialization; -using Newtonsoft.Json; namespace Microsoft.Azure.Commands.Common.Authentication.Abstractions { - public class AuthenticationInfo : IAuthenticationInfo + /// + /// A model class for authenction telemetry record. + /// + public class AuthTelemetryRecord : IAuthTelemetryRecord { /// /// Class name of the TokenCredential, stands for the authentication method @@ -36,15 +39,14 @@ public class AuthenticationInfo : IAuthenticationInfo /// Additional properties for AuthenticationInfo /// [JsonIgnore] - [XmlIgnore] public IDictionary ExtendedProperties { get; } = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); - public AuthenticationInfo() + public AuthTelemetryRecord() { TokenCredentialName = null; } - public AuthenticationInfo(IAuthenticationInfo other, bool? isSuccess = null) + public AuthTelemetryRecord(IAuthTelemetryRecord other, bool? isSuccess = null) { this.TokenCredentialName = other.TokenCredentialName; this.AuthenticationSuccess = isSuccess ?? other.AuthenticationSuccess; @@ -59,8 +61,14 @@ public AuthenticationInfo(IAuthenticationInfo other, bool? isSuccess = null) /// public const string TokenCacheEnabled = "TokenCacheEnabled"; + /// + /// Prefix of properties of the first record of authentication telemetry record. + /// public const string AuthInfoTelemetryHeadKey = "auth-info-head"; + /// + /// Key of the left records of authentication telemetry. + /// public const string AuthInfoTelemetrySubsequentKey = "auth-info-sub"; } } diff --git a/src/Authentication.Abstractions/AuthenticationTelemetry.cs b/src/Authentication.Abstractions/AuthenticationTelemetry.cs new file mode 100644 index 0000000000..75172387f2 --- /dev/null +++ b/src/Authentication.Abstractions/AuthenticationTelemetry.cs @@ -0,0 +1,48 @@ +// ---------------------------------------------------------------------------------- +// +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using System.Collections.Generic; + +namespace Microsoft.Azure.Commands.Common.Authentication.Abstractions +{ + /// + /// A model class for a list of authenction telemetry records. + /// + public class AuthenticationTelemetry + { + /// + /// The first record of authentication telemetry data, usually describes the main method of this authentication process. + /// + public IAuthTelemetryRecord Head { get; } = null; + + /// + /// The left part of authentication telemetry records. + /// + public IList Tail { get; } = new List(); + + public AuthenticationTelemetry(IEnumerable records) + { + var enumerator = records.GetEnumerator(); + if (enumerator.MoveNext()) + { + Head = enumerator.Current; + } + + while (enumerator.MoveNext()) + { + Tail.Add(enumerator.Current); + } + } + } +} diff --git a/src/Authentication.Abstractions/Interfaces/IAuthenticationInfo.cs b/src/Authentication.Abstractions/Interfaces/IAuthTelemetryRecord.cs similarity index 88% rename from src/Authentication.Abstractions/Interfaces/IAuthenticationInfo.cs rename to src/Authentication.Abstractions/Interfaces/IAuthTelemetryRecord.cs index 6867fa53e3..5c3b673cb6 100644 --- a/src/Authentication.Abstractions/Interfaces/IAuthenticationInfo.cs +++ b/src/Authentication.Abstractions/Interfaces/IAuthTelemetryRecord.cs @@ -14,7 +14,10 @@ namespace Microsoft.Azure.Commands.Common.Authentication.Abstractions { - public interface IAuthenticationInfo : IExtensibleModel + /// + /// Representation of an authentication telemetry record + /// + public interface IAuthTelemetryRecord : IExtensibleModel { /// /// Class name of the TokenCredential, stands for the authentication method diff --git a/src/Authentication.Abstractions/Interfaces/IAuthenticationFactory.cs b/src/Authentication.Abstractions/Interfaces/IAuthenticationFactory.cs index 242d4f024e..7c7eeca126 100644 --- a/src/Authentication.Abstractions/Interfaces/IAuthenticationFactory.cs +++ b/src/Authentication.Abstractions/Interfaces/IAuthenticationFactory.cs @@ -99,6 +99,6 @@ IAccessToken Authenticate( /// /// Get the information to be recorded in Telemetry /// - IList GetDataForTelemetry(); + AuthenticationTelemetry GetDataForTelemetry(); } } diff --git a/src/Common/AzurePSCmdlet.cs b/src/Common/AzurePSCmdlet.cs index 63af2a84e3..fb2d13a4b9 100644 --- a/src/Common/AzurePSCmdlet.cs +++ b/src/Common/AzurePSCmdlet.cs @@ -430,8 +430,6 @@ protected override void EndProcessing() WriteWarningMessageForVersionUpgrade(); WriteSecretsWarningMessage(); - _qosEvent.AuthInfo = AzureSession.Instance.AuthenticationFactory.GetDataForTelemetry(); - if (MetricHelper.IsCalledByUser() && SurveyHelper.GetInstance().ShouldPromptAzSurvey() && (AzureSession.Instance.TryGetComponent(nameof(IConfigManager), out var configManager) @@ -844,6 +842,7 @@ protected void LogQosEvent() _qosEvent.ParameterSetName = this.ParameterSetName; _qosEvent.FinishQosEvent(); + _qosEvent.AuthTelemetry = AzureSession.Instance.AuthenticationFactory.GetDataForTelemetry(); if (!IsUsageMetricEnabled && (!IsErrorMetricEnabled || _qosEvent.IsSuccess)) { diff --git a/src/Common/MetricHelper.cs b/src/Common/MetricHelper.cs index a85f572d37..4fb9b01b71 100644 --- a/src/Common/MetricHelper.cs +++ b/src/Common/MetricHelper.cs @@ -292,28 +292,18 @@ public void SetPSHost(PSHost host) { } - private static void PopulateAuthenticationInfoFromQos(IEnumerable infos, IDictionary eventProperties) + private static void PopulateAuthenticationPropertiesFromQos(AuthenticationTelemetry telemetry, IDictionary eventProperties) { - var enumerator = infos.GetEnumerator(); - if (enumerator.MoveNext()) - { - var info = enumerator.Current; - eventProperties[$"{AuthenticationInfo.AuthInfoTelemetryHeadKey}-{nameof(info.TokenCredentialName).ToLower()}"] = info.TokenCredentialName; - eventProperties[$"{AuthenticationInfo.AuthInfoTelemetryHeadKey}-{nameof(info.AuthenticationSuccess).ToLower()}"] = info.AuthenticationSuccess.ToString(); - - foreach (var property in info.ExtendedProperties) - { - eventProperties[$"{AuthenticationInfo.AuthInfoTelemetryHeadKey}-{property.Key.ToLower()}"] = property.Value; - } - } + var record = telemetry.Head; + eventProperties[$"{AuthTelemetryRecord.AuthInfoTelemetryHeadKey}-{nameof(record.TokenCredentialName).ToLower()}"] = record.TokenCredentialName; + eventProperties[$"{AuthTelemetryRecord.AuthInfoTelemetryHeadKey}-{nameof(record.AuthenticationSuccess).ToLower()}"] = record.AuthenticationSuccess.ToString(); - var subAuthInfos = new List(); - while (enumerator.MoveNext()) + foreach (var property in record.ExtendedProperties) { - var info = enumerator.Current; - subAuthInfos.Add(info as AuthenticationInfo); + eventProperties[$"{AuthTelemetryRecord.AuthInfoTelemetryHeadKey}-{property.Key.ToLower()}"] = property.Value; } - eventProperties[AuthenticationInfo.AuthInfoTelemetrySubsequentKey] = JsonConvert.SerializeObject(subAuthInfos); + + eventProperties[AuthTelemetryRecord.AuthInfoTelemetrySubsequentKey] = JsonConvert.SerializeObject(telemetry.Tail); } private void PopulatePropertiesFromQos(AzurePSQoSEvent qos, IDictionary eventProperties, bool populateException = false) @@ -478,7 +468,7 @@ private void PopulatePropertiesFromQos(AzurePSQoSEvent qos, IDictionary AuthInfo { get; set; } + public AuthenticationTelemetry AuthTelemetry { get; set; } public AzurePSQoSEvent() {