Skip to content
This repository has been archived by the owner on Jun 10, 2020. It is now read-only.

SDK Connection Strings (Net Core support) #992

Merged
merged 20 commits into from
Oct 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
- Skipping version numbers to keep in sync with Base SDK.
- [Fix Null/Empty Ikey from ApplicationInsightsServiceOptions overrding one from appsettings.json](https://github.com/microsoft/ApplicationInsights-aspnetcore/issues/989)
- [Provide ApplicationInsightsServiceOptions for easy disabling of any default TelemetryModules](https://github.com/microsoft/ApplicationInsights-aspnetcore/issues/988)
- [Added support for SDK Connection String](https://github.com/microsoft/ApplicationInsights-dotnet/issues/1221)


## Version 2.8.0
- Updated Bask SDK/Web SDK/Logging Adaptor SDK to 2.11.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ public JavaScriptSnippet(
/// <returns>JavaScript code snippet with instrumentation key or empty if instrumentation key was not set for the application.</returns>
public string FullScript
{
// TODO: NEED TO SUPPORT CONNECTION STRING. DISCUSS WITH JAVASCRIPT SDK TO CONFIRM COMPATIBILITY.

get
{
if (!this.telemetryConfiguration.DisableTelemetry &&
Expand Down
28 changes: 26 additions & 2 deletions src/Shared/Extensions/ApplicationInsightsExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,12 @@ public static partial class ApplicationInsightsExtensions
{
private const string VersionKeyFromConfig = "version";
private const string InstrumentationKeyFromConfig = "ApplicationInsights:InstrumentationKey";
private const string ConnectionStringFromConfig = "ApplicationInsights:ConnectionString";
private const string DeveloperModeFromConfig = "ApplicationInsights:TelemetryChannel:DeveloperMode";
private const string EndpointAddressFromConfig = "ApplicationInsights:TelemetryChannel:EndpointAddress";

private const string InstrumentationKeyForWebSites = "APPINSIGHTS_INSTRUMENTATIONKEY";
private const string ConnectionStringEnvironmentVariable = "APPLICATIONINSIGHTS_CONNECTION_STRING";
private const string DeveloperModeForWebSites = "APPINSIGHTS_DEVELOPER_MODE";
private const string EndpointAddressForWebSites = "APPINSIGHTS_ENDPOINTADDRESS";

Expand Down Expand Up @@ -156,12 +158,14 @@ public static IServiceCollection ConfigureTelemetryModule<T>(
/// <param name="developerMode">Enables or disables developer mode.</param>
/// <param name="endpointAddress">Sets telemetry endpoint address.</param>
/// <param name="instrumentationKey">Sets instrumentation key.</param>
/// <param name="connectionString">Sets connection string.</param>
/// <returns>The <see cref="IConfigurationBuilder"/>.</returns>
public static IConfigurationBuilder AddApplicationInsightsSettings(
this IConfigurationBuilder configurationSourceRoot,
bool? developerMode = null,
string endpointAddress = null,
string instrumentationKey = null)
string instrumentationKey = null,
string connectionString = null)
{
var telemetryConfigValues = new List<KeyValuePair<string, string>>();

Expand All @@ -179,6 +183,12 @@ public static IConfigurationBuilder AddApplicationInsightsSettings(
wasAnythingSet = true;
}

if (connectionString != null)
{
telemetryConfigValues.Add(new KeyValuePair<string, string>(ConnectionStringEnvironmentVariable, connectionString));
wasAnythingSet = true;
}

if (instrumentationKey != null)
{
telemetryConfigValues.Add(new KeyValuePair<string, string>(InstrumentationKeyForWebSites, instrumentationKey));
Expand All @@ -204,13 +214,22 @@ public static IConfigurationBuilder AddApplicationInsightsSettings(
/// Config.json will look like this:
/// <para>
/// "ApplicationInsights": {
/// "InstrumentationKey": "11111111-2222-3333-4444-555555555555"
/// "InstrumentationKey": "11111111-2222-3333-4444-555555555555",
/// "TelemetryChannel": {
/// "EndpointAddress": "http://dc.services.visualstudio.com/v2/track",
/// "DeveloperMode": true
/// }
/// }.
/// </para>
/// Or
/// <para>
/// "ApplicationInsights": {
/// "ConnectionString" : "InstrumentationKey=11111111-2222-3333-4444-555555555555;IngestionEndpoint=http://dc.services.visualstudio.com"
/// "TelemetryChannel": {
/// "DeveloperMode": true
/// }
/// }.
/// </para>
/// Values can also be read from environment variables to support azure web sites configuration.
/// </summary>
/// <param name="config">Configuration to read variables from.</param>
Expand All @@ -221,6 +240,11 @@ internal static void AddTelemetryConfiguration(
{
try
{
if (config.TryGetValue(primaryKey: ConnectionStringEnvironmentVariable, backupKey: ConnectionStringFromConfig, value: out string connectionStringValue))
{
serviceOptions.ConnectionString = connectionStringValue;
}

if (config.TryGetValue(primaryKey: InstrumentationKeyForWebSites, backupKey: InstrumentationKeyFromConfig, value: out string instrumentationKey))
{
serviceOptions.InstrumentationKey = instrumentationKey;
Expand Down
6 changes: 6 additions & 0 deletions src/Shared/Extensions/ApplicationInsightsServiceOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,11 @@ public ApplicationInsightsServiceOptions()
/// </summary>
public string InstrumentationKey { get; set; }

/// <summary>
/// Gets or sets the connection string for the application.
/// </summary>
public string ConnectionString { get; set; }

/// <summary>
/// Gets or sets the application version reported with telemetries.
/// </summary>
Expand Down Expand Up @@ -164,6 +169,7 @@ internal void CopyPropertiesTo(ApplicationInsightsServiceOptions target)
target.InstrumentationKey = this.InstrumentationKey;
}

target.ConnectionString = this.ConnectionString;
TimothyMothra marked this conversation as resolved.
Show resolved Hide resolved
target.ApplicationVersion = this.ApplicationVersion;
target.EnableAdaptiveSampling = this.EnableAdaptiveSampling;
target.EnableDebugLogger = this.EnableDebugLogger;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,12 @@ public void Configure(TelemetryConfiguration configuration)
configuration.TelemetryChannel.EndpointAddress = this.applicationInsightsServiceOptions.EndpointAddress;
}

// Need to set connection string before calling Initialize() on the Modules and Processors.
if (this.applicationInsightsServiceOptions.ConnectionString != null)
{
configuration.ConnectionString = this.applicationInsightsServiceOptions.ConnectionString;
TimothyMothra marked this conversation as resolved.
Show resolved Hide resolved
}

foreach (ITelemetryInitializer initializer in this.initializers)
{
configuration.TelemetryInitializers.Add(initializer);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ public static class ApplicationInsightsExtensionsTests
{
/// <summary>Constant instrumentation key value for testintg.</summary>
public const string TestInstrumentationKey = "11111111-2222-3333-4444-555555555555";
private const string TestConnectionString = "InstrumentationKey=11111111-2222-3333-4444-555555555555;IngestionEndpoint=http://127.0.0.1";
private const string InstrumentationKeyFromConfig = "ApplicationInsights:InstrumentationKey";
private const string ConnectionStringEnvironmentVariable = "APPLICATIONINSIGHTS_CONNECTION_STRING";

public static ServiceCollection GetServiceCollectionWithContextAccessor()
{
Expand Down Expand Up @@ -114,7 +116,6 @@ public static void RegistersTelemetryConfigurationFactoryMethodThatCreatesDefaul
/// Tests that the instrumentation key configuration can be read from a JSON file by the configuration factory.
/// </summary>
[Fact]

public static void RegistersTelemetryConfigurationFactoryMethodThatReadsInstrumentationKeyFromConfiguration()
{
var services = CreateServicesAndAddApplicationinsightsTelemetry(Path.Combine("content", "config-instrumentation-key.json"), null);
Expand All @@ -124,6 +125,39 @@ public static void RegistersTelemetryConfigurationFactoryMethodThatReadsInstrume
Assert.Equal(TestInstrumentationKey, telemetryConfiguration.InstrumentationKey);
}

/// <summary>
/// Tests that the connection string can be read from a JSON file by the configuration factory.
/// </summary>
[Fact]
[Trait("Trait", "ConnectionString")]
public static void RegistersTelemetryConfigurationFactoryMethodThatReadsConnectionStringFromConfiguration()
{
var services = CreateServicesAndAddApplicationinsightsTelemetry(Path.Combine("content", "config-connection-string.json"), null);

IServiceProvider serviceProvider = services.BuildServiceProvider();
var telemetryConfiguration = serviceProvider.GetTelemetryConfiguration();
Assert.Equal(TestConnectionString, telemetryConfiguration.ConnectionString);
Assert.Equal(TestInstrumentationKey, telemetryConfiguration.InstrumentationKey);
Assert.Equal("http://127.0.0.1/", telemetryConfiguration.EndpointContainer.Ingestion.AbsoluteUri);
}

/// <summary>
/// Tests that the connection string can be read from a JSON file by the configuration factory.
/// This config has both a connection string and an instrumentation key. It is expected to use the ikey from the connection string.
/// </summary>
[Fact]
[Trait("Trait", "ConnectionString")]
public static void RegistersTelemetryConfigurationFactoryMethodThatReadsConnectionStringAndInstrumentationKeyFromConfiguration()
{
var services = CreateServicesAndAddApplicationinsightsTelemetry(Path.Combine("content", "config-connection-string-and-instrumentation-key.json"), null);

IServiceProvider serviceProvider = services.BuildServiceProvider();
var telemetryConfiguration = serviceProvider.GetTelemetryConfiguration();
Assert.Equal(TestConnectionString, telemetryConfiguration.ConnectionString);
Assert.Equal(TestInstrumentationKey, telemetryConfiguration.InstrumentationKey);
Assert.Equal("http://127.0.0.1/", telemetryConfiguration.EndpointContainer.Ingestion.AbsoluteUri);
}

/// <summary>
/// Tests that the Active configuration singleton is updated, but another instance of telemetry configuration is created for dependency injection.
/// ASP.NET Core developers should always use Dependency Injection instead of static singleton approach.
Expand All @@ -147,7 +181,7 @@ public static void ConfigurationFactoryMethodUpdatesTheActiveConfigurationSingle
}

/// <summary>
/// We determine if Active telemtery needs to be configured based on the assumptions that 'default' configuration
/// We determine if Active telemetry needs to be configured based on the assumptions that 'default' configuration
// created by base SDK has single preset ITelemetryInitializer. If it ever changes, change TelemetryConfigurationOptions.IsActiveConfigured method as well.
/// </summary>
[Fact]
Expand All @@ -159,7 +193,6 @@ public static void DefaultTelemetryConfigurationHasOneTelemetryInitializer()
}

[Fact]

public static void RegistersTelemetryConfigurationFactoryMethodThatReadsDeveloperModeFromConfiguration()
{
var services = CreateServicesAndAddApplicationinsightsTelemetry(Path.Combine("content", "config-developer-mode.json"), null);
Expand All @@ -170,7 +203,6 @@ public static void RegistersTelemetryConfigurationFactoryMethodThatReadsDevelope
}

[Fact]

public static void RegistersTelemetryConfigurationFactoryMethodThatReadsEndpointAddressFromConfiguration()
{
var services = CreateServicesAndAddApplicationinsightsTelemetry(Path.Combine("content", "config-endpoint-address.json"), null);
Expand Down Expand Up @@ -201,15 +233,40 @@ public static void RegistersTelemetryConfigurationFactoryMethodThatReadsInstrume
}
}

/// <summary>
/// Validates that while using services.AddApplicationInsightsTelemetry(); ikey is read from
/// Environment
/// </summary>
[Fact]
[Trait("Trait", "ConnectionString")]
public static void AddApplicationInsightsTelemetry_ReadsConnectionString_FromEnvironment()
{
var services = ApplicationInsightsExtensionsTests.GetServiceCollectionWithContextAccessor();
Environment.SetEnvironmentVariable(ConnectionStringEnvironmentVariable, TestConnectionString);
try
{
services.AddApplicationInsightsTelemetry();
IServiceProvider serviceProvider = services.BuildServiceProvider();
var telemetryConfiguration = serviceProvider.GetTelemetryConfiguration();
Assert.Equal(TestConnectionString, telemetryConfiguration.ConnectionString);
TimothyMothra marked this conversation as resolved.
Show resolved Hide resolved
Assert.Equal(TestInstrumentationKey, telemetryConfiguration.InstrumentationKey);
Assert.Equal("http://127.0.0.1/", telemetryConfiguration.EndpointContainer.Ingestion.AbsoluteUri);
}
finally
{
Environment.SetEnvironmentVariable(ConnectionStringEnvironmentVariable, null);
}
}

/// <summary>
/// Validates that while using services.AddApplicationInsightsTelemetry(); ikey is read from
/// Environment
/// </summary>
[Fact]
public static void AddApplicationInsightsTelemetryReadsInstrumentationKeyFromEnvironment()
{
var services = ApplicationInsightsExtensionsTests.GetServiceCollectionWithContextAccessor();
Environment.SetEnvironmentVariable("APPINSIGHTS_INSTRUMENTATIONKEY", TestInstrumentationKey);
var services = ApplicationInsightsExtensionsTests.GetServiceCollectionWithContextAccessor();
TimothyMothra marked this conversation as resolved.
Show resolved Hide resolved
Environment.SetEnvironmentVariable("APPINSIGHTS_INSTRUMENTATIONKEY", TestInstrumentationKey);
try
{
services.AddApplicationInsightsTelemetry();
Expand Down Expand Up @@ -495,7 +552,8 @@ public static void AppApplicationInsightsTelemetryFromApplicationInsightsService
EnableQuickPulseMetricStream = false,
EndpointAddress = "http://test",
EnableHeartbeat = false,
InstrumentationKey = "test"
InstrumentationKey = "test",
ConnectionString = "InstrumentationKey=00000000-0000-0000-0000-000000000000"
};
services.AddApplicationInsightsTelemetry(options);
ApplicationInsightsServiceOptions servicesOptions = null;
Expand Down Expand Up @@ -1002,24 +1060,46 @@ public static void AddsServerTelemetryChannelByDefault()
}

[Fact]
[Trait("Trait", "ConnectionString")]
public static void AddApplicationInsightsSettings_SetsConnectionString()
{
var services = ApplicationInsightsExtensionsTests.GetServiceCollectionWithContextAccessor();
services.AddSingleton<ITelemetryChannel>(new InMemoryChannel());
var config = new ConfigurationBuilder().AddApplicationInsightsSettings(connectionString: TestConnectionString).Build();
services.AddApplicationInsightsTelemetry(config);

IServiceProvider serviceProvider = services.BuildServiceProvider();
var telemetryConfiguration = serviceProvider.GetTelemetryConfiguration();
Assert.Equal(TestConnectionString, telemetryConfiguration.ConnectionString);
Assert.Equal(TestInstrumentationKey, telemetryConfiguration.InstrumentationKey);
Assert.Equal("http://127.0.0.1/", telemetryConfiguration.EndpointContainer.Ingestion.AbsoluteUri);
}

[Fact]
[Trait("Trait", "Endpoints")]
public static void DoesNotOverWriteExistingChannel()
{
var testEndpoint = "http://localhost:1234/v2/track/";

var services = ApplicationInsightsExtensionsTests.GetServiceCollectionWithContextAccessor();
services.AddSingleton<ITelemetryChannel, InMemoryChannel>();
var config = new ConfigurationBuilder().AddApplicationInsightsSettings(endpointAddress: "http://localhost:1234/v2/track/").Build();
var config = new ConfigurationBuilder().AddApplicationInsightsSettings(endpointAddress: testEndpoint).Build();
services.AddApplicationInsightsTelemetry(config);

IServiceProvider serviceProvider = services.BuildServiceProvider();
var telemetryConfiguration = serviceProvider.GetTelemetryConfiguration();
Assert.Equal(typeof(InMemoryChannel), telemetryConfiguration.TelemetryChannel.GetType());
Assert.Equal(testEndpoint, telemetryConfiguration.TelemetryChannel.EndpointAddress);
}

[Fact]
public static void FallbacktoDefaultChannelWhenNoChannelFoundInDI()
{
var testEndpoint = "http://localhost:1234/v2/track/";

// ARRANGE
var services = ApplicationInsightsExtensionsTests.GetServiceCollectionWithContextAccessor();
var config = new ConfigurationBuilder().AddApplicationInsightsSettings(endpointAddress: "http://localhost:1234/v2/track/").Build();
var config = new ConfigurationBuilder().AddApplicationInsightsSettings(endpointAddress: testEndpoint).Build();
services.AddApplicationInsightsTelemetry(config);

// Remove all ITelemetryChannel to simulate scenario where customer remove all channel from DI but forgot to add new one.
Expand All @@ -1037,6 +1117,7 @@ public static void FallbacktoDefaultChannelWhenNoChannelFoundInDI()
IServiceProvider serviceProvider = services.BuildServiceProvider();
var telemetryConfiguration = serviceProvider.GetTelemetryConfiguration();
Assert.Equal(typeof(InMemoryChannel), telemetryConfiguration.TelemetryChannel.GetType());
Assert.Equal(testEndpoint, telemetryConfiguration.TelemetryChannel.EndpointAddress);
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<Generator>SettingsSingleFileGenerator</Generator>
</None>
<None Update="content\config-connection-string-and-instrumentation-key.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="content\config-developer-mode.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
Expand All @@ -77,6 +80,9 @@
<None Update="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="content\config-connection-string.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="content\config-instrumentation-key-new.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
Expand Down
Loading