internal static TelemetryItem GetTelemetryItem(Activity activity, ref TagEnumerationState monitorTags, Resource resource, string instrumentationKey) { TelemetryItem telemetryItem = new TelemetryItem(PartA_Name_Mapping[activity.GetTelemetryType()], FormatUtcTimestamp(activity.StartTimeUtc)) { InstrumentationKey = instrumentationKey }; InitRoleInfo(resource); if (activity.ParentSpanId != default) { telemetryItem.Tags[ContextTagKeys.AiOperationParentId.ToString()] = activity.ParentSpanId.ToHexString(); } telemetryItem.Tags[ContextTagKeys.AiCloudRole.ToString()] = RoleName; telemetryItem.Tags[ContextTagKeys.AiCloudRoleInstance.ToString()] = RoleInstance; telemetryItem.Tags[ContextTagKeys.AiOperationId.ToString()] = activity.TraceId.ToHexString(); // todo: update swagger to include this key. telemetryItem.Tags["ai.user.userAgent"] = AzMonList.GetTagValue(ref monitorTags.PartBTags, SemanticConventions.AttributeHttpUserAgent)?.ToString(); // we only have mapping for server spans // todo: non-server spans if (activity.Kind == ActivityKind.Server) { telemetryItem.Tags[ContextTagKeys.AiOperationName.ToString()] = GetOperationName(activity, ref monitorTags.PartBTags); telemetryItem.Tags[ContextTagKeys.AiLocationIp.ToString()] = GetLocationIp(ref monitorTags.PartBTags); } telemetryItem.Tags[ContextTagKeys.AiInternalSdkVersion.ToString()] = SdkVersionUtils.SdkVersion; return(telemetryItem); }
internal static RequestData GetRequestData(Activity activity) { string url = null; string urlAuthority = null; var monitorTags = EnumerateActivityTags(activity); switch (monitorTags.activityType) { case PartBType.Http: monitorTags.PartBTags.GenerateUrlAndAuthority(out url, out urlAuthority); break; case PartBType.Messaging: url = AzMonList.GetTagValue(ref monitorTags.PartBTags, SemanticConventions.AttributeMessagingUrl)?.ToString(); break; } var statusCode = AzMonList.GetTagValue(ref monitorTags.PartBTags, SemanticConventions.AttributeHttpStatusCode)?.ToString() ?? "0"; var success = activity.GetStatus() != Status.Error; var request = new RequestData(2, activity.Context.SpanId.ToHexString(), activity.Duration.ToString("c", CultureInfo.InvariantCulture), success, statusCode) { Name = activity.DisplayName, Url = url, Source = urlAuthority }; AddPropertiesToTelemetry(request.Properties, ref monitorTags.PartCTags); return(request); }
internal static RequestData GetRequestData(Activity activity, ref TagEnumerationState monitorTags) { string url = null; AddActivityLinksToPartCTags(activity.Links, ref monitorTags.PartCTags); switch (monitorTags.activityType) { case PartBType.Http: url = monitorTags.PartBTags.GetRequestUrl(); break; case PartBType.Messaging: url = AzMonList.GetTagValue(ref monitorTags.PartBTags, SemanticConventions.AttributeMessagingUrl)?.ToString(); break; } var requestName = TelemetryPartA.GetOperationName(activity, ref monitorTags.PartBTags); var statusCode = AzMonList.GetTagValue(ref monitorTags.PartBTags, SemanticConventions.AttributeHttpStatusCode)?.ToString() ?? "0"; var success = activity.GetStatus().StatusCode != StatusCode.Error; var request = new RequestData(2, activity.Context.SpanId.ToHexString(), activity.Duration.ToString("c", CultureInfo.InvariantCulture), success, statusCode) { Name = requestName, Url = url, }; AddPropertiesToTelemetry(request.Properties, ref monitorTags.PartCTags); return(request); }
///<summary> /// Gets http request url from activity tag objects. ///</summary> internal static string GetRequestUrl(this AzMonList tagObjects) { // From spec: one of the following combinations is required in case of server spans: // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/http.md#http-server-semantic-conventions // http.url // http.scheme, http.host, http.target // http.scheme, http.server_name, net.host.port, http.target // http.scheme, net.host.name, net.host.port, http.target string url = null; url = tagObjects.GetUrlUsingHttpUrl(); if (url != null) { return(url); } var httpScheme = AzMonList.GetTagValue(ref tagObjects, SemanticConventions.AttributeHttpScheme)?.ToString(); if (!string.IsNullOrWhiteSpace(httpScheme)) { var httpTarget = AzMonList.GetTagValue(ref tagObjects, SemanticConventions.AttributeHttpTarget)?.ToString(); // http.target is required in other three possible combinations // If not available then do not proceed. if (string.IsNullOrWhiteSpace(httpTarget)) { return(null); } string defaultPort = GetDefaultHttpPort(httpScheme); url = tagObjects.GetUrlUsingHttpHost(httpScheme, defaultPort, httpTarget); if (url != null) { return(url); } var httpServerName = AzMonList.GetTagValue(ref tagObjects, SemanticConventions.AttributeHttpServerName)?.ToString(); string host; if (!string.IsNullOrWhiteSpace(httpServerName)) { host = httpServerName; } else { host = AzMonList.GetTagValue(ref tagObjects, SemanticConventions.AttributeNetHostName)?.ToString(); } if (!string.IsNullOrWhiteSpace(host)) { var netHostPort = AzMonList.GetTagValue(ref tagObjects, SemanticConventions.AttributeNetHostPort)?.ToString(); if (!string.IsNullOrWhiteSpace(netHostPort)) { url = tagObjects.GetUrlUsingHostAndPort(httpScheme, host, netHostPort, defaultPort, httpTarget); return(url); } } } return(url); }
private static string GetLocationIp(ref AzMonList partBTags) { var httpClientIp = AzMonList.GetTagValue(ref partBTags, SemanticConventions.AttributeHttpClientIP)?.ToString(); if (!string.IsNullOrWhiteSpace(httpClientIp)) { return(httpClientIp); } return(AzMonList.GetTagValue(ref partBTags, SemanticConventions.AttributeNetPeerIp)?.ToString()); }
internal static string GetOperationName(Activity activity, ref AzMonList partBTags) { var httpMethod = AzMonList.GetTagValue(ref partBTags, SemanticConventions.AttributeHttpMethod)?.ToString(); if (!string.IsNullOrWhiteSpace(httpMethod)) { return($"{httpMethod} {activity.DisplayName}"); } return(activity.DisplayName); }
internal static string GetUrlUsingHttpUrl(this AzMonList tagObjects) { string url = null; var httpUrl = AzMonList.GetTagValue(ref tagObjects, SemanticConventions.AttributeHttpUrl)?.ToString(); if (!string.IsNullOrWhiteSpace(httpUrl)) { url = httpUrl; } return(url); }
internal static RemoteDependencyData GetRemoteDependencyData(Activity activity, ref TagEnumerationState monitorTags) { AddActivityLinksToPartCTags(activity.Links, ref monitorTags.PartCTags); var dependency = new RemoteDependencyData(2, activity.DisplayName, activity.Duration.ToString("c", CultureInfo.InvariantCulture)) { Id = activity.Context.SpanId.ToHexString(), Success = activity.GetStatus().StatusCode != StatusCode.Error }; switch (monitorTags.activityType) { case PartBType.Http: dependency.Data = monitorTags.PartBTags.GetDependencyUrl(); dependency.Target = monitorTags.PartBTags.GetDependencyTarget(PartBType.Http); dependency.Type = "Http"; dependency.ResultCode = AzMonList.GetTagValue(ref monitorTags.PartBTags, SemanticConventions.AttributeHttpStatusCode)?.ToString() ?? "0"; break; case PartBType.Db: var depDataAndType = AzMonList.GetTagValues(ref monitorTags.PartBTags, SemanticConventions.AttributeDbStatement, SemanticConventions.AttributeDbSystem); dependency.Data = depDataAndType[0]?.ToString(); dependency.Target = monitorTags.PartBTags.GetDbDependencyTarget(); dependency.Type = SqlDbs.Contains(depDataAndType[1]?.ToString()) ? "SQL" : depDataAndType[1]?.ToString(); break; case PartBType.Rpc: var depInfo = AzMonList.GetTagValues(ref monitorTags.PartBTags, SemanticConventions.AttributeRpcService, SemanticConventions.AttributeRpcSystem, SemanticConventions.AttributeRpcStatus); dependency.Data = depInfo[0]?.ToString(); dependency.Type = depInfo[1]?.ToString(); dependency.ResultCode = depInfo[2]?.ToString(); break; case PartBType.Messaging: depDataAndType = AzMonList.GetTagValues(ref monitorTags.PartBTags, SemanticConventions.AttributeMessagingUrl, SemanticConventions.AttributeMessagingSystem); dependency.Data = depDataAndType[0]?.ToString(); dependency.Type = depDataAndType[1]?.ToString(); break; } if (activity.Kind == ActivityKind.Internal && activity.Parent != null) { dependency.Type = "InProc"; } AddPropertiesToTelemetry(dependency.Properties, ref monitorTags.PartCTags); return(dependency); }
internal static string GetHostUsingNetPeerAttributes(this AzMonList tagObjects) { var netPeerName = AzMonList.GetTagValue(ref tagObjects, SemanticConventions.AttributeNetPeerName)?.ToString(); string host; if (!string.IsNullOrWhiteSpace(netPeerName)) { host = netPeerName; } else { host = AzMonList.GetTagValue(ref tagObjects, SemanticConventions.AttributeNetPeerIp)?.ToString(); } return(host); }
internal static RemoteDependencyData GetRemoteDependencyData(Activity activity) { var monitorTags = EnumerateActivityTags(activity); var dependency = new RemoteDependencyData(2, activity.DisplayName, activity.Duration.ToString("c", CultureInfo.InvariantCulture)) { Id = activity.Context.SpanId.ToHexString(), Success = activity.GetStatus() != Status.Error }; switch (monitorTags.activityType) { case PartBType.Http: monitorTags.PartBTags.GenerateUrlAndAuthority(out var url, out var urlAuthority); dependency.Data = url; dependency.Target = urlAuthority; dependency.Type = "Http"; dependency.ResultCode = AzMonList.GetTagValue(ref monitorTags.PartBTags, SemanticConventions.AttributeHttpStatusCode)?.ToString() ?? "0"; break; case PartBType.Db: var depDataAndType = AzMonList.GetTagValues(ref monitorTags.PartBTags, SemanticConventions.AttributeDbStatement, SemanticConventions.AttributeDbSystem); dependency.Data = depDataAndType[0]?.ToString(); dependency.Type = depDataAndType[1]?.ToString(); break; case PartBType.Rpc: var depInfo = AzMonList.GetTagValues(ref monitorTags.PartBTags, SemanticConventions.AttributeRpcService, SemanticConventions.AttributeRpcSystem, SemanticConventions.AttributeRpcStatus); dependency.Data = depInfo[0]?.ToString(); dependency.Type = depInfo[1]?.ToString(); dependency.ResultCode = depInfo[2]?.ToString(); break; case PartBType.Messaging: depDataAndType = AzMonList.GetTagValues(ref monitorTags.PartBTags, SemanticConventions.AttributeMessagingUrl, SemanticConventions.AttributeMessagingSystem); dependency.Data = depDataAndType[0]?.ToString(); dependency.Type = depDataAndType[1]?.ToString(); break; } AddPropertiesToTelemetry(dependency.Properties, ref monitorTags.PartCTags); return(dependency); }
internal static string GetHttpDependencyName(this AzMonList tagObjects, string httpUrl) { if (string.IsNullOrWhiteSpace(httpUrl)) { return(null); } var httpMethod = AzMonList.GetTagValue(ref tagObjects, SemanticConventions.AttributeHttpMethod)?.ToString(); if (!string.IsNullOrWhiteSpace(httpMethod)) { if (Uri.TryCreate(httpUrl.ToString(), UriKind.RelativeOrAbsolute, out var uri) && uri.IsAbsoluteUri) { return($"{httpMethod} {uri.AbsolutePath}"); } } return(null); }
internal static string GetUrlUsingHttpHost(this AzMonList tagObjects, string httpScheme, string defaultPort, string httpTarget) { string url = null; var httpHost = AzMonList.GetTagValue(ref tagObjects, SemanticConventions.AttributeHttpHost)?.ToString(); if (!string.IsNullOrWhiteSpace(httpHost)) { string portSection = $":{defaultPort}"; if (httpHost.EndsWith(portSection, StringComparison.OrdinalIgnoreCase)) { var truncatedHost = httpHost.Substring(0, httpHost.IndexOf(portSection, StringComparison.OrdinalIgnoreCase)); url = $"{httpScheme}://{truncatedHost}{httpTarget}"; } else { url = $"{httpScheme}://{httpHost}{httpTarget}"; } } return(url); }
internal static string GetOperationName(Activity activity, ref AzMonList partBTags) { var httpMethod = AzMonList.GetTagValue(ref partBTags, SemanticConventions.AttributeHttpMethod)?.ToString(); if (!string.IsNullOrWhiteSpace(httpMethod)) { var httpRoute = AzMonList.GetTagValue(ref partBTags, SemanticConventions.AttributeHttpRoute)?.ToString(); // ASP.NET instrumentation assigns route as {controller}/{action}/{id} which would result in the same name for different operations. // To work around that we will use path from httpUrl. if (!string.IsNullOrWhiteSpace(httpRoute) && !httpRoute.Contains("{controller}")) { return($"{httpMethod} {httpRoute}"); } var httpUrl = AzMonList.GetTagValue(ref partBTags, SemanticConventions.AttributeHttpUrl)?.ToString(); if (!string.IsNullOrWhiteSpace(httpUrl) && Uri.TryCreate(httpUrl.ToString(), UriKind.RelativeOrAbsolute, out var uri) && uri.IsAbsoluteUri) { return($"{httpMethod} {uri.AbsolutePath}"); } } return(activity.DisplayName); }
///<summary> /// Gets Database dependency target from activity tag objects. ///</summary> internal static string GetDbDependencyTarget(this AzMonList tagObjects) { string target = tagObjects.GetDependencyTarget(PartBType.Db); string dbName = AzMonList.GetTagValue(ref tagObjects, SemanticConventions.AttributeDbName)?.ToString(); bool isTargetEmpty = string.IsNullOrEmpty(target); bool isDbNameEmpty = string.IsNullOrEmpty(dbName); if (!isTargetEmpty && !isDbNameEmpty) { target = $"{target}/{dbName}"; } else if (isTargetEmpty && !isDbNameEmpty) { target = dbName; } else if (isTargetEmpty && isDbNameEmpty) { target = AzMonList.GetTagValue(ref tagObjects, SemanticConventions.AttributeDbSystem)?.ToString(); } return(target); }
///<summary> /// Gets Http dependency target from activity tag objects. ///</summary> internal static string GetDependencyTarget(this AzMonList tagObjects, PartBType type) { string target; string defaultPort; switch (type) { case PartBType.Http: defaultPort = GetDefaultHttpPort(AzMonList.GetTagValue(ref tagObjects, SemanticConventions.AttributeHttpScheme)?.ToString()); break; case PartBType.Db: defaultPort = GetDefaultDbPort(AzMonList.GetTagValue(ref tagObjects, SemanticConventions.AttributeDbSystem)?.ToString()); break; default: defaultPort = "0"; break; } var peerService = AzMonList.GetTagValue(ref tagObjects, SemanticConventions.AttributePeerService)?.ToString(); if (!string.IsNullOrEmpty(peerService)) { target = peerService; return(target); } if (type == PartBType.Http) { var httpHost = AzMonList.GetTagValue(ref tagObjects, SemanticConventions.AttributeHttpHost)?.ToString(); if (!string.IsNullOrEmpty(httpHost)) { string portSection = $":{defaultPort}"; if (httpHost.EndsWith(portSection, StringComparison.OrdinalIgnoreCase)) { var truncatedHost = httpHost.Substring(0, httpHost.IndexOf(portSection, StringComparison.OrdinalIgnoreCase)); target = truncatedHost; } else { target = httpHost; } return(target); } var httpUrl = AzMonList.GetTagValue(ref tagObjects, SemanticConventions.AttributeHttpUrl)?.ToString(); if (!string.IsNullOrEmpty(httpUrl) && Uri.TryCreate(httpUrl.ToString(), UriKind.RelativeOrAbsolute, out var uri) && uri.IsAbsoluteUri) { target = uri.Authority; if (!string.IsNullOrEmpty(target)) { return(target); } } } target = tagObjects.GetHostUsingNetPeerAttributes(); if (!string.IsNullOrEmpty(target)) { var netPeerPort = AzMonList.GetTagValue(ref tagObjects, SemanticConventions.AttributeNetPeerPort)?.ToString(); if (!string.IsNullOrEmpty(netPeerPort) && netPeerPort != defaultPort) { target = $"{target}:{netPeerPort}"; } return(target); } return(target); }
/// <summary> /// This method follows OpenTelemetry specification to retrieve http URL. /// Reference: https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/semantic_conventions/http.md#http-client. /// </summary> /// <param name="tagObjects">Activity Tags</param> /// <param name="url">URL</param> /// <param name="urlAuthority">Host name or IP address and the port number </param> internal static void GenerateUrlAndAuthority(this AzMonList tagObjects, out string url, out string urlAuthority) { urlAuthority = null; url = null; var httpurl = AzMonList.GetTagValue(ref tagObjects, SemanticConventions.AttributeHttpUrl); if (httpurl != null && Uri.TryCreate(httpurl.ToString(), UriKind.RelativeOrAbsolute, out var uri) && uri.IsAbsoluteUri) { url = uri.AbsoluteUri; urlAuthority = uri.Authority; return; } var httpScheme = AzMonList.GetTagValue(ref tagObjects, SemanticConventions.AttributeHttpScheme)?.ToString(); if (!string.IsNullOrWhiteSpace(httpScheme)) { var httpHost = AzMonList.GetTagValue(ref tagObjects, SemanticConventions.AttributeHttpHost)?.ToString(); if (!string.IsNullOrWhiteSpace(httpHost)) { var httpPortAndTarget = AzMonList.GetTagValues(ref tagObjects, SemanticConventions.AttributeHttpHostPort, SemanticConventions.AttributeHttpTarget); if (httpPortAndTarget[0] != null && httpPortAndTarget[0].ToString() != "80" && httpPortAndTarget[0].ToString() != "443") { var IsColon = (string.IsNullOrWhiteSpace(httpPortAndTarget[0].ToString()) ? null : Colon); url = $"{httpScheme}://{httpHost}{IsColon}{httpPortAndTarget[0]}{httpPortAndTarget[1]}"; urlAuthority = $"{httpHost}{IsColon}{httpPortAndTarget[0]}"; } else { url = $"{httpScheme}://{httpHost}{httpPortAndTarget[1]}"; urlAuthority = $"{httpHost}"; } return; } var netPeerName = AzMonList.GetTagValue(ref tagObjects, SemanticConventions.AttributeNetPeerName)?.ToString(); if (!string.IsNullOrWhiteSpace(netPeerName)) { var netPeerPortAndTarget = AzMonList.GetTagValues(ref tagObjects, SemanticConventions.AttributeNetPeerPort, SemanticConventions.AttributeHttpTarget); var IsColon = (string.IsNullOrWhiteSpace(netPeerPortAndTarget[0]?.ToString()) ? null : Colon); url = $"{httpScheme}{SchemePostfix}{netPeerName}{IsColon}{netPeerPortAndTarget[0]}{netPeerPortAndTarget[1]}"; urlAuthority = $"{netPeerName}{IsColon}{netPeerPortAndTarget[0]}"; return; } var netPeerIP = AzMonList.GetTagValue(ref tagObjects, SemanticConventions.AttributeNetPeerIp)?.ToString(); if (!string.IsNullOrWhiteSpace(netPeerIP)) { var netPeerPortAndTarget = AzMonList.GetTagValues(ref tagObjects, SemanticConventions.AttributeNetPeerPort, SemanticConventions.AttributeHttpTarget); var IsColon = (string.IsNullOrWhiteSpace(netPeerPortAndTarget[0]?.ToString()) ? null : Colon); url = $"{httpScheme}{SchemePostfix}{netPeerIP}{IsColon}{netPeerPortAndTarget[0]}{netPeerPortAndTarget[1]}"; urlAuthority = $"{netPeerIP}{IsColon}{netPeerPortAndTarget[0]}"; return; } } var host = AzMonList.GetTagValue(ref tagObjects, SemanticConventions.AttributeHttpHost)?.ToString(); if (!string.IsNullOrWhiteSpace(host)) { var httpPortAndTarget = AzMonList.GetTagValues(ref tagObjects, SemanticConventions.AttributeHttpHostPort, SemanticConventions.AttributeHttpTarget); var IsColon = (string.IsNullOrWhiteSpace(httpPortAndTarget[0]?.ToString()) ? null : Colon); url = $"{host}{IsColon}{httpPortAndTarget[0]}{httpPortAndTarget[1]}"; urlAuthority = $"{host}{IsColon}{httpPortAndTarget[0]}"; return; } url = string.IsNullOrWhiteSpace(url) ? null : url; }