private void PopulatePropertiesFromQos()

in src/Common/MetricHelper.cs [315:492]


        private void PopulatePropertiesFromQos(AzurePSQoSEvent qos, IDictionary<string, string> eventProperties, bool populateException = false)
        {
            if (qos == null)
            {
                return;
            }

            // Breaking change of telemetry
            // * 2, change host version to real PowerShell version. Original version was PowerShell host version which is not always the same as PS version
            //      and can be customized.
            eventProperties.Add("telemetry-version", "2");
            eventProperties.Add("Command", qos.CommandName);
            eventProperties.Add("IsSuccess", qos.IsSuccess.ToString());
            eventProperties.Add("ModuleName", qos.ModuleName);
            eventProperties.Add("ModuleVersion", qos.ModuleVersion);
            eventProperties.Add("HostVersion", qos.HostVersion);
            eventProperties.Add("HostName", qos.PSHostName);
            eventProperties.Add("OS", Environment.OSVersion.ToString());
            eventProperties.Add("CommandParameters", qos.Parameters);
            eventProperties.Add("x-ms-client-request-id", qos.ClientRequestId);
            eventProperties.Add("UserAgent", qos.UserAgent);
            eventProperties.Add("HashMacAddress", HashMacAddress);
            eventProperties.Add("PowerShellVersion", qos.PSVersion);
            eventProperties.Add("Version", qos.AzVersion);
            eventProperties.Add("AccountsVersion", qos.AzAccountsVersion);
            eventProperties.Add("CommandParameterSetName", qos.ParameterSetName);
            eventProperties.Add("CommandInvocationName", qos.InvocationName);
            eventProperties.Add("start-time", qos.StartTime.ToUniversalTime().ToString("o"));
            eventProperties.Add("end-time", qos.EndTime.ToUniversalTime().ToString("o"));
            eventProperties.Add("duration", qos.Duration.ToString("c"));
            eventProperties.Add("InternalCalledCmdlets", MetricHelper.InternalCalledCmdlets);
            eventProperties.Add("InstallationId", MetricHelper.InstallationId);
            eventProperties.Add("upgrade-notification-checked", qos.HigherVersionsChecked.ToString());
            eventProperties.Add("upgrade-notification-prompted", qos.UpgradeNotificationPrompted.ToString());
            if (!string.IsNullOrWhiteSpace(SharedVariable.PredictorCorrelationId))
            {
                eventProperties.Add("predictor-correlation-id", SharedVariable.PredictorCorrelationId);
                SharedVariable.PredictorCorrelationId = null;
            }
            if (qos.SurveyPrompted)
            {
                eventProperties.Add("survey-prompted", qos.SurveyPrompted.ToString());
            }
            if (!string.IsNullOrEmpty(qos.DisplayRegionIdentified))
            {
                eventProperties.Add("DisplayRegionIdentified", qos.DisplayRegionIdentified);
            }
            if (qos.Uid != null)
            {
                eventProperties.Add("UserId", qos.Uid);
            }
            if (qos.SubscriptionId != null)
            {
                eventProperties.Add("subscription-id", qos.SubscriptionId);
            }
            if (qos.TenantId != null)
            {
                eventProperties.Add("tenant-id", qos.TenantId);
            }

            if (qos.PreviousEndTime != null)
            {
                eventProperties.Add("interval", ((TimeSpan)(qos.StartTime - qos.PreviousEndTime)).ToString("c"));
            }

            if (qos.Exception != null && populateException)
            {
                eventProperties["exception-type"] = qos.Exception.GetType().ToString();
                string cloudErrorCode = null;
                if (qos.Exception is CloudException cloudException)
                {
                    eventProperties["exception-httpcode"] = cloudException.Response?.StatusCode.ToString();
                    cloudErrorCode = cloudException.Body?.Code;
                }
                Exception innerException = qos.Exception.InnerException;
                List<Exception> innerExceptions = new List<Exception>();
                string innerExceptionStr = string.Empty;
                while (innerException != null)
                {
                    innerExceptions.Add(innerException);
                    if (innerException is CloudException innerCloudException)
                    {
                        eventProperties["exception-httpcode"] = innerCloudException.Response?.StatusCode.ToString();
                        cloudErrorCode = innerCloudException.Body?.Code;
                    }
                    innerException = innerException.InnerException;
                }
                if (innerExceptions.Count > 0)
                {
                    eventProperties["exception-inner"] = string.Join(";", innerExceptions.Select(e => e.GetType().ToString()));
                }
                if (exceptionTrackAcceptModuleList.Contains(qos.ModuleName, StringComparer.InvariantCultureIgnoreCase)
                    || exceptionTrackAcceptCmdletList.Contains(qos.CommandName, StringComparer.InvariantCultureIgnoreCase))
                {
                    StackTrace trace = new StackTrace(qos.Exception);
                    string stack = string.Join(";", trace.GetFrames().Take(2).Select(f => ConvertFrameToString(f)));
                    eventProperties["exception-stack"] = stack;
                }

                if (cloudErrorCode != null && !(qos.Exception.Data?.Contains(AzurePSErrorDataKeys.CloudErrorCodeKey) == true))
                {
                    qos.Exception.Data[AzurePSErrorDataKeys.CloudErrorCodeKey] = cloudErrorCode;
                }

                if (qos.Exception.Data != null)
                {
                    if (qos.Exception.Data.Contains(AzurePSErrorDataKeys.HttpStatusCode))
                    {
                        eventProperties["exception-httpcode"] = qos.Exception.Data[AzurePSErrorDataKeys.HttpStatusCode].ToString();
                    }

                    if (qos.Exception.Data.Contains(AzurePSErrorDataKeys.CloudErrorCodeKey) == true)
                    {
                        string existingErrorKind = qos.Exception.Data.Contains(AzurePSErrorDataKeys.ErrorKindKey)
                                                    ? qos.Exception.Data[AzurePSErrorDataKeys.ErrorKindKey].ToString()
                                                    : null;
                        cloudErrorCode = (string)qos.Exception.Data[AzurePSErrorDataKeys.CloudErrorCodeKey];
                        // For the time being, we consider ResourceNotFound and ResourceGroupNotFound as user's input error.
                        // We are considering if ResourceNotFound should be false positive error.
                        if (("ResourceNotFound".Equals(cloudErrorCode) || "ResourceGroupNotFound".Equals(cloudErrorCode))
                            && existingErrorKind != ErrorKind.FalseError)
                        {
                            qos.Exception.Data[AzurePSErrorDataKeys.ErrorKindKey] = ErrorKind.UserError;
                        }
                    }

                    StringBuilder sb = new StringBuilder();
                    foreach (var key in qos.Exception.Data?.Keys)
                    {
                        if (AzurePSErrorDataKeys.IsKeyPredefined(key.ToString())
                            && !AzurePSErrorDataKeys.HttpStatusCode.Equals(key))
                        {
                            if (sb.Length > 0)
                            {
                                sb.Append(";");
                            }
                            sb.Append($"{key.ToString().Substring(AzurePSErrorDataKeys.KeyPrefix.Length)}={qos.Exception.Data[key]}");
                        }
                    }
                    if (sb.Length > 0)
                    {
                        eventProperties["exception-data"] = sb.ToString();
                    }
                }
                //We record the case which exception has no message
                if (string.IsNullOrEmpty(qos.Exception.Message))
                {
                    eventProperties["exception-emptymessage"] = true.ToString();
                }

                if (!qos.IsSuccess && qos.Exception?.Data?.Contains(AzurePSErrorDataKeys.ErrorKindKey) == true)
                {
                    eventProperties["pebcak"] = (qos.Exception.Data[AzurePSErrorDataKeys.ErrorKindKey] == ErrorKind.UserError).ToString();
                    if (qos.Exception.Data[AzurePSErrorDataKeys.ErrorKindKey] == ErrorKind.FalseError)
                    {
                        eventProperties["IsSuccess"] = true.ToString();
                    }
                }
            }

            PopulateConfigMetricsFromQos(qos, eventProperties);
            PopulateSanitizerPropertiesFromQos(qos, eventProperties);
            PopulateAuthenticationPropertiesFromQos(qos.AuthTelemetry, eventProperties);

            if (qos.InputFromPipeline != null)
            {
                eventProperties.Add("InputFromPipeline", qos.InputFromPipeline.Value.ToString());
            }
            if (qos.OutputToPipeline != null)
            {
                eventProperties.Add("OutputToPipeline", qos.OutputToPipeline.Value.ToString());
            }

            foreach (var key in qos.CustomProperties.Keys)
            {
                eventProperties[key] = qos.CustomProperties[key];
            }
        }