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];
}
}