diff --git a/CHANGELOG.md b/CHANGELOG.md index 2cdaeb91c..6190ce8c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,12 @@ # Changelog ## Version 2.6.0-beta4 +- [Remove CorrelationIdLookupHelper. Use TelemetryConfiguration.ApplicationIdProvider instead.](https://github.com/Microsoft/ApplicationInsights-dotnet-server/pull/880) With this change you can update URL to query application ID from which enables environments with reverse proxy configuration to access Application Insights ednpoints. - [Update Microsoft.AspNet.TelemetryCorrelation package to 1.0.1: Fix endless loop when activity stack is broken](https://github.com/aspnet/Microsoft.AspNet.TelemetryCorrelation/issues/22) - [Fix: Failed HTTP outgoing requests are not tracked on .NET Core](https://github.com/Microsoft/ApplicationInsights-dotnet-server/issues/780) - [Enable collection of Available Memory counter on Azure Web Apps](https://github.com/Microsoft/ApplicationInsights-dotnet-server/issues/585) + ## Version 2.6.0-beta3 - [Ignore Deprecated events if running under netcore20](https://github.com/Microsoft/ApplicationInsights-dotnet-server/issues/848) - [Implement unhandled exception auto-tracking (500 requests) for MVC 5 and WebAPI 2 applications.](https://github.com/Microsoft/ApplicationInsights-dotnet-server/pull/847) diff --git a/Src/Common/Common.projitems b/Src/Common/Common.projitems index ae60f8124..a5a0b3c2d 100644 --- a/Src/Common/Common.projitems +++ b/Src/Common/Common.projitems @@ -11,10 +11,8 @@ - - diff --git a/Src/Common/CorrelationIdLookupHelper.cs b/Src/Common/CorrelationIdLookupHelper.cs deleted file mode 100644 index 0cdf094e1..000000000 --- a/Src/Common/CorrelationIdLookupHelper.cs +++ /dev/null @@ -1,393 +0,0 @@ -namespace Microsoft.ApplicationInsights.Common -{ - using System; - using System.Collections.Concurrent; - using System.Collections.Generic; - using System.Globalization; - using System.IO; - using System.Net; -#if NETSTANDARD1_6 - using System.Net.Http; -#endif - using System.Threading.Tasks; - using Extensibility; - using Extensibility.Implementation.Tracing; - - /// - /// A store for instrumentation App Ids. This makes sure we don't query the public endpoint to find an app Id for the same instrumentation key more than once. - /// - internal class CorrelationIdLookupHelper : ICorrelationIdLookupHelper - { - /// - /// Max number of app ids to cache. - /// - private const int MAXSIZE = 100; - - private const string CorrelationIdFormat = "cid-v1:{0}"; - - private const string AppIdQueryApiRelativeUriFormat = "api/profiles/{0}/appId"; - - // We have arbitrarily chosen 5 second delay between trying to get app Id once we get a failure while trying to get it. - // This is to throttle tries between failures to safeguard against performance hits. The impact would be that telemetry generated during this interval would not have x-component correlation id. - private readonly TimeSpan intervalBetweenFailedRetries = TimeSpan.FromSeconds(30); - - private Uri endpointAddress; - - private ConcurrentDictionary knownCorrelationIds = new ConcurrentDictionary(); - - private ConcurrentDictionary fetchTasks = new ConcurrentDictionary(); - - // Stores failed instrumentation keys along with the time we tried to retrieve them. - private ConcurrentDictionary failingInstrumentationKeys = new ConcurrentDictionary(); - - private Func> provideAppId; - - /// - /// Initializes a new instance of the class mostly to be used by the test classes to provide an override for fetching appId logic. - /// - /// The delegate to be called to fetch the appId. - public CorrelationIdLookupHelper(Func> appIdProviderMethod) - { - if (appIdProviderMethod == null) - { - throw new ArgumentNullException(nameof(appIdProviderMethod)); - } - - this.provideAppId = appIdProviderMethod; - } - - /// - /// Initializes a new instance of the class mostly to be used by the test classes to seed the instrumentation key -> app Id relationship. - /// - /// A dictionary that contains known instrumentation key - app id relationship. - public CorrelationIdLookupHelper(Dictionary mapSeed) - { - if (mapSeed == null) - { - throw new ArgumentNullException(nameof(mapSeed)); - } - - this.provideAppId = this.FetchAppIdFromService; - - foreach (var entry in mapSeed) - { - this.knownCorrelationIds[entry.Key] = entry.Value; - } - } - - /// - /// Initializes a new instance of the class. - /// - /// Endpoint that is to be used to fetch appId. - public CorrelationIdLookupHelper(string endpointAddress) - { - if (string.IsNullOrEmpty(endpointAddress)) - { - throw new ArgumentNullException(nameof(endpointAddress)); - } - - Uri endpointUri = new Uri(endpointAddress); - - // Get the base URI, so that we can append the known relative segments to it. - this.endpointAddress = new Uri(endpointUri.AbsoluteUri.Substring(0, endpointUri.AbsoluteUri.Length - endpointUri.LocalPath.Length)); - - this.provideAppId = this.FetchAppIdFromService; - } - - /// - /// Retrieves the correlation id corresponding to a given instrumentation key. - /// - /// Instrumentation key string. - /// AppId corresponding to the provided instrumentation key. - /// true if correlationId was successfully retrieved; false otherwise. - public bool TryGetXComponentCorrelationId(string instrumentationKey, out string correlationId) - { - if (string.IsNullOrEmpty(instrumentationKey)) - { - // This method cannot throw - it's a Try... method. We cannot proceed any further. - correlationId = string.Empty; - return false; - } - - var found = this.knownCorrelationIds.TryGetValue(instrumentationKey, out correlationId); - - if (found) - { - return true; - } - else - { - // Simplistic cleanup to guard against this becoming a memory hog. - if (this.knownCorrelationIds.Keys.Count >= MAXSIZE) - { - this.knownCorrelationIds.Clear(); - } - - try - { - FailedResult lastFailedResult; - if (this.failingInstrumentationKeys.TryGetValue(instrumentationKey, out lastFailedResult)) - { - if (!lastFailedResult.ShouldRetry || DateTime.UtcNow - lastFailedResult.FailureTime <= this.intervalBetweenFailedRetries) - { - // We tried not too long ago and failed to retrieve app Id for this instrumentation key from breeze. Let wait a while before we try again. For now just report failure. - correlationId = string.Empty; - return false; - } - } - - // We only want one task to be there to fetch the ikey. If initial requests come in a bunch, only one of them gets to take responsibility of creating the fetch task. Rest return. - if (this.fetchTasks.TryAdd(instrumentationKey, int.MinValue)) - { - this.provideAppId(instrumentationKey.ToLowerInvariant()) - .ContinueWith((appId) => - { - try - { - this.GenerateCorrelationIdAndAddToDictionary(instrumentationKey, appId.Result); - } - catch (Exception ex) - { - this.RegisterFailure(instrumentationKey, ex); - } - finally - { - this.fetchTasks.TryRemove(instrumentationKey, out int taskId); - } - }); - - return false; - } - else - { - // Fetch tasks are scheduled - don't queue a task. - correlationId = string.Empty; - return false; - } - } - catch (Exception ex) - { - this.RegisterFailure(instrumentationKey, ex); - - correlationId = string.Empty; - return false; - } - } - } - - /// - /// This method is purely a test helper at this point. It checks whether the task to get app ID is still running. - /// - /// True if fetch task is still in progress, false otherwise. - public bool IsFetchAppInProgress(string ikey) - { - int value; - return this.fetchTasks.TryGetValue(ikey, out value); - } - - /// - /// Format and store an iKey and appId pair into the dictionary of known correlation ids. - /// - /// Instrumentation Key is expected to be a Guid string. - /// Application Id is expected to be a Guid string. App Id needs to be Http Header safe, and all non-ASCII characters will be removed. - /// To protect against injection attacks, AppId will be truncated to a maximum length. - private void GenerateCorrelationIdAndAddToDictionary(string ikey, string appId) - { - // Arbitrary maximum length to guard against injections. - appId = StringUtilities.EnforceMaxLength(appId, InjectionGuardConstants.AppIdMaxLengeth); - - if (string.IsNullOrWhiteSpace(appId)) - { - return; - } - - appId = HeadersUtilities.SanitizeString(appId); - if (!string.IsNullOrEmpty(appId)) - { - this.knownCorrelationIds[ikey] = string.Format(CultureInfo.InvariantCulture, CorrelationIdFormat, appId); - } - } - - /// - /// Retrieves the app id given the instrumentation key. - /// - /// Instrumentation key for which app id is to be retrieved. - /// App id. - private async Task FetchAppIdFromService(string instrumentationKey) - { -#if NETSTANDARD1_6 - string result = null; - Uri appIdEndpoint = this.GetAppIdEndPointUri(instrumentationKey); - - using (HttpClient client = new HttpClient()) - { - var resultMessage = await client.GetAsync(appIdEndpoint).ConfigureAwait(false); - if (resultMessage.IsSuccessStatusCode) - { - result = await resultMessage.Content.ReadAsStringAsync().ConfigureAwait(false); - } - else - { - this.RegisterFetchFailure(instrumentationKey, resultMessage.StatusCode); - } - } - - return result; -#else - try - { - SdkInternalOperationsMonitor.Enter(); - - string result = null; - Uri appIdEndpoint = this.GetAppIdEndPointUri(instrumentationKey); - WebRequest request = WebRequest.Create(appIdEndpoint); - request.Method = "GET"; - - using (HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync().ConfigureAwait(false)) - { - if (response.StatusCode == HttpStatusCode.OK) - { - using (StreamReader reader = new StreamReader(response.GetResponseStream())) - { - result = await reader.ReadToEndAsync(); - } - } - else - { - this.RegisterFetchFailure(instrumentationKey, response.StatusCode); - } - } - - return result; - } - finally - { - SdkInternalOperationsMonitor.Exit(); - } -#endif - } - - /// - /// Strips off any relative path at the end of the base URI and then appends the known relative path to get the app id uri. - /// - /// AI resource's instrumentation key. - /// Computed Uri. - private Uri GetAppIdEndPointUri(string instrumentationKey) - { - return new Uri(this.endpointAddress, string.Format(CultureInfo.InvariantCulture, AppIdQueryApiRelativeUriFormat, instrumentationKey)); - } - - /// - /// Registers failure for further action in future. - /// - /// Instrumentation key for which the failure occurred. - /// Exception indicating failure. - private void RegisterFailure(string instrumentationKey, Exception ex) - { -#if !NETSTANDARD1_6 - var ae = ex as AggregateException; - - if (ae != null) - { - ae = ae.Flatten(); - if (ae.InnerException != null) - { - this.RegisterFailure(instrumentationKey, ae.InnerException); - return; - } - } - - var webException = ex as WebException; - if (webException != null && webException.Response != null) - { - this.failingInstrumentationKeys[instrumentationKey] = new FailedResult( - DateTime.UtcNow, - ((HttpWebResponse)webException.Response).StatusCode); - } - else - { -#endif - this.failingInstrumentationKeys[instrumentationKey] = new FailedResult(DateTime.UtcNow); -#if !NETSTANDARD1_6 - } -#endif - - AppMapCorrelationEventSource.Log.FetchAppIdFailed(this.GetExceptionDetailString(ex)); - } - - /// - /// FetchAppIdFromService failed. - /// Registers failure for further action in future. - /// - /// Instrumentation key for which the failure occurred. - /// Response code from AppId Endpoint. - private void RegisterFetchFailure(string instrumentationKey, HttpStatusCode httpStatusCode) - { - this.failingInstrumentationKeys[instrumentationKey] = new FailedResult(DateTime.UtcNow, httpStatusCode); - - AppMapCorrelationEventSource.Log.FetchAppIdFailedWithResponseCode(httpStatusCode.ToString()); - } - - private string GetExceptionDetailString(Exception ex) - { - var ae = ex as AggregateException; - if (ae != null) - { - return ae.Flatten().InnerException.ToInvariantString(); - } - - return ex.ToInvariantString(); - } - - /// - /// Structure that represents a failed fetch app Id call. - /// - private class FailedResult - { - /// - /// Initializes a new instance of the class. - /// - /// Time when the failure occurred. - /// Failure response code. - public FailedResult(DateTime failureTime, HttpStatusCode failureCode) - { - this.FailureTime = failureTime; - this.FailureCode = (int)failureCode; - } - - /// - /// Initializes a new instance of the class. - /// - /// Time when the failure occurred. - public FailedResult(DateTime failureTime) - { - this.FailureTime = failureTime; - - // Unknown failure code. - this.FailureCode = int.MinValue; - } - - /// - /// Gets the time of failure. - /// - public DateTime FailureTime { get; private set; } - - /// - /// Gets the integer value for response code representing the type of failure. - /// - public int FailureCode { get; private set; } - - /// - /// Gets a value indicating whether the failure is likely to go away when a retry happens. - /// - public bool ShouldRetry - { - get - { - // If not in the 400 range. - return !(this.FailureCode >= 400 && this.FailureCode < 500); - } - } - } - } -} diff --git a/Src/Common/ICorrelationIdLookupHelper.cs b/Src/Common/ICorrelationIdLookupHelper.cs deleted file mode 100644 index 6a1868385..000000000 --- a/Src/Common/ICorrelationIdLookupHelper.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace Microsoft.ApplicationInsights.Common -{ - /// - /// An interface for getting a correlation id from a provided instrumentation key. - /// - internal interface ICorrelationIdLookupHelper - { - /// - /// Retrieves the correlation id corresponding to a given instrumentation key. - /// - /// Instrumentation key string. - /// AppId corresponding to the provided instrumentation key. - /// true if correlationId was successfully retrieved; false otherwise. - bool TryGetXComponentCorrelationId(string instrumentationKey, out string correlationId); - } -} diff --git a/Src/DependencyCollector/Net45.Tests/DependencyTrackingTelemetryModuleHttpTest.cs b/Src/DependencyCollector/Net45.Tests/DependencyTrackingTelemetryModuleHttpTest.cs index 5a25da0e8..8b96430ca 100644 --- a/Src/DependencyCollector/Net45.Tests/DependencyTrackingTelemetryModuleHttpTest.cs +++ b/Src/DependencyCollector/Net45.Tests/DependencyTrackingTelemetryModuleHttpTest.cs @@ -218,7 +218,6 @@ public void OnBeginOnEndAreNotCalledForAppInsightsUrl() { using (var module = new DependencyTrackingTelemetryModule()) { - module.ProfileQueryEndpoint = FakeProfileApiEndpoint; module.Initialize(this.config); using (var listener = new TestEventListener()) @@ -561,7 +560,6 @@ private DependencyTrackingTelemetryModule CreateDependencyTrackingModule(bool en module.DisableDiagnosticSourceInstrumentation = true; } - module.ProfileQueryEndpoint = FakeProfileApiEndpoint; module.Initialize(this.config); Assert.AreEqual(enableDiagnosticSource, DependencyTableStore.IsDesktopHttpDiagnosticSourceActivated); diff --git a/Src/DependencyCollector/NuGet/ApplicationInsights.config.install.xdt b/Src/DependencyCollector/NuGet/ApplicationInsights.config.install.xdt index 07d4a8656..2939c9a5d 100644 --- a/Src/DependencyCollector/NuGet/ApplicationInsights.config.install.xdt +++ b/Src/DependencyCollector/NuGet/ApplicationInsights.config.install.xdt @@ -23,4 +23,5 @@ + \ No newline at end of file diff --git a/Src/DependencyCollector/NuGet/ApplicationInsights.config.uninstall.xdt b/Src/DependencyCollector/NuGet/ApplicationInsights.config.uninstall.xdt index 6dffbb49b..be9cbd175 100644 --- a/Src/DependencyCollector/NuGet/ApplicationInsights.config.uninstall.xdt +++ b/Src/DependencyCollector/NuGet/ApplicationInsights.config.uninstall.xdt @@ -7,4 +7,7 @@ + + + \ No newline at end of file diff --git a/Src/DependencyCollector/Shared.Tests/CorrelationIdLookupHelperTests.cs b/Src/DependencyCollector/Shared.Tests/CorrelationIdLookupHelperTests.cs deleted file mode 100644 index ca9ef845f..000000000 --- a/Src/DependencyCollector/Shared.Tests/CorrelationIdLookupHelperTests.cs +++ /dev/null @@ -1,81 +0,0 @@ -namespace Microsoft.ApplicationInsights.Tests -{ - using System; - using System.Collections.Generic; - using System.Text; - using System.Threading; - using System.Threading.Tasks; - using Microsoft.ApplicationInsights.Common; - using Microsoft.VisualStudio.TestTools.UnitTesting; - - /// - /// Correlation Id Lookup helper tests. - /// - [TestClass] - public sealed class CorrelationIdLookupHelperTests - { - /// - /// Makes sure that the first call to get app id returns false, because it hasn't been fetched yet. - /// But the second call is able to get it from the dictionary. - /// - [TestMethod] - public void CorrelationIdLookupHelperReturnsAppIdOnSecondCall() - { - var correlationIdLookupHelper = new CorrelationIdLookupHelper((ikey) => - { - // Pretend App Id is the same as Ikey - return Task.FromResult(ikey); - }); - - string instrumenationKey = Guid.NewGuid().ToString(); - string cid; - - // First call returns false; - Assert.IsFalse(correlationIdLookupHelper.TryGetXComponentCorrelationId(instrumenationKey, out cid)); - - // Let's wait for the task to complete. It should be really quick (based on the test setup) but not immediate. - while (correlationIdLookupHelper.IsFetchAppInProgress(instrumenationKey)) - { - Thread.Sleep(10); // wait 10 ms. - } - - // Once fetch is complete, subsequent calls should return correlation id. - Assert.IsTrue(correlationIdLookupHelper.TryGetXComponentCorrelationId(instrumenationKey, out cid)); - } - - /// - /// Test that if an malicious value is returned, that value will be truncated. - /// - [TestMethod] - public void CorrelationIdLookupHelperTruncatesMaliciousValue() - { - // 50 character string. - var value = "a123456789b123546789c123456789d123456798e123456789"; - - // An arbitrary string that is expected to be truncated. - var malicious = "00000000000000000000000000000000000000000000000000000000000"; - - var cidPrefix = "cid-v1:"; - - var correlationIdLookupHelper = new CorrelationIdLookupHelper((ikey) => - { - return Task.FromResult(value + malicious); - }); - - string instrumenationKey = Guid.NewGuid().ToString(); - - // first request fails because this will create the fetch task. - Assert.IsFalse(correlationIdLookupHelper.TryGetXComponentCorrelationId(instrumenationKey, out string ignore)); - - // Let's wait for the task to complete. It should be really quick (based on the test setup) but not immediate. - while (correlationIdLookupHelper.IsFetchAppInProgress(instrumenationKey)) - { - Thread.Sleep(10); // wait 10 ms. - } - - // Once fetch is complete, subsequent calls should return correlation id. - Assert.IsTrue(correlationIdLookupHelper.TryGetXComponentCorrelationId(instrumenationKey, out string cid)); - Assert.AreEqual(cidPrefix + value, cid); - } - } -} diff --git a/Src/DependencyCollector/Shared.Tests/DependencyCollector.Shared.Tests.projitems b/Src/DependencyCollector/Shared.Tests/DependencyCollector.Shared.Tests.projitems index f78b435ea..c5a67ee9d 100644 --- a/Src/DependencyCollector/Shared.Tests/DependencyCollector.Shared.Tests.projitems +++ b/Src/DependencyCollector/Shared.Tests/DependencyCollector.Shared.Tests.projitems @@ -9,7 +9,6 @@ Microsoft.ApplicationInsights.DependencyCollector - @@ -22,7 +21,6 @@ - diff --git a/Src/DependencyCollector/Shared.Tests/Implementation/DependencyCollectorDiagnosticListenerTests.Netstandard16.cs b/Src/DependencyCollector/Shared.Tests/Implementation/DependencyCollectorDiagnosticListenerTests.Netstandard16.cs index 9f6f71c7c..bdfebed01 100644 --- a/Src/DependencyCollector/Shared.Tests/Implementation/DependencyCollectorDiagnosticListenerTests.Netstandard16.cs +++ b/Src/DependencyCollector/Shared.Tests/Implementation/DependencyCollectorDiagnosticListenerTests.Netstandard16.cs @@ -28,14 +28,14 @@ public partial class DependencyCollectorDiagnosticListenerTests private const string RequestUrlWithScheme = "https://" + RequestUrl; private const string HttpOkResultCode = "200"; private const string NotFoundResultCode = "404"; - private const string MockAppId = "MOCK_APP_ID"; - private const string MockAppId2 = "MOCK_APP_ID_2"; private readonly List sentTelemetry = new List(); - private string instrumentationKey; + private string testInstrumentationKey1 = nameof(testInstrumentationKey1); + private string testInstrumentationKey2 = nameof(testInstrumentationKey2); + private string testApplicationId1 = nameof(testApplicationId1); + private string testApplicationId2 = nameof(testApplicationId2); private StubTelemetryChannel telemetryChannel; - private MockCorrelationIdLookupHelper mockCorrelationIdLookupHelper; private HttpCoreDiagnosticSourceListener listener; /// @@ -44,32 +44,26 @@ public partial class DependencyCollectorDiagnosticListenerTests [TestInitialize] public void Initialize() { - this.instrumentationKey = Guid.NewGuid().ToString(); - this.telemetryChannel = new StubTelemetryChannel() { EndpointAddress = "https://endpointaddress", OnSend = this.sentTelemetry.Add }; - this.mockCorrelationIdLookupHelper = new MockCorrelationIdLookupHelper(new Dictionary() - { - [this.instrumentationKey] = MockAppId - }); + this.testInstrumentationKey1 = Guid.NewGuid().ToString(); var configuration = new TelemetryConfiguration { TelemetryChannel = this.telemetryChannel, - InstrumentationKey = this.instrumentationKey, + InstrumentationKey = this.testInstrumentationKey1, + ApplicationIdProvider = new MockApplicationIdProvider(this.testInstrumentationKey1, this.testApplicationId1) }; configuration.TelemetryInitializers.Add(new OperationCorrelationTelemetryInitializer()); this.listener = new HttpCoreDiagnosticSourceListener( configuration, - this.telemetryChannel.EndpointAddress, setComponentCorrelationHttpHeaders: true, - correlationDomainExclusionList: new string[] { "excluded.host.com" }, - correlationIdLookupHelper: this.mockCorrelationIdLookupHelper); + correlationDomainExclusionList: new string[] { "excluded.host.com" }); } /// @@ -212,7 +206,7 @@ public void OnRequestWithRequestEvent() Assert.AreEqual(string.Empty, telemetry.ResultCode); Assert.AreEqual(true, telemetry.Success); - Assert.AreEqual(MockAppId, GetRequestContextKeyValue(request, RequestResponseHeaders.RequestContextCorrelationSourceKey)); + Assert.AreEqual(this.testApplicationId1, GetRequestContextKeyValue(request, RequestResponseHeaders.RequestContextCorrelationSourceKey)); Assert.AreEqual(null, GetRequestContextKeyValue(request, RequestResponseHeaders.StandardRootIdHeader)); var legacyParentIdHeader = GetRequestHeaderValues(request, RequestResponseHeaders.StandardParentIdHeader).Single(); @@ -328,14 +322,14 @@ public void OnResponseWithSuccessfulResponseEventWithMatchingRequestAndSameTarge DependencyTelemetry telemetry = dependency.Telemetry; Assert.AreEqual(string.Empty, telemetry.ResultCode); - Assert.AreEqual(true, telemetry.Success); + Assert.AreEqual(true, telemetry.Success, "request was not successful"); HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK) { RequestMessage = request }; - response.Headers.Add(RequestResponseHeaders.RequestContextCorrelationTargetKey, MockAppId); + response.Headers.Add(RequestResponseHeaders.RequestContextCorrelationTargetKey, this.testApplicationId1); this.listener.OnResponse(response, loggingRequestId); Assert.IsFalse(this.listener.PendingDependencyTelemetry.TryGetValue(request, out dependency)); @@ -345,7 +339,7 @@ public void OnResponseWithSuccessfulResponseEventWithMatchingRequestAndSameTarge Assert.AreEqual(RemoteDependencyConstants.HTTP, telemetry.Type); Assert.AreEqual(RequestUrl, telemetry.Target); Assert.AreEqual(HttpOkResultCode, telemetry.ResultCode); - Assert.AreEqual(true, telemetry.Success); + Assert.AreEqual(true, telemetry.Success, "response was not successful"); } /// @@ -370,7 +364,7 @@ public void OnResponseWithFailedResponseEventWithMatchingRequestAndSameTargetIns RequestMessage = request }; - response.Headers.Add(RequestResponseHeaders.RequestContextCorrelationTargetKey, MockAppId); + response.Headers.Add(RequestResponseHeaders.RequestContextCorrelationTargetKey, this.testApplicationId1); this.listener.OnResponse(response, loggingRequestId); Assert.IsFalse(this.listener.PendingDependencyTelemetry.TryGetValue(request, out dependency)); @@ -405,7 +399,7 @@ public void OnResponseWithSuccessfulResponseEventWithMatchingRequestAndDifferent RequestMessage = request }; - string targetApplicationId = MockAppId2; + string targetApplicationId = this.testApplicationId2; HttpHeadersUtilities.SetRequestContextKeyValue(response.Headers, RequestResponseHeaders.RequestContextCorrelationTargetKey, targetApplicationId); this.listener.OnResponse(response, loggingRequestId); @@ -441,7 +435,7 @@ public void OnResponseWithFailedResponseEventWithMatchingRequestAndDifferentTarg RequestMessage = request }; - string targetApplicationId = MockAppId2; + string targetApplicationId = this.testApplicationId2; HttpHeadersUtilities.SetRequestContextKeyValue(response.Headers, RequestResponseHeaders.RequestContextCorrelationTargetKey, targetApplicationId); this.listener.OnResponse(response, loggingRequestId); diff --git a/Src/DependencyCollector/Shared.Tests/Implementation/DependencyCollectorDiagnosticListenerTests.Netstandard20.cs b/Src/DependencyCollector/Shared.Tests/Implementation/DependencyCollectorDiagnosticListenerTests.Netstandard20.cs index f41e8ea8b..94ac25612 100644 --- a/Src/DependencyCollector/Shared.Tests/Implementation/DependencyCollectorDiagnosticListenerTests.Netstandard20.cs +++ b/Src/DependencyCollector/Shared.Tests/Implementation/DependencyCollectorDiagnosticListenerTests.Netstandard20.cs @@ -38,7 +38,7 @@ public void OnActivityStartInjectsHeaders() // check only legacy headers here Assert.AreEqual(activity.RootId, request.Headers.GetValues(RequestResponseHeaders.StandardRootIdHeader).Single()); Assert.AreEqual(activity.Id, request.Headers.GetValues(RequestResponseHeaders.StandardParentIdHeader).Single()); - Assert.AreEqual(MockAppId, GetRequestContextKeyValue(request, RequestResponseHeaders.RequestContextCorrelationSourceKey)); + Assert.AreEqual(this.testApplicationId1, GetRequestContextKeyValue(request, RequestResponseHeaders.RequestContextCorrelationSourceKey)); } /// diff --git a/Src/DependencyCollector/Shared.Tests/Implementation/DesktopDiagnosticSourceHttpProcessingTests.cs b/Src/DependencyCollector/Shared.Tests/Implementation/DesktopDiagnosticSourceHttpProcessingTests.cs index 291e24476..1687ce33c 100644 --- a/Src/DependencyCollector/Shared.Tests/Implementation/DesktopDiagnosticSourceHttpProcessingTests.cs +++ b/Src/DependencyCollector/Shared.Tests/Implementation/DesktopDiagnosticSourceHttpProcessingTests.cs @@ -24,12 +24,13 @@ namespace Microsoft.ApplicationInsights.Tests public class DesktopDiagnosticSourceHttpProcessingTests { #region Fields - private const string RandomAppIdEndpoint = "http://app.id.endpoint"; // appIdEndpoint - this really won't be used for tests because of the app id provider override. private const int TimeAccuracyMilliseconds = 50; + private const string TestInstrumentationKey = nameof(TestInstrumentationKey); + private const string TestApplicationId = nameof(TestApplicationId); private Uri testUrl = new Uri("http://www.microsoft.com/"); private int sleepTimeMsecBetweenBeginAndEnd = 100; private TelemetryConfiguration configuration; - private List sendItems; + private List sendItems = new List(); private DesktopDiagnosticSourceHttpProcessing httpDesktopProcessingFramework; #endregion //Fields @@ -38,12 +39,14 @@ public class DesktopDiagnosticSourceHttpProcessingTests [TestInitialize] public void TestInitialize() { - this.configuration = new TelemetryConfiguration(); - this.sendItems = new List(); - this.configuration.TelemetryChannel = new StubTelemetryChannel { OnSend = item => this.sendItems.Add(item) }; - this.configuration.InstrumentationKey = Guid.NewGuid().ToString(); - this.httpDesktopProcessingFramework = new DesktopDiagnosticSourceHttpProcessing(this.configuration, new CacheBasedOperationHolder("testCache", 100 * 1000), /*setCorrelationHeaders*/ true, new List(), RandomAppIdEndpoint); - this.httpDesktopProcessingFramework.OverrideCorrelationIdLookupHelper(new CorrelationIdLookupHelper(new Dictionary { { this.configuration.InstrumentationKey, "cid-v1:" + this.configuration.InstrumentationKey } })); + this.configuration = new TelemetryConfiguration() + { + TelemetryChannel = new StubTelemetryChannel { OnSend = item => this.sendItems.Add(item) }, + InstrumentationKey = TestInstrumentationKey, + ApplicationIdProvider = new MockApplicationIdProvider(TestInstrumentationKey, TestApplicationId) + }; + + this.httpDesktopProcessingFramework = new DesktopDiagnosticSourceHttpProcessing(this.configuration, new CacheBasedOperationHolder("testCache", 100 * 1000), /*setCorrelationHeaders*/ true, new List()); DependencyTableStore.IsDesktopHttpDiagnosticSourceActivated = false; } @@ -224,8 +227,7 @@ public void RddTestHttpDesktopProcessingFrameworkOnBeginSkipsAddingSourceHeaderP this.configuration, new CacheBasedOperationHolder("testCache", 100 * 1000), false, - new List(), - RandomAppIdEndpoint); + new List()); localHttpProcessingFramework.OnBegin(request); Assert.IsNull(request.Headers[RequestResponseHeaders.RequestContextHeader]); @@ -236,8 +238,8 @@ public void RddTestHttpDesktopProcessingFrameworkOnBeginSkipsAddingSourceHeaderP this.configuration, new CacheBasedOperationHolder("testCache", 100 * 1000), true, - exclusionList, - RandomAppIdEndpoint); + exclusionList); + localHttpProcessingFramework.OnBegin(request); Assert.IsNull(request.Headers[RequestResponseHeaders.RequestContextHeader]); Assert.AreEqual(0, request.Headers.Keys.Cast().Count(x => x.StartsWith("x-ms-", StringComparison.OrdinalIgnoreCase))); diff --git a/Src/DependencyCollector/Shared.Tests/Implementation/FrameworkHttpProcessingTest.cs b/Src/DependencyCollector/Shared.Tests/Implementation/FrameworkHttpProcessingTest.cs index 88f1ea302..6d1989505 100644 --- a/Src/DependencyCollector/Shared.Tests/Implementation/FrameworkHttpProcessingTest.cs +++ b/Src/DependencyCollector/Shared.Tests/Implementation/FrameworkHttpProcessingTest.cs @@ -4,12 +4,9 @@ using System.Collections.Generic; using System.Diagnostics; using System.Globalization; - using System.Linq; using System.Net; using System.Threading; - using System.Threading.Tasks; using Microsoft.ApplicationInsights.Channel; - using Microsoft.ApplicationInsights.Common; using Microsoft.ApplicationInsights.DataContracts; using Microsoft.ApplicationInsights.DependencyCollector; using Microsoft.ApplicationInsights.DependencyCollector.Implementation; @@ -26,11 +23,13 @@ public sealed class FrameworkHttpProcessingTest : IDisposable #region Fields private const string RandomAppIdEndpoint = "http://app.id.endpoint"; // appIdEndpoint - this really won't be used for tests because of the app id provider override. private const int TimeAccuracyMilliseconds = 50; + private const string TestInstrumentationKey = nameof(TestInstrumentationKey); + private const string TestApplicationId = nameof(TestApplicationId); private Uri testUrl = new Uri("http://www.microsoft.com/"); private Uri testUrlNonStandardPort = new Uri("http://www.microsoft.com:911/"); private int sleepTimeMsecBetweenBeginAndEnd = 100; private TelemetryConfiguration configuration; - private List sendItems; + private List sendItems = new List(); private FrameworkHttpProcessing httpProcessingFramework; private CacheBasedOperationHolder cache = new CacheBasedOperationHolder("testCache", 100 * 1000); #endregion //Fields @@ -40,12 +39,13 @@ public sealed class FrameworkHttpProcessingTest : IDisposable [TestInitialize] public void TestInitialize() { - this.configuration = new TelemetryConfiguration(); - this.sendItems = new List(); - this.configuration.TelemetryChannel = new StubTelemetryChannel { OnSend = item => this.sendItems.Add(item) }; - this.configuration.InstrumentationKey = Guid.NewGuid().ToString(); - this.httpProcessingFramework = new FrameworkHttpProcessing(this.configuration, this.cache, /*setCorrelationHeaders*/ true, new List(), RandomAppIdEndpoint); - this.httpProcessingFramework.OverrideCorrelationIdLookupHelper(new CorrelationIdLookupHelper(new Dictionary { { this.configuration.InstrumentationKey, "cid-v1:" + this.configuration.InstrumentationKey } })); + this.configuration = new TelemetryConfiguration() + { + TelemetryChannel = new StubTelemetryChannel { OnSend = item => this.sendItems.Add(item) }, + InstrumentationKey = TestInstrumentationKey, + ApplicationIdProvider = new MockApplicationIdProvider(TestInstrumentationKey, TestApplicationId) + }; + this.httpProcessingFramework = new FrameworkHttpProcessing(this.configuration, this.cache, /*setCorrelationHeaders*/ true, new List()); DependencyTableStore.IsDesktopHttpDiagnosticSourceActivated = false; } diff --git a/Src/DependencyCollector/Shared.Tests/Implementation/MockCorrelationIdLookupHelper.cs b/Src/DependencyCollector/Shared.Tests/Implementation/MockCorrelationIdLookupHelper.cs deleted file mode 100644 index 381ae03f9..000000000 --- a/Src/DependencyCollector/Shared.Tests/Implementation/MockCorrelationIdLookupHelper.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace Microsoft.ApplicationInsights.Tests -{ - using System.Collections.Generic; - using Microsoft.ApplicationInsights.Common; - - internal class MockCorrelationIdLookupHelper : ICorrelationIdLookupHelper - { - private readonly Dictionary instrumentationKeyToCorrelationIdMap; - - public MockCorrelationIdLookupHelper(Dictionary instrumentationKeyToCorrelationIdMap) - { - this.instrumentationKeyToCorrelationIdMap = instrumentationKeyToCorrelationIdMap; - } - - public bool TryGetXComponentCorrelationId(string instrumentationKey, out string correlationId) - { - return this.instrumentationKeyToCorrelationIdMap.TryGetValue(instrumentationKey, out correlationId); - } - } -} diff --git a/Src/DependencyCollector/Shared.Tests/Implementation/ProfilerHttpProcessingTest.cs b/Src/DependencyCollector/Shared.Tests/Implementation/ProfilerHttpProcessingTest.cs index e0e6e75de..f5697ecae 100644 --- a/Src/DependencyCollector/Shared.Tests/Implementation/ProfilerHttpProcessingTest.cs +++ b/Src/DependencyCollector/Shared.Tests/Implementation/ProfilerHttpProcessingTest.cs @@ -10,8 +10,6 @@ using System.Linq; using System.Net; using System.Threading; - using System.Threading.Tasks; - using System.Web; using Common; using Microsoft.ApplicationInsights.Channel; @@ -32,13 +30,14 @@ public sealed class ProfilerHttpProcessingTest : IDisposable { #region Fields private const int TimeAccuracyMilliseconds = 150; // this may be big number when under debugger - private const string RandomAppIdEndpoint = "http://app.id.endpoint"; // appIdEndpoint - this really won't be used for tests because of the app id provider override. + private const string TestInstrumentationKey = nameof(TestInstrumentationKey); + private const string TestApplicationId = nameof(TestApplicationId); private TelemetryConfiguration configuration; private Uri testUrl = new Uri("http://www.microsoft.com/"); private Uri testUrlNonStandardPort = new Uri("http://www.microsoft.com:911/"); - private List sendItems; + private List sendItems = new List(); private int sleepTimeMsecBetweenBeginAndEnd = 100; - private Exception ex; + private Exception ex = new Exception(); private ProfilerHttpProcessing httpProcessingProfiler; #endregion //Fields @@ -47,7 +46,20 @@ public sealed class ProfilerHttpProcessingTest : IDisposable [TestInitialize] public void TestInitialize() { - this.Initialize(Guid.NewGuid().ToString()); + this.configuration = new TelemetryConfiguration() + { + TelemetryChannel = new StubTelemetryChannel { OnSend = item => this.sendItems.Add(item) }, + InstrumentationKey = TestInstrumentationKey, + ApplicationIdProvider = new MockApplicationIdProvider(TestInstrumentationKey, TestApplicationId) + }; + + this.configuration.TelemetryInitializers.Add(new OperationCorrelationTelemetryInitializer()); + this.httpProcessingProfiler = new ProfilerHttpProcessing( + this.configuration, + null, + new ObjectInstanceBasedOperationHolder(), + true /*setCorrelationHeaders*/, + new List()); } [TestCleanup] @@ -112,23 +124,11 @@ public void RddTestHttpProcessingProfilerOnEndAddsAppIdToTargetField() // This will not match the current component's App ID. Hence represents an external component. string ikey = "0935FC42-FE1A-4C67-975C-0C9D5CBDEE8E"; string appId = ikey + "-appId"; - - this.httpProcessingProfiler.OverrideCorrelationIdLookupHelper(new CorrelationIdLookupHelper(new Dictionary - { - { - ikey, - "cid-v1:" + appId - }, - { - this.configuration.InstrumentationKey, - "cid-v1:" + this.configuration.InstrumentationKey + "-appId" - } - })); - + this.SimulateWebRequestResponseWithAppId(appId); Assert.AreEqual(1, this.sendItems.Count, "Only one telemetry item should be sent"); - Assert.AreEqual(this.testUrl.Host + " | " + this.GetCorrelationIdValue(appId), ((DependencyTelemetry)this.sendItems[0]).Target); + Assert.AreEqual(this.testUrl.Host + " | " + appId, ((DependencyTelemetry)this.sendItems[0]).Target); } /// @@ -138,9 +138,7 @@ public void RddTestHttpProcessingProfilerOnEndAddsAppIdToTargetField() [Description("Validates DependencyTelemetry does not send correlation ID if the IKey is from the same component")] public void RddTestHttpProcessingProfilerOnEndDoesNotAddAppIdToTargetFieldForInternalComponents() { - string appId = this.configuration.InstrumentationKey + "-appId"; - - this.SimulateWebRequestResponseWithAppId(appId); + this.SimulateWebRequestResponseWithAppId(TestApplicationId); Assert.AreEqual(1, this.sendItems.Count, "Only one telemetry item should be sent"); @@ -257,13 +255,13 @@ public void RddTestHttpProcessingProfilerOnBeginSkipsAddingSourceHeaderPerConfig Assert.IsNull(request.Headers[RequestResponseHeaders.RequestContextHeader]); Assert.AreEqual(0, request.Headers.Keys.Cast().Where((x) => { return x.StartsWith("x-ms-", StringComparison.OrdinalIgnoreCase); }).Count()); - var httpProcessingProfiler = new ProfilerHttpProcessing(this.configuration, null, new ObjectInstanceBasedOperationHolder(), /*setCorrelationHeaders*/ false, new List(), RandomAppIdEndpoint); + var httpProcessingProfiler = new ProfilerHttpProcessing(this.configuration, null, new ObjectInstanceBasedOperationHolder(), /*setCorrelationHeaders*/ false, new List()); httpProcessingProfiler.OnBeginForGetResponse(request); Assert.IsNull(request.Headers[RequestResponseHeaders.RequestContextHeader]); Assert.AreEqual(0, request.Headers.Keys.Cast().Where((x) => { return x.StartsWith("x-ms-", StringComparison.OrdinalIgnoreCase); }).Count()); ICollection exclusionList = new SanitizedHostList() { "randomstringtoexclude", hostnamepart }; - httpProcessingProfiler = new ProfilerHttpProcessing(this.configuration, null, new ObjectInstanceBasedOperationHolder(), /*setCorrelationHeaders*/ true, exclusionList, RandomAppIdEndpoint); + httpProcessingProfiler = new ProfilerHttpProcessing(this.configuration, null, new ObjectInstanceBasedOperationHolder(), /*setCorrelationHeaders*/ true, exclusionList); httpProcessingProfiler.OnBeginForGetResponse(request); Assert.IsNull(request.Headers[RequestResponseHeaders.RequestContextHeader]); Assert.AreEqual(0, request.Headers.Keys.Cast().Where((x) => { return x.StartsWith("x-ms-", StringComparison.OrdinalIgnoreCase); }).Count()); @@ -880,42 +878,10 @@ private void SimulateWebRequestWithGivenRequestContextHeaderValue(string headerV this.httpProcessingProfiler.OnBeginForGetResponse(request); var objectReturned = this.httpProcessingProfiler.OnEndForGetResponse(null, returnObjectPassed, request); } - - private string GetCorrelationIdValue(string appId) - { - return string.Format(CultureInfo.InvariantCulture, "cid-v1:{0}", appId); - } - + private string GetCorrelationIdHeaderValue(string appId) { - return string.Format(CultureInfo.InvariantCulture, "{0}=cid-v1:{1}", RequestResponseHeaders.RequestContextCorrelationTargetKey, appId); - } - - private void Initialize(string instrumentationKey) - { - this.configuration = new TelemetryConfiguration(); - this.configuration.TelemetryInitializers.Add(new OperationCorrelationTelemetryInitializer()); - this.sendItems = new List(); - this.configuration.TelemetryChannel = new StubTelemetryChannel { OnSend = item => this.sendItems.Add(item) }; - this.configuration.InstrumentationKey = instrumentationKey; - this.httpProcessingProfiler = new ProfilerHttpProcessing( - this.configuration, - null, - new ObjectInstanceBasedOperationHolder(), - true /*setCorrelationHeaders*/, - new List(), - RandomAppIdEndpoint); - - var correlationIdLookupHelper = new CorrelationIdLookupHelper(new Dictionary - { - { - instrumentationKey, - "cid-v1:" + instrumentationKey + "-appId" - } - }); - - this.httpProcessingProfiler.OverrideCorrelationIdLookupHelper(correlationIdLookupHelper); - this.ex = new Exception(); + return string.Format(CultureInfo.InvariantCulture, "{0}={1}", RequestResponseHeaders.RequestContextCorrelationTargetKey, appId); } #endregion Helpers } diff --git a/Src/DependencyCollector/Shared/DependencyTrackingTelemetryModule.cs b/Src/DependencyCollector/Shared/DependencyTrackingTelemetryModule.cs index 68f3d0b59..2a6fea72e 100644 --- a/Src/DependencyCollector/Shared/DependencyTrackingTelemetryModule.cs +++ b/Src/DependencyCollector/Shared/DependencyTrackingTelemetryModule.cs @@ -10,7 +10,6 @@ using Microsoft.ApplicationInsights.Extensibility; using Microsoft.ApplicationInsights.Extensibility.Implementation.Tracing; #if NETSTANDARD1_6 - using Microsoft.Extensions.PlatformAbstractions; using System.Reflection; using System.Runtime.Versioning; #else @@ -98,16 +97,9 @@ public bool SetComponentCorrelationHttpHeaders /// /// Gets or sets the endpoint that is to be used to get the application insights resource's profile (appId etc.). /// + [Obsolete("This field has been deprecated. Please set TelemetryConfiguration.Active.ApplicationIdProvider = new ApplicationInsightsApplicationIdProvider() and customize ApplicationInsightsApplicationIdProvider.ProfileQueryEndpoint.")] public string ProfileQueryEndpoint { get; set; } - internal string EffectiveProfileQueryEndpoint - { - get - { - return string.IsNullOrEmpty(this.ProfileQueryEndpoint) ? this.telemetryConfiguration.TelemetryChannel.EndpointAddress : this.ProfileQueryEndpoint; - } - } - /// /// IDisposable implementation. /// @@ -145,10 +137,8 @@ public void Initialize(TelemetryConfiguration configuration) // NET45 referencing .net core System.Net.Http supports diagnostic listener this.httpCoreDiagnosticSourceListener = new HttpCoreDiagnosticSourceListener( configuration, - this.EffectiveProfileQueryEndpoint, this.SetComponentCorrelationHttpHeaders, - this.ExcludeComponentCorrelationHttpHeadersOnDomains, - null); + this.ExcludeComponentCorrelationHttpHeadersOnDomains); if (this.IncludeDiagnosticSourceActivities != null && this.IncludeDiagnosticSourceActivities.Count > 0) { @@ -195,7 +185,7 @@ internal virtual void InitializeForRuntimeProfiler() var agentVersion = Decorator.GetAgentVersion(); DependencyCollectorEventSource.Log.RemoteDependencyModuleInformation("AgentVersion is " + agentVersion); - this.httpProcessing = new ProfilerHttpProcessing(this.telemetryConfiguration, agentVersion, DependencyTableStore.Instance.WebRequestConditionalHolder, this.SetComponentCorrelationHttpHeaders, this.ExcludeComponentCorrelationHttpHeadersOnDomains, this.EffectiveProfileQueryEndpoint); + this.httpProcessing = new ProfilerHttpProcessing(this.telemetryConfiguration, agentVersion, DependencyTableStore.Instance.WebRequestConditionalHolder, this.SetComponentCorrelationHttpHeaders, this.ExcludeComponentCorrelationHttpHeadersOnDomains); this.sqlCommandProcessing = new ProfilerSqlCommandProcessing(this.telemetryConfiguration, agentVersion, DependencyTableStore.Instance.SqlRequestConditionalHolder); this.sqlConnectionProcessing = new ProfilerSqlConnectionProcessing(this.telemetryConfiguration, agentVersion, DependencyTableStore.Instance.SqlRequestConditionalHolder); @@ -270,8 +260,7 @@ private void InitializeForDiagnosticAndFrameworkEventSource() this.telemetryConfiguration, DependencyTableStore.Instance.WebRequestCacheHolder, this.SetComponentCorrelationHttpHeaders, - this.ExcludeComponentCorrelationHttpHeadersOnDomains, - this.EffectiveProfileQueryEndpoint); + this.ExcludeComponentCorrelationHttpHeadersOnDomains); this.httpDesktopDiagnosticSourceListener = new HttpDesktopDiagnosticSourceListener(desktopHttpProcessing, new ApplicationInsightsUrlFilter(this.telemetryConfiguration)); } @@ -279,8 +268,7 @@ private void InitializeForDiagnosticAndFrameworkEventSource() this.telemetryConfiguration, DependencyTableStore.Instance.WebRequestCacheHolder, this.SetComponentCorrelationHttpHeaders, - this.ExcludeComponentCorrelationHttpHeadersOnDomains, - this.EffectiveProfileQueryEndpoint); + this.ExcludeComponentCorrelationHttpHeadersOnDomains); // In 4.5 EventListener has a race condition issue in constructor so we retry to create listeners this.httpEventListener = RetryPolicy.Retry( diff --git a/Src/DependencyCollector/Shared/HttpCoreDiagnosticSourceListener.cs b/Src/DependencyCollector/Shared/HttpCoreDiagnosticSourceListener.cs index 30f37332d..dac8c25a6 100644 --- a/Src/DependencyCollector/Shared/HttpCoreDiagnosticSourceListener.cs +++ b/Src/DependencyCollector/Shared/HttpCoreDiagnosticSourceListener.cs @@ -30,7 +30,6 @@ internal class HttpCoreDiagnosticSourceListener : IObserver correlationDomainExclusionList; private readonly ApplicationInsightsUrlFilter applicationInsightsUrlFilter; private readonly bool setComponentCorrelationHttpHeaders; - private readonly ICorrelationIdLookupHelper correlationIdLookupHelper; private readonly TelemetryClient client; private readonly TelemetryConfiguration configuration; private readonly HttpCoreDiagnosticSourceSubscriber subscriber; @@ -57,12 +56,7 @@ internal class HttpCoreDiagnosticSourceListener : IObserver correlationDomainExclusionList, - ICorrelationIdLookupHelper correlationIdLookupHelper) + public HttpCoreDiagnosticSourceListener(TelemetryConfiguration configuration, bool setComponentCorrelationHttpHeaders, IEnumerable correlationDomainExclusionList) { this.client = new TelemetryClient(configuration); this.client.Context.GetInternalContext().SdkVersion = SdkVersionUtils.GetSdkVersion("rdd" + RddSource.DiagnosticSourceCore + ":"); @@ -73,7 +67,6 @@ public HttpCoreDiagnosticSourceListener( this.configuration = configuration; this.applicationInsightsUrlFilter = new ApplicationInsightsUrlFilter(configuration); this.setComponentCorrelationHttpHeaders = setComponentCorrelationHttpHeaders; - this.correlationIdLookupHelper = correlationIdLookupHelper ?? new CorrelationIdLookupHelper(effectiveProfileQueryEndpoint); this.correlationDomainExclusionList = correlationDomainExclusionList ?? Enumerable.Empty(); this.subscriber = new HttpCoreDiagnosticSourceSubscriber(this, this.applicationInsightsUrlFilter, this.isNetCore20HttpClient); @@ -137,14 +130,13 @@ public void OnNext(KeyValuePair evnt) var response = this.stopResponseFetcher.Fetch(evnt.Value) as HttpResponseMessage; var request = this.stopRequestFetcher.Fetch(evnt.Value) as HttpRequestMessage; var requestTaskStatusString = this.stopRequestStatusFetcher.Fetch(evnt.Value).ToString(); - TaskStatus requestTaskStatus; if (request == null) { var error = string.Format(CultureInfo.InvariantCulture, ErrorTemplateTypeCast, evnt.Key, "request", "HttpRequestMessage"); DependencyCollectorEventSource.Log.HttpCoreDiagnosticSourceListenerOnNextFailed(error); } - else if (!Enum.TryParse(requestTaskStatusString, out requestTaskStatus)) + else if (!Enum.TryParse(requestTaskStatusString, out TaskStatus requestTaskStatus)) { var error = string.Format(CultureInfo.InvariantCulture, ErrorTemplateValueParse, evnt.Key, requestTaskStatusString, "TaskStatus"); DependencyCollectorEventSource.Log.HttpCoreDiagnosticSourceListenerOnNextFailed(error); @@ -190,14 +182,13 @@ public void OnNext(KeyValuePair evnt) var request = this.deprecatedRequestFetcher.Fetch(evnt.Value) as HttpRequestMessage; var loggingRequestIdString = this.deprecatedRequestGuidFetcher.Fetch(evnt.Value).ToString(); - Guid loggingRequestId; if (request == null) { var error = string.Format(CultureInfo.InvariantCulture, ErrorTemplateTypeCast, evnt.Key, "request", "HttpRequestMessage"); DependencyCollectorEventSource.Log.HttpCoreDiagnosticSourceListenerOnNextFailed(error); } - else if (!Guid.TryParse(loggingRequestIdString, out loggingRequestId)) + else if (!Guid.TryParse(loggingRequestIdString, out Guid loggingRequestId)) { var error = string.Format(CultureInfo.InvariantCulture, ErrorTemplateValueParse, evnt.Key, loggingRequestIdString, "Guid"); DependencyCollectorEventSource.Log.HttpCoreDiagnosticSourceListenerOnNextFailed(error); @@ -220,14 +211,13 @@ public void OnNext(KeyValuePair evnt) var response = this.deprecatedResponseFetcher.Fetch(evnt.Value) as HttpResponseMessage; var loggingRequestIdString = this.deprecatedResponseGuidFetcher.Fetch(evnt.Value).ToString(); - Guid loggingRequestId; if (response == null) { var error = string.Format(CultureInfo.InvariantCulture, ErrorTemplateTypeCast, evnt.Key, "response", "HttpResponseMessage"); DependencyCollectorEventSource.Log.HttpCoreDiagnosticSourceListenerOnNextFailed(error); } - else if (!Guid.TryParse(loggingRequestIdString, out loggingRequestId)) + else if (!Guid.TryParse(loggingRequestIdString, out Guid loggingRequestId)) { var error = string.Format(CultureInfo.InvariantCulture, ErrorTemplateValueParse, evnt.Key, loggingRequestIdString, "Guid"); DependencyCollectorEventSource.Log.HttpCoreDiagnosticSourceListenerOnNextFailed(error); @@ -363,8 +353,7 @@ internal void OnActivityStop(HttpResponseMessage response, HttpRequestMessage re } else { - Exception exception; - if (this.pendingExceptions.TryRemove(currentActivity.Id, out exception)) + if (this.pendingExceptions.TryRemove(currentActivity.Id, out Exception exception)) { telemetry.Context.Properties[DependencyErrorPropertyKey] = exception.GetBaseException().Message; } @@ -413,8 +402,7 @@ internal void OnResponse(HttpResponseMessage response, Guid loggingRequestId) { DependencyCollectorEventSource.Log.HttpCoreDiagnosticSourceListenerResponse(loggingRequestId); var request = response.RequestMessage; - IOperationHolder dependency; - if (request != null && this.pendingTelemetry.TryGetValue(request, out dependency)) + if (request != null && this.pendingTelemetry.TryGetValue(request, out IOperationHolder dependency)) { this.ParseResponse(response, dependency.Telemetry); this.client.StopOperation(dependency); @@ -434,13 +422,12 @@ private void InjectRequestHeaders(HttpRequestMessage request, string instrumenta { try { - if (!string.IsNullOrEmpty(instrumentationKey) && !HttpHeadersUtilities.ContainsRequestContextKeyValue(requestHeaders, RequestResponseHeaders.RequestContextCorrelationSourceKey)) + string sourceApplicationId = null; + if (!string.IsNullOrEmpty(instrumentationKey) + && !HttpHeadersUtilities.ContainsRequestContextKeyValue(requestHeaders, RequestResponseHeaders.RequestContextCorrelationSourceKey) + && (this.configuration.ApplicationIdProvider?.TryGetApplicationId(instrumentationKey, out sourceApplicationId) ?? false)) { - string sourceApplicationId; - if (this.correlationIdLookupHelper.TryGetXComponentCorrelationId(instrumentationKey, out sourceApplicationId)) - { - HttpHeadersUtilities.SetRequestContextKeyValue(requestHeaders, RequestResponseHeaders.RequestContextCorrelationSourceKey, sourceApplicationId); - } + HttpHeadersUtilities.SetRequestContextKeyValue(requestHeaders, RequestResponseHeaders.RequestContextCorrelationSourceKey, sourceApplicationId); } } catch (Exception e) @@ -502,12 +489,14 @@ private void ParseResponse(HttpResponseMessage response, DependencyTelemetry tel if (!string.IsNullOrEmpty(targetApplicationId) && !string.IsNullOrEmpty(telemetry.Context.InstrumentationKey)) { // We only add the cross component correlation key if the key does not represent the current component. - string sourceApplicationId; - if (this.correlationIdLookupHelper.TryGetXComponentCorrelationId(telemetry.Context.InstrumentationKey, out sourceApplicationId) && - targetApplicationId != sourceApplicationId) + string sourceApplicationId = null; + if (this.configuration.ApplicationIdProvider?.TryGetApplicationId(telemetry.Context.InstrumentationKey, out sourceApplicationId) ?? false) { - telemetry.Type = RemoteDependencyConstants.AI; - telemetry.Target += " | " + targetApplicationId; + if (targetApplicationId != sourceApplicationId) + { + telemetry.Type = RemoteDependencyConstants.AI; + telemetry.Target += " | " + targetApplicationId; + } } } } diff --git a/Src/DependencyCollector/Shared/Implementation/DesktopDiagnosticSourceHttpProcessing.cs b/Src/DependencyCollector/Shared/Implementation/DesktopDiagnosticSourceHttpProcessing.cs index 463c258da..777dc7302 100644 --- a/Src/DependencyCollector/Shared/Implementation/DesktopDiagnosticSourceHttpProcessing.cs +++ b/Src/DependencyCollector/Shared/Implementation/DesktopDiagnosticSourceHttpProcessing.cs @@ -16,8 +16,8 @@ internal sealed class DesktopDiagnosticSourceHttpProcessing : HttpProcessing { private readonly CacheBasedOperationHolder telemetryTable; - internal DesktopDiagnosticSourceHttpProcessing(TelemetryConfiguration configuration, CacheBasedOperationHolder telemetryTupleHolder, bool setCorrelationHeaders, ICollection correlationDomainExclusionList, string appIdEndpoint) - : base(configuration, SdkVersionUtils.GetSdkVersion("rdd" + RddSource.DiagnosticSourceDesktop + ":"), null, setCorrelationHeaders, correlationDomainExclusionList, appIdEndpoint) + internal DesktopDiagnosticSourceHttpProcessing(TelemetryConfiguration configuration, CacheBasedOperationHolder telemetryTupleHolder, bool setCorrelationHeaders, ICollection correlationDomainExclusionList) + : base(configuration, SdkVersionUtils.GetSdkVersion("rdd" + RddSource.DiagnosticSourceDesktop + ":"), null, setCorrelationHeaders, correlationDomainExclusionList) { if (telemetryTupleHolder == null) { diff --git a/Src/DependencyCollector/Shared/Implementation/FrameworkHttpProcessing.cs b/Src/DependencyCollector/Shared/Implementation/FrameworkHttpProcessing.cs index 537657a6d..b15ad157c 100644 --- a/Src/DependencyCollector/Shared/Implementation/FrameworkHttpProcessing.cs +++ b/Src/DependencyCollector/Shared/Implementation/FrameworkHttpProcessing.cs @@ -18,8 +18,8 @@ internal sealed class FrameworkHttpProcessing : HttpProcessing internal CacheBasedOperationHolder TelemetryTable; private readonly ApplicationInsightsUrlFilter applicationInsightsUrlFilter; - internal FrameworkHttpProcessing(TelemetryConfiguration configuration, CacheBasedOperationHolder telemetryTupleHolder, bool setCorrelationHeaders, ICollection correlationDomainExclusionList, string appIdEndpoint) - : base(configuration, SdkVersionUtils.GetSdkVersion("rdd" + RddSource.Framework + ":"), null, setCorrelationHeaders, correlationDomainExclusionList, appIdEndpoint) + internal FrameworkHttpProcessing(TelemetryConfiguration configuration, CacheBasedOperationHolder telemetryTupleHolder, bool setCorrelationHeaders, ICollection correlationDomainExclusionList) + : base(configuration, SdkVersionUtils.GetSdkVersion("rdd" + RddSource.Framework + ":"), null, setCorrelationHeaders, correlationDomainExclusionList) { if (telemetryTupleHolder == null) { diff --git a/Src/DependencyCollector/Shared/Implementation/HttpProcessing.cs b/Src/DependencyCollector/Shared/Implementation/HttpProcessing.cs index 18f9ec612..fbb163ef1 100644 --- a/Src/DependencyCollector/Shared/Implementation/HttpProcessing.cs +++ b/Src/DependencyCollector/Shared/Implementation/HttpProcessing.cs @@ -6,11 +6,9 @@ namespace Microsoft.ApplicationInsights.DependencyCollector.Implementation using System.Globalization; using System.Linq; using System.Net; - using System.Web; using Extensibility.Implementation.Tracing; using Microsoft.ApplicationInsights.Common; using Microsoft.ApplicationInsights.DataContracts; - using Microsoft.ApplicationInsights.DependencyCollector.Implementation.Operation; using Microsoft.ApplicationInsights.Extensibility; using Microsoft.ApplicationInsights.Extensibility.Implementation; @@ -22,30 +20,21 @@ internal abstract class HttpProcessing { protected TelemetryClient telemetryClient; private readonly ApplicationInsightsUrlFilter applicationInsightsUrlFilter; + private readonly TelemetryConfiguration configuration; private ICollection correlationDomainExclusionList; private bool setCorrelationHeaders; - private CorrelationIdLookupHelper correlationIdLookupHelper; /// /// Initializes a new instance of the class. /// - public HttpProcessing(TelemetryConfiguration configuration, string sdkVersion, string agentVersion, bool setCorrelationHeaders, ICollection correlationDomainExclusionList, string appIdEndpoint) + public HttpProcessing(TelemetryConfiguration configuration, string sdkVersion, string agentVersion, bool setCorrelationHeaders, ICollection correlationDomainExclusionList) { - if (configuration == null) - { - throw new ArgumentNullException("configuration"); - } - - if (correlationDomainExclusionList == null) - { - throw new ArgumentNullException("correlationDomainExclusionList"); - } - + this.configuration = configuration ?? throw new ArgumentNullException(nameof(configuration)); this.applicationInsightsUrlFilter = new ApplicationInsightsUrlFilter(configuration); this.telemetryClient = new TelemetryClient(configuration); - this.correlationDomainExclusionList = correlationDomainExclusionList; + + this.correlationDomainExclusionList = correlationDomainExclusionList ?? throw new ArgumentNullException(nameof(correlationDomainExclusionList)); this.setCorrelationHeaders = setCorrelationHeaders; - this.correlationIdLookupHelper = new CorrelationIdLookupHelper(appIdEndpoint); this.telemetryClient.Context.GetInternalContext().SdkVersion = sdkVersion; if (!string.IsNullOrEmpty(agentVersion)) @@ -69,16 +58,7 @@ internal Uri GetUrl(WebRequest webRequest) return resource; } - - /// - /// Simple test hook, that allows for using a stub rather than the implementation that calls the original service. - /// - /// Lookup header to use. - internal void OverrideCorrelationIdLookupHelper(CorrelationIdLookupHelper correlationIdLookupHelper) - { - this.correlationIdLookupHelper = correlationIdLookupHelper; - } - + /// /// Common helper for all Begin Callbacks. /// @@ -163,19 +143,16 @@ internal object OnBegin(object thisObj, bool injectCorrelationHeaders = true) telemetry.Data = url.OriginalString; // Add the source instrumentation key header if collection is enabled, the request host is not in the excluded list and the same header doesn't already exist - if (this.setCorrelationHeaders - && !this.correlationDomainExclusionList.Contains(url.Host)) + if (this.setCorrelationHeaders && !this.correlationDomainExclusionList.Contains(url.Host)) { try { + string applicationId = null; if (!string.IsNullOrEmpty(telemetry.Context.InstrumentationKey) - && webRequest.Headers.GetNameValueHeaderValue(RequestResponseHeaders.RequestContextHeader, RequestResponseHeaders.RequestContextCorrelationSourceKey) == null) + && webRequest.Headers.GetNameValueHeaderValue(RequestResponseHeaders.RequestContextHeader, RequestResponseHeaders.RequestContextCorrelationSourceKey) == null + && (this.configuration.ApplicationIdProvider?.TryGetApplicationId(telemetry.Context.InstrumentationKey, out applicationId) ?? false)) { - string appId; - if (this.correlationIdLookupHelper.TryGetXComponentCorrelationId(telemetry.Context.InstrumentationKey, out appId)) - { - webRequest.Headers.SetNameValueHeaderValue(RequestResponseHeaders.RequestContextHeader, RequestResponseHeaders.RequestContextCorrelationSourceKey, appId); - } + webRequest.Headers.SetNameValueHeaderValue(RequestResponseHeaders.RequestContextHeader, RequestResponseHeaders.RequestContextCorrelationSourceKey, applicationId); } } catch (Exception ex) @@ -238,11 +215,9 @@ internal void OnEndResponse(object request, object response) { try { - DependencyTelemetry telemetry; - if (this.TryGetPendingTelemetry(request, out telemetry)) + if (this.TryGetPendingTelemetry(request, out DependencyTelemetry telemetry)) { - var responseObj = response as HttpWebResponse; - if (responseObj != null) + if (response is HttpWebResponse responseObj) { int statusCode = -1; @@ -278,13 +253,11 @@ internal void OnEndException(object exception, object request) { try { - DependencyTelemetry telemetry; - if (this.TryGetPendingTelemetry(request, out telemetry)) + if (this.TryGetPendingTelemetry(request, out DependencyTelemetry telemetry)) { var webException = exception as WebException; - HttpWebResponse responseObj = webException?.Response as HttpWebResponse; - if (responseObj != null) + if (webException?.Response is HttpWebResponse responseObj) { int statusCode = -1; @@ -330,8 +303,7 @@ internal void OnEndResponse(object request, object statusCode, object responseHe { try { - DependencyTelemetry telemetry; - if (this.TryGetPendingTelemetry(request, out telemetry)) + if (this.TryGetPendingTelemetry(request, out DependencyTelemetry telemetry)) { if (statusCode != null) { @@ -430,8 +402,8 @@ private void SetTarget(DependencyTelemetry telemetry, WebHeaderCollection respon AppMapCorrelationEventSource.Log.GetCrossComponentCorrelationHeaderFailed(ex.ToInvariantString()); } - string currentComponentAppId; - if (this.correlationIdLookupHelper.TryGetXComponentCorrelationId(telemetry.Context.InstrumentationKey, out currentComponentAppId)) + string currentComponentAppId = null; + if (this.configuration.ApplicationIdProvider?.TryGetApplicationId(telemetry.Context.InstrumentationKey, out currentComponentAppId) ?? false) { // We only add the cross component correlation key if the key does not remain the current component. if (!string.IsNullOrEmpty(targetAppId) && targetAppId != currentComponentAppId) diff --git a/Src/DependencyCollector/Shared/Implementation/ProfilerHttpProcessing.cs b/Src/DependencyCollector/Shared/Implementation/ProfilerHttpProcessing.cs index 6fdde6fab..eb3b5a024 100644 --- a/Src/DependencyCollector/Shared/Implementation/ProfilerHttpProcessing.cs +++ b/Src/DependencyCollector/Shared/Implementation/ProfilerHttpProcessing.cs @@ -20,8 +20,8 @@ internal sealed class ProfilerHttpProcessing : HttpProcessing /// /// Initializes a new instance of the class. /// - public ProfilerHttpProcessing(TelemetryConfiguration configuration, string agentVersion, ObjectInstanceBasedOperationHolder telemetryTupleHolder, bool setCorrelationHeaders, ICollection correlationDomainExclusionList, string appIdEndpoint) - : base(configuration, SdkVersionUtils.GetSdkVersion("rdd" + RddSource.Profiler + ":"), agentVersion, setCorrelationHeaders, correlationDomainExclusionList, appIdEndpoint) + public ProfilerHttpProcessing(TelemetryConfiguration configuration, string agentVersion, ObjectInstanceBasedOperationHolder telemetryTupleHolder, bool setCorrelationHeaders, ICollection correlationDomainExclusionList) + : base(configuration, SdkVersionUtils.GetSdkVersion("rdd" + RddSource.Profiler + ":"), agentVersion, setCorrelationHeaders, correlationDomainExclusionList) { if (telemetryTupleHolder == null) { diff --git a/Src/TestFramework/Shared/MockApplicationIdProvider.cs b/Src/TestFramework/Shared/MockApplicationIdProvider.cs new file mode 100644 index 000000000..730a87f93 --- /dev/null +++ b/Src/TestFramework/Shared/MockApplicationIdProvider.cs @@ -0,0 +1,28 @@ +namespace Microsoft.ApplicationInsights.Web.TestFramework +{ + using Microsoft.ApplicationInsights.Extensibility; + + internal class MockApplicationIdProvider : IApplicationIdProvider + { + private readonly string expectedInstrumentationKey; + private readonly string applicationId; + + public MockApplicationIdProvider(string expectedInstrumentationKey, string applicationId) + { + this.expectedInstrumentationKey = expectedInstrumentationKey; + this.applicationId = applicationId; + } + + public bool TryGetApplicationId(string instrumentationKey, out string applicationId) + { + if (this.expectedInstrumentationKey == instrumentationKey) + { + applicationId = this.applicationId; + return true; + } + + applicationId = null; + return false; + } + } +} diff --git a/Src/TestFramework/Shared/TestFramework.Shared.projitems b/Src/TestFramework/Shared/TestFramework.Shared.projitems index d9e92783f..a8c2bd79b 100644 --- a/Src/TestFramework/Shared/TestFramework.Shared.projitems +++ b/Src/TestFramework/Shared/TestFramework.Shared.projitems @@ -10,6 +10,7 @@ + diff --git a/Src/Web/Web.Nuget/Resources/net45/ApplicationInsights.config.install.xdt b/Src/Web/Web.Nuget/Resources/net45/ApplicationInsights.config.install.xdt index 8532a9c2d..b7a8f457d 100644 --- a/Src/Web/Web.Nuget/Resources/net45/ApplicationInsights.config.install.xdt +++ b/Src/Web/Web.Nuget/Resources/net45/ApplicationInsights.config.install.xdt @@ -37,4 +37,5 @@ + \ No newline at end of file diff --git a/Src/Web/Web.Nuget/Resources/net45/ApplicationInsights.config.uninstall.xdt b/Src/Web/Web.Nuget/Resources/net45/ApplicationInsights.config.uninstall.xdt index f83543f28..0290401f1 100644 --- a/Src/Web/Web.Nuget/Resources/net45/ApplicationInsights.config.uninstall.xdt +++ b/Src/Web/Web.Nuget/Resources/net45/ApplicationInsights.config.uninstall.xdt @@ -19,5 +19,7 @@ + + \ No newline at end of file diff --git a/Src/Web/Web.Shared.Net.Tests/RequestTrackingTelemetryModuleTest.cs b/Src/Web/Web.Shared.Net.Tests/RequestTrackingTelemetryModuleTest.cs index 4b9ef54c2..c03d660c9 100644 --- a/Src/Web/Web.Shared.Net.Tests/RequestTrackingTelemetryModuleTest.cs +++ b/Src/Web/Web.Shared.Net.Tests/RequestTrackingTelemetryModuleTest.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.Globalization; - using System.Threading.Tasks; using System.Web; using Microsoft.ApplicationInsights.Channel; @@ -25,14 +24,11 @@ [TestClass] public partial class RequestTrackingTelemetryModuleTest { - private CorrelationIdLookupHelper correlationIdLookupHelper = new CorrelationIdLookupHelper((string ikey) => - { - // Pretend App Id is the same as Ikey - var tcs = new TaskCompletionSource(); - tcs.SetResult(ikey + "-appId"); - return tcs.Task; - }); - + private const string TestInstrumentationKey1 = nameof(TestInstrumentationKey1); + private const string TestInstrumentationKey2 = nameof(TestInstrumentationKey2); + private const string TestApplicationId1 = nameof(TestApplicationId1); + private const string TestApplicationId2 = nameof(TestApplicationId2); + [TestCleanup] public void Cleanup() { @@ -324,15 +320,13 @@ public void SdkVersionHasCorrectFormat() public void OnEndDoesNotAddSourceFieldForRequestForSameComponent() { // ARRANGE - string ikey = "b3eb14d6-bb32-4542-9b93-473cd94aaedf"; - string requestContextContainingCorrelationId = this.GetCorrelationIdHeaderValue(ikey); // since per our mock appId = ikey - Dictionary headers = new Dictionary(); - headers.Add(RequestResponseHeaders.RequestContextHeader, requestContextContainingCorrelationId); + headers.Add(RequestResponseHeaders.RequestContextHeader, TestApplicationId2); var context = HttpModuleHelper.GetFakeHttpContext(headers); - var config = this.CreateDefaultConfig(context, instrumentationKey: ikey); + var config = this.CreateDefaultConfig(context, instrumentationKey: TestInstrumentationKey1); + config.ApplicationIdProvider = new MockApplicationIdProvider(TestInstrumentationKey1, TestApplicationId1); var module = this.RequestTrackingTelemetryModuleFactory(config); // ACT @@ -347,32 +341,17 @@ public void OnEndDoesNotAddSourceFieldForRequestForSameComponent() public void OnEndAddsSourceFieldForRequestWithCorrelationId() { // ARRANGE - string instrumentationKey = "b3eb14d6-bb32-4542-9b93-473cd94aaedf"; - string appId = instrumentationKey + "-appId"; - Dictionary headers = new Dictionary(); - headers.Add(RequestResponseHeaders.RequestContextHeader, this.GetCorrelationIdHeaderValue(appId)); + headers.Add(RequestResponseHeaders.RequestContextHeader, this.GetCorrelationIdHeaderValue(TestApplicationId2)); var context = HttpModuleHelper.GetFakeHttpContext(headers); // My instrumentation key and hence app id is random / newly generated. The appId header is different - hence a different component. var config = TelemetryConfiguration.CreateDefault(); - config.InstrumentationKey = Guid.NewGuid().ToString(); - - // Add ikey -> app Id mappings in correlation helper - var correlationHelper = new CorrelationIdLookupHelper(new Dictionary() - { - { - config.InstrumentationKey, - config.InstrumentationKey + "-appId" - }, - { - instrumentationKey, - appId + "-appId" - } - }); - - var module = this.RequestTrackingTelemetryModuleFactory(null /*use default*/, correlationHelper); + config.InstrumentationKey = TestInstrumentationKey1; + config.ApplicationIdProvider = new MockApplicationIdProvider(TestInstrumentationKey1, TestApplicationId1); + + var module = this.RequestTrackingTelemetryModuleFactory(null /*use default*/); // ACT module.Initialize(config); @@ -380,7 +359,7 @@ public void OnEndAddsSourceFieldForRequestWithCorrelationId() module.OnEndRequest(context); // VALIDATE - Assert.Equal(this.GetCorrelationIdValue(appId), context.GetRequestTelemetry().Source); + Assert.Equal(TestApplicationId2, context.GetRequestTelemetry().Source); } [TestMethod] @@ -408,25 +387,21 @@ public void OnEndDoesNotAddSourceFieldForRequestWithOutSourceIkeyHeader() [TestMethod] public void OnEndDoesNotOverrideSourceField() { - // ARRANGE - string appIdInHeader = this.GetCorrelationIdHeaderValue("b3eb14d6-bb32-4542-9b93-473cd94aaedf"); - string someFieldHeader = "SomeField=SomeNameHere"; - string appIdInSourceField = "9AB8EDCB-21D2-44BB-A64A-C33BB4515F20"; - + // ARRANGE Dictionary headers = new Dictionary(); - headers.Add(RequestResponseHeaders.RequestContextHeader, appIdInHeader + "," + someFieldHeader); + headers.Add(RequestResponseHeaders.RequestContextHeader, TestApplicationId1); var context = HttpModuleHelper.GetFakeHttpContext(headers); var module = this.RequestTrackingTelemetryModuleFactory(); module.OnBeginRequest(context); - context.GetRequestTelemetry().Source = appIdInSourceField; + context.GetRequestTelemetry().Source = TestApplicationId2; // ACT module.OnEndRequest(context); // VALIDATE - Assert.Equal(appIdInSourceField, context.GetRequestTelemetry().Source); + Assert.Equal(TestApplicationId2, context.GetRequestTelemetry().Source); } private TelemetryConfiguration CreateDefaultConfig(HttpContext fakeContext, string rootIdHeaderName = null, string parentIdHeaderName = null, string instrumentationKey = null) @@ -454,25 +429,20 @@ private string GetActivityRootId(string telemetryId) return telemetryId.Substring(1, telemetryId.IndexOf('.') - 1); } - private RequestTrackingTelemetryModule RequestTrackingTelemetryModuleFactory(TelemetryConfiguration config = null, CorrelationIdLookupHelper correlationHelper = null) + private RequestTrackingTelemetryModule RequestTrackingTelemetryModuleFactory(TelemetryConfiguration config = null) { var module = new RequestTrackingTelemetryModule() { EnableChildRequestTrackingSuppression = false }; - module.OverrideCorrelationIdLookupHelper(correlationHelper ?? this.correlationIdLookupHelper); + module.Initialize(config ?? this.CreateDefaultConfig(HttpModuleHelper.GetFakeHttpContext())); return module; } - private string GetCorrelationIdValue(string appId) - { - return string.Format(CultureInfo.InvariantCulture, "cid-v1:{0}", appId); - } - - private string GetCorrelationIdHeaderValue(string appId) + private string GetCorrelationIdHeaderValue(string applicationId) { - return string.Format(CultureInfo.InvariantCulture, "{0}=cid-v1:{1}", RequestResponseHeaders.RequestContextCorrelationSourceKey, appId); + return string.Format(CultureInfo.InvariantCulture, "{0}={1}", RequestResponseHeaders.RequestContextCorrelationSourceKey, applicationId); } internal class FakeHttpHandler : IHttpHandler diff --git a/Src/Web/Web.Shared.Net/RequestTrackingTelemetryModule.cs b/Src/Web/Web.Shared.Net/RequestTrackingTelemetryModule.cs index f9c0b0b70..473f71092 100644 --- a/Src/Web/Web.Shared.Net/RequestTrackingTelemetryModule.cs +++ b/Src/Web/Web.Shared.Net/RequestTrackingTelemetryModule.cs @@ -19,10 +19,9 @@ public class RequestTrackingTelemetryModule : ITelemetryModule { private readonly IList handlersToFilter = new List(); private TelemetryClient telemetryClient; + private TelemetryConfiguration telemetryConfiguration; private bool initializationErrorReported; private bool correlationHeadersEnabled = true; - private string telemetryChannelEnpoint; - private CorrelationIdLookupHelper correlationIdLookupHelper; private ChildRequestTrackingSuppressionModule childRequestTrackingSuppressionModule = null; /// @@ -83,16 +82,9 @@ public bool SetComponentCorrelationHttpHeaders /// /// Gets or sets the endpoint that is to be used to get the application insights resource's profile (appId etc.). /// + [Obsolete("This field has been deprecated. Please set TelemetryConfiguration.Active.ApplicationIdProvider = new ApplicationInsightsApplicationIdProvider() and customize ApplicationInsightsApplicationIdProvider.ProfileQueryEndpoint.")] public string ProfileQueryEndpoint { get; set; } - internal string EffectiveProfileQueryEndpoint - { - get - { - return string.IsNullOrEmpty(this.ProfileQueryEndpoint) ? this.telemetryChannelEnpoint : this.ProfileQueryEndpoint; - } - } - /// /// Implements on begin callback of http module. /// @@ -200,24 +192,18 @@ public void OnEndRequest(HttpContext context) { AppMapCorrelationEventSource.Log.GetCrossComponentCorrelationHeaderFailed(ex.ToInvariantString()); } - - bool correlationIdLookupHelperInitialized = this.TryInitializeCorrelationHelperIfNotInitialized(); - - string currentComponentAppId = string.Empty; - bool foundMyAppId = false; - if (!string.IsNullOrEmpty(requestTelemetry.Context.InstrumentationKey) && correlationIdLookupHelperInitialized) - { - foundMyAppId = this.correlationIdLookupHelper.TryGetXComponentCorrelationId(requestTelemetry.Context.InstrumentationKey, out currentComponentAppId); - } - // If the source header is present on the incoming request, - // and it is an external component (not the same ikey as the one used by the current component), - // then populate the source field. - if (!string.IsNullOrEmpty(sourceAppId) - && foundMyAppId - && sourceAppId != currentComponentAppId) + string currentComponentAppId = null; + if (!string.IsNullOrEmpty(requestTelemetry.Context.InstrumentationKey) + && (this.telemetryConfiguration?.ApplicationIdProvider?.TryGetApplicationId(requestTelemetry.Context.InstrumentationKey, out currentComponentAppId) ?? false)) { - requestTelemetry.Source = sourceAppId; + // If the source header is present on the incoming request, + // and it is an external component (not the same ikey as the one used by the current component), + // then populate the source field. + if (!string.IsNullOrEmpty(sourceAppId) && sourceAppId != currentComponentAppId) + { + requestTelemetry.Source = sourceAppId; + } } } @@ -250,24 +236,20 @@ public void AddTargetHashForResponseHeader(HttpContext context) this.telemetryClient.Initialize(requestTelemetry); } - bool correlationIdHelperInitialized = this.TryInitializeCorrelationHelperIfNotInitialized(); - try { if (!string.IsNullOrEmpty(requestTelemetry.Context.InstrumentationKey) - && context.Response.Headers.GetNameValueHeaderValue(RequestResponseHeaders.RequestContextHeader, RequestResponseHeaders.RequestContextCorrelationTargetKey) == null - && correlationIdHelperInitialized) + && context.Response.Headers.GetNameValueHeaderValue(RequestResponseHeaders.RequestContextHeader, RequestResponseHeaders.RequestContextCorrelationTargetKey) == null) { - string correlationId; - - if (this.correlationIdLookupHelper.TryGetXComponentCorrelationId(requestTelemetry.Context.InstrumentationKey, out correlationId)) + string applicationId = null; + if (this.telemetryConfiguration.ApplicationIdProvider?.TryGetApplicationId(requestTelemetry.Context.InstrumentationKey, out applicationId) ?? false) { - context.Response.Headers.SetNameValueHeaderValue(RequestResponseHeaders.RequestContextHeader, RequestResponseHeaders.RequestContextCorrelationTargetKey, correlationId); + context.Response.Headers.SetNameValueHeaderValue(RequestResponseHeaders.RequestContextHeader, RequestResponseHeaders.RequestContextCorrelationTargetKey, applicationId); if (this.EnableAccessControlExposeHeader) { // set additional header that allows to read this Request-Context from Javascript SDK - // append this header with additional value to the potential ones defined by customer and they will be concatenated on cliend-side + // append this header with additional value to the potential ones defined by customer and they will be concatenated on client-side context.Response.AppendHeader(RequestResponseHeaders.AccessControlExposeHeadersHeader, RequestResponseHeaders.RequestContextHeader); } } @@ -285,14 +267,10 @@ public void AddTargetHashForResponseHeader(HttpContext context) /// Telemetry configuration to use for initialization. public void Initialize(TelemetryConfiguration configuration) { + this.telemetryConfiguration = configuration; this.telemetryClient = new TelemetryClient(configuration); this.telemetryClient.Context.GetInternalContext().SdkVersion = SdkVersionUtils.GetSdkVersion("web:"); - if (configuration != null && configuration.TelemetryChannel != null) - { - this.telemetryChannelEnpoint = configuration.TelemetryChannel.EndpointAddress; - } - // Headers will be read-only in a classic iis pipeline // Exception System.PlatformNotSupportedException: This operation requires IIS integrated pipeline mode. if (HttpRuntime.UsingIntegratedPipeline && this.EnableChildRequestTrackingSuppression) @@ -325,15 +303,6 @@ internal bool NeedProcessRequest(HttpContext httpContext) return true; } - /// - /// Simple test hook, that allows for using a stub rather than the implementation that calls the original service. - /// - /// Lookup header to use. - internal void OverrideCorrelationIdLookupHelper(CorrelationIdLookupHelper correlationIdLookupHelper) - { - this.correlationIdLookupHelper = correlationIdLookupHelper; - } - /// /// Checks whether or not handler is a transfer handler. /// @@ -356,24 +325,7 @@ private bool IsHandlerToFilter(IHttpHandler handler) return false; } - - private bool TryInitializeCorrelationHelperIfNotInitialized() - { - try - { - if (this.correlationIdLookupHelper == null) - { - this.correlationIdLookupHelper = new CorrelationIdLookupHelper(this.EffectiveProfileQueryEndpoint); - } - - return true; - } - catch - { - return false; - } - } - + /// /// can create a Child request to route extension-less requests to a controller. /// (ex: site/home -> site/HomeController.cs) diff --git a/Test/E2ETests/TestApps/Net452/E2ETestApp/ApplicationInsights.config b/Test/E2ETests/TestApps/Net452/E2ETestApp/ApplicationInsights.config index df631e99a..7ab13dd96 100644 --- a/Test/E2ETests/TestApps/Net452/E2ETestApp/ApplicationInsights.config +++ b/Test/E2ETests/TestApps/Net452/E2ETestApp/ApplicationInsights.config @@ -83,6 +83,9 @@ http://e2etests_ingestionservice_1/api/Data/PushItem true + + http://e2etests_ingestionservice_1/api/profiles/{0}/appId + + + http://LocalHost:{TelemetryEndpointPort}/api/profiles/{0}/appId + diff --git a/Test/Web/FunctionalTests/FunctionalTests/DiagnosticsTest.cs b/Test/Web/FunctionalTests/FunctionalTests/DiagnosticsTest.cs index aa3cb1187..6ee4f2f33 100644 --- a/Test/Web/FunctionalTests/FunctionalTests/DiagnosticsTest.cs +++ b/Test/Web/FunctionalTests/FunctionalTests/DiagnosticsTest.cs @@ -49,7 +49,7 @@ public void TestCleanUp() } [TestMethod] - [Description("Validates that diagnostics module sends trace data to the Portal")] + [Description("Validates that diagnostics module sends trace data to the Portal. Expects an exception about incorrect xml structure of 'BuildInfo.config'.")] public void TestDiagnosticsFW45() { var responseTask = this.HttpClient.GetStringAsync("/"); @@ -59,12 +59,16 @@ public void TestDiagnosticsFW45() Assert.IsTrue(responseTask.Result.Contains("Home Page - My ASP.NET Application"), "Incorrect response returned: " + responseTask.Result); var items = Listener.ReceiveAllItemsDuringTimeOfType>(TestListenerTimeoutInMs); + var itemCount = items.Count(); // Check that instrumentation key is correct Assert.AreEqual(0, items.Count(i => !i.iKey.Equals(DiagnosticsInstrumentationKey)), "Some item does not have DiagnosticsInstrumentationKey"); // There should be one custom actionable event about incorrect timeout of session expiration - Assert.IsTrue(items.Count(i => i.data.baseData.message.StartsWith("AI: ")) == 1, "AI actionable event was not recieved"); + var actionableEventCount = items.Count(i => i.data.baseData.message.StartsWith("AI: ")); + Assert.IsTrue(actionableEventCount >= 1, "AI actionable event was not received"); + + Assert.AreEqual(1, actionableEventCount, $"Test project possibly mis-configured. Expected 1 actionable event. Received '{actionableEventCount}'"); } } } diff --git a/Test/Web/FunctionalTests/TestApps/AspNetDiagnostics/ApplicationInsights.config b/Test/Web/FunctionalTests/TestApps/AspNetDiagnostics/ApplicationInsights.config index c62019073..3af96b824 100644 --- a/Test/Web/FunctionalTests/TestApps/AspNetDiagnostics/ApplicationInsights.config +++ b/Test/Web/FunctionalTests/TestApps/AspNetDiagnostics/ApplicationInsights.config @@ -57,4 +57,7 @@ Event + + http://localhost:4000/api/profiles/{0}/appId + diff --git a/Test/Web/FunctionalTests/TestApps/AspNetDiagnostics/BuildInfo.config b/Test/Web/FunctionalTests/TestApps/AspNetDiagnostics/BuildInfo.config index 715ea64d0..b313b9fc1 100644 --- a/Test/Web/FunctionalTests/TestApps/AspNetDiagnostics/BuildInfo.config +++ b/Test/Web/FunctionalTests/TestApps/AspNetDiagnostics/BuildInfo.config @@ -1,3 +1,3 @@ This is clearly not a valid XML. File is used so user actionable diagnostics message will be generated by BuildInfoConfigComponentVersionTelemetryInitializer. - Test verifies that diagnositcs works. \ No newline at end of file + Test verifies that diagnostics works. \ No newline at end of file diff --git a/Test/Web/FunctionalTests/TestApps/Aspx45/ApplicationInsights.config b/Test/Web/FunctionalTests/TestApps/Aspx45/ApplicationInsights.config index 61bba6c0b..bae0edad7 100644 --- a/Test/Web/FunctionalTests/TestApps/Aspx45/ApplicationInsights.config +++ b/Test/Web/FunctionalTests/TestApps/Aspx45/ApplicationInsights.config @@ -53,4 +53,7 @@ Event + + http://localhost:4001/api/profiles/{0}/appId + diff --git a/Test/Web/FunctionalTests/TestApps/ConsoleAppFW45/ApplicationInsights.config b/Test/Web/FunctionalTests/TestApps/ConsoleAppFW45/ApplicationInsights.config index a886c9a0b..9a10b0e94 100644 --- a/Test/Web/FunctionalTests/TestApps/ConsoleAppFW45/ApplicationInsights.config +++ b/Test/Web/FunctionalTests/TestApps/ConsoleAppFW45/ApplicationInsights.config @@ -29,4 +29,7 @@ Event + + http://localhost:4002/api/profiles/{0}/appId + \ No newline at end of file diff --git a/Test/Web/FunctionalTests/TestApps/Mvc4_MediumTrust/ApplicationInsights.config b/Test/Web/FunctionalTests/TestApps/Mvc4_MediumTrust/ApplicationInsights.config index 6c565d5ad..b30c7e59f 100644 --- a/Test/Web/FunctionalTests/TestApps/Mvc4_MediumTrust/ApplicationInsights.config +++ b/Test/Web/FunctionalTests/TestApps/Mvc4_MediumTrust/ApplicationInsights.config @@ -50,4 +50,7 @@ 5 + + http://localhost:4004/api/profiles/{0}/appId + diff --git a/Test/Web/FunctionalTests/TestApps/Wa45Aspx/ApplicationInsights.config b/Test/Web/FunctionalTests/TestApps/Wa45Aspx/ApplicationInsights.config index ebd65af88..d1b678b7c 100644 --- a/Test/Web/FunctionalTests/TestApps/Wa45Aspx/ApplicationInsights.config +++ b/Test/Web/FunctionalTests/TestApps/Wa45Aspx/ApplicationInsights.config @@ -52,4 +52,7 @@ Event + + http://localhost:4005/api/profiles/{0}/appId + diff --git a/Test/Web/FunctionalTests/TestApps/Wcf45Tests/ApplicationInsights.config b/Test/Web/FunctionalTests/TestApps/Wcf45Tests/ApplicationInsights.config index 5b7bedb6b..181a78aa4 100644 --- a/Test/Web/FunctionalTests/TestApps/Wcf45Tests/ApplicationInsights.config +++ b/Test/Web/FunctionalTests/TestApps/Wcf45Tests/ApplicationInsights.config @@ -55,4 +55,7 @@ Event + + http://localhost:4006/api/profiles/{0}/appId + diff --git a/Test/Web/FunctionalTests/TestApps/WebAppFW45/ApplicationInsights.config b/Test/Web/FunctionalTests/TestApps/WebAppFW45/ApplicationInsights.config index 83680baa5..4493ca96e 100644 --- a/Test/Web/FunctionalTests/TestApps/WebAppFW45/ApplicationInsights.config +++ b/Test/Web/FunctionalTests/TestApps/WebAppFW45/ApplicationInsights.config @@ -57,4 +57,7 @@ Event + + http://localhost:4017/api/profiles/{0}/appId + diff --git a/Test/Web/FunctionalTests/TestApps/WebAppFW45Sampled/ApplicationInsights.config b/Test/Web/FunctionalTests/TestApps/WebAppFW45Sampled/ApplicationInsights.config index 5d0f214d6..3d6ed0fba 100644 --- a/Test/Web/FunctionalTests/TestApps/WebAppFW45Sampled/ApplicationInsights.config +++ b/Test/Web/FunctionalTests/TestApps/WebAppFW45Sampled/ApplicationInsights.config @@ -58,4 +58,7 @@ Event + + http://localhost:4008/api/profiles/{0}/appId +