//----------------------------------------------------------------------------- // // Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"). // You may not use this file except in compliance with the License. // A copy of the License is located at // // http://aws.amazon.com/apache2.0 // // or in the "license" file accompanying this file. This file 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 Amazon.Runtime.Internal.Util; using Amazon.XRay.Recorder.Core; using Amazon.XRay.Recorder.Core.Exceptions; using Amazon.XRay.Recorder.Core.Internal.Entities; using System.Collections.Concurrent; using System.Collections.Generic; using System.Data.Common; using System.Reflection; namespace Amazon.XRay.Recorder.AutoInstrumentation.Utils { public static class AgentUtil { private static readonly Logger _logger = Logger.GetLogger(typeof(AgentUtil)); private static readonly string EntityFramework = "EntityFramework"; private static readonly string[] UserIdFormatOptions = { "user id", "username", "user", "userid" }; // case insensitive private static readonly string[] DatabaseTypes = { "sqlserver", "sqlite", "postgresql", "mysql", "firebirdsql", "inmemory" , "cosmosdb" , "oracle" , "filecontextcore" , "jet" , "teradata" , "openedge" , "ibm" , "mycat" , "vfp"}; private static readonly string SqlServerCompact35 = "sqlservercompact35"; private static readonly string SqlServerCompact40 = "sqlservercompact40"; private static readonly string SqlServer = "sqlserver"; /// /// Extract database_type from . /// public static string GetDataBaseType(DbCommand command) { var typeString = command?.Connection?.GetType()?.FullName?.ToLower(); // Won't be the case for Sql query through System.Data.SqlClient and Microsoft.Data.SqlClient // only for the edge case of sql query through Entity Framework and Entity Framework Core if (string.IsNullOrEmpty(typeString)) { return EntityFramework; } if (typeString.Contains("microsoft.data.sqlclient") || typeString.Contains("system.data.sqlclient")) { return SqlServer; } if (typeString.Contains(SqlServerCompact35)) { return SqlServerCompact35; } if (typeString.Contains(SqlServerCompact40)) { return SqlServerCompact40; } foreach (var databaseType in DatabaseTypes) { if (typeString.Contains(databaseType)) { return databaseType; } } return typeString; } /// /// Extract user id from . /// public static object GetUserId(DbConnectionStringBuilder builder) { object value = null; foreach (string key in UserIdFormatOptions) { if (builder.TryGetValue(key, out value)) { break; } } return value; } /// /// Fetch property from reflection /// public static object FetchPropertyUsingReflection(object value, string item) { return value.GetType().GetTypeInfo().GetDeclaredProperty(item)?.GetValue(value); } /// /// Add AutoInstrumentation mark on the Segment /// public static void AddAutoInstrumentationMark() { try { var segment = AWSXRayRecorder.Instance.GetEntity() as Segment; if (segment == null) { _logger.DebugFormat("Unable to retrieve Segment from trace context"); return; } IDictionary awsAttribute = segment.Aws; if (awsAttribute == null) { _logger.DebugFormat("Unable to retrieve AWS dictionary to set the auto instrumentation flag."); } else { ConcurrentDictionary xrayAttribute = (ConcurrentDictionary)awsAttribute["xray"]; if (xrayAttribute == null) { _logger.DebugFormat("Unable to retrieve X-Ray dictionary from AWS dictionary of segment."); } else { // Set attribute "auto_instrumentation":true in the "xray" section of the segment xrayAttribute["auto_instrumentation"] = true; } } } catch (EntityNotAvailableException e) { AWSXRayRecorder.Instance.TraceContext.HandleEntityMissing(AWSXRayRecorder.Instance, e, "Failed to get entity since it is not available in trace context while processing ASPNET Core request."); } } /// /// Mark Segment/Subsegment from http status code /// /// public static void MarkEntityFromStatus(int statusCode) { if (statusCode >= 400 && statusCode <= 499) { AWSXRayRecorder.Instance.MarkError(); if (statusCode == 429) { AWSXRayRecorder.Instance.MarkThrottle(); } } else if (statusCode >= 500 && statusCode <= 599) { AWSXRayRecorder.Instance.MarkFault(); } } } }