diff --git a/Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs b/Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs index ed9afcd925..5f15d74769 100644 --- a/Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs +++ b/Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs @@ -40,8 +40,10 @@ public class CosmosClientOptions private static readonly CosmosSerializer propertiesSerializer = new CosmosJsonSerializerWrapper(new CosmosJsonDotNetSerializer()); private readonly Collection customHandlers; + private readonly string currentEnvironmentInformation; private int gatewayModeMaxConnectionLimit; + private string applicationName; /// /// Creates a new CosmosClientOptions @@ -49,6 +51,9 @@ public class CosmosClientOptions public CosmosClientOptions() { this.UserAgentContainer = new UserAgentContainer(); + EnvironmentInformation environmentInformation = new EnvironmentInformation(); + this.currentEnvironmentInformation = environmentInformation.ToString(); + this.UserAgentContainer.Suffix = this.currentEnvironmentInformation; this.GatewayModeMaxConnectionLimit = ConnectionPolicy.Default.MaxConnectionLimit; this.RequestTimeout = ConnectionPolicy.Default.RequestTimeout; this.ConnectionMode = CosmosClientOptions.DefaultConnectionMode; @@ -65,8 +70,12 @@ public CosmosClientOptions() /// public string ApplicationName { - get => this.UserAgentContainer.Suffix; - set => this.UserAgentContainer.Suffix = value; + get => this.applicationName; + set + { + this.UserAgentContainer.Suffix = this.currentEnvironmentInformation + EnvironmentInformation.Delimiter + value; + this.applicationName = value; + } } /// diff --git a/Microsoft.Azure.Cosmos/src/EnvironmentInformation.cs b/Microsoft.Azure.Cosmos/src/EnvironmentInformation.cs new file mode 100644 index 0000000000..c2e766649d --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/EnvironmentInformation.cs @@ -0,0 +1,54 @@ +//------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------ +namespace Microsoft.Azure.Cosmos +{ + using System; + using System.Reflection; + using System.Runtime.InteropServices; + + internal sealed class EnvironmentInformation + { + internal const string Delimiter = " "; + private static readonly string clientId; + private static readonly string clientSDKVersion; + private static readonly string framework; + private static readonly string architecture; + + static EnvironmentInformation() + { + Version sdkVersion = Assembly.GetAssembly(typeof(CosmosClient)).GetName().Version; + EnvironmentInformation.clientSDKVersion = $"{sdkVersion.Major}.{sdkVersion.Minor}.{sdkVersion.Build}"; + EnvironmentInformation.framework = RuntimeInformation.FrameworkDescription; + EnvironmentInformation.architecture = RuntimeInformation.ProcessArchitecture.ToString(); + EnvironmentInformation.clientId = DateTime.UtcNow.Ticks.ToString(); + } + + /// + /// Unique identifier of a client + /// + public string ClientId => EnvironmentInformation.clientId; + + /// + /// Version of the current client. + /// + public string ClientVersion => EnvironmentInformation.clientSDKVersion; + + /// + /// Identifier of the Framework. + /// + /// + public string RuntimeFramework => EnvironmentInformation.framework; + + /// + /// Type of architecture being used. + /// + /// + public string ProcessArchitecture => EnvironmentInformation.architecture; + + public override string ToString() + { + return $" {this.ClientVersion}-{this.RuntimeFramework} {this.ProcessArchitecture} {this.ClientId}"; + } + } +} diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosClientOptionsUnitTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosClientOptionsUnitTests.cs index dfd6e8c085..e562f6f443 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosClientOptionsUnitTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosClientOptionsUnitTests.cs @@ -90,7 +90,7 @@ public void VerifyCosmosConfigurationPropertiesGetUpdated() Assert.AreEqual(Protocol.Https, policy.ConnectionProtocol); Assert.AreEqual(maxConnections, policy.MaxConnectionLimit); Assert.AreEqual(requestTimeout, policy.RequestTimeout); - Assert.AreEqual(userAgentSuffix, policy.UserAgentSuffix); + Assert.IsTrue(policy.UserAgentSuffix.Contains(userAgentSuffix)); Assert.IsTrue(policy.UseMultipleWriteLocations); Assert.AreEqual(maxRetryAttemptsOnThrottledRequests, policy.RetryOptions.MaxRetryAttemptsOnThrottledRequests); Assert.AreEqual((int)maxRetryWaitTime.TotalSeconds, policy.RetryOptions.MaxRetryWaitTimeInSeconds); @@ -116,6 +116,23 @@ public void ThrowOnNullEndpoint() new CosmosClientBuilder(null, "testKey"); } + [TestMethod] + public void UserAgentContainsEnvironmentInformation() + { + var environmentInformation = new EnvironmentInformation(); + var expectedValue = environmentInformation.ToString(); + CosmosClientOptions cosmosClientOptions = new CosmosClientOptions(); + string userAgentSuffix = "testSuffix"; + cosmosClientOptions.ApplicationName = userAgentSuffix; + + Assert.IsTrue(cosmosClientOptions.UserAgentContainer.Suffix.EndsWith(userAgentSuffix)); + Assert.IsTrue(cosmosClientOptions.UserAgentContainer.Suffix.Contains(expectedValue)); + + ConnectionPolicy connectionPolicy = cosmosClientOptions.GetConnectionPolicy(); + Assert.IsTrue(connectionPolicy.UserAgentSuffix.EndsWith(userAgentSuffix)); + Assert.IsTrue(connectionPolicy.UserAgentSuffix.Contains(expectedValue)); + } + [TestMethod] [ExpectedException(typeof(ArgumentNullException))] public void ThrowOnNullConnectionString() diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/EnvironmentInformationTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/EnvironmentInformationTests.cs new file mode 100644 index 0000000000..00ab746641 --- /dev/null +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/EnvironmentInformationTests.cs @@ -0,0 +1,56 @@ +//------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos.Tests +{ + using System; + using System.Reflection; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class EnvironmentInformationTests + { + [TestMethod] + public void ClientVersionIsNotNull() + { + var envInfo = new EnvironmentInformation(); + Assert.IsNotNull(envInfo.ClientVersion); + + Version sdkVersion = Assembly.GetAssembly(typeof(CosmosClient)).GetName().Version; + Assert.AreEqual($"{sdkVersion.Major}.{sdkVersion.Minor}.{sdkVersion.Build}", envInfo.ClientVersion, "Version format differs"); + } + + [TestMethod] + public void ProcessArchitectureIsNotNull() + { + var envInfo = new EnvironmentInformation(); + Assert.IsNotNull(envInfo.ProcessArchitecture); + } + + [TestMethod] + public void FrameworkIsNotNull() + { + var envInfo = new EnvironmentInformation(); + Assert.IsNotNull(envInfo.RuntimeFramework); + } + + [TestMethod] + public void ClientIdIsNotNull() + { + var envInfo = new EnvironmentInformation(); + Assert.IsNotNull(envInfo.ClientId); + } + + [TestMethod] + public void ToStringContainsAll() + { + var envInfo = new EnvironmentInformation(); + var serialization = envInfo.ToString(); + Assert.IsTrue(serialization.Contains(envInfo.ClientVersion)); + Assert.IsTrue(serialization.Contains(envInfo.ProcessArchitecture)); + Assert.IsTrue(serialization.Contains(envInfo.RuntimeFramework)); + Assert.IsTrue(serialization.Contains(envInfo.ClientId)); + } + } +} diff --git a/changelog.md b/changelog.md index 685df06a6f..b82e187cd1 100644 --- a/changelog.md +++ b/changelog.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [#614](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/614) Fixed SpatialPath serialization and compatibility with older index versions - [#626](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/626) FeedResponse status code now return OK for success instead of the invalid status code 0 or Accepted - [#629](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/629) Fixed CreateContainerIfNotExistsAsync validation to limited to partitionKeyPath only +- [#630](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/630) Fixed User Agent to contain environment and package information ## [3.1.0](https://www.nuget.org/packages/Microsoft.Azure.Cosmos/3.1.0) - 2019-07-26