diff --git a/Microsoft.Azure.Cosmos/src/CosmosClient.cs b/Microsoft.Azure.Cosmos/src/CosmosClient.cs index 0a3c536f36..2c87f5a78d 100644 --- a/Microsoft.Azure.Cosmos/src/CosmosClient.cs +++ b/Microsoft.Azure.Cosmos/src/CosmosClient.cs @@ -309,7 +309,7 @@ public virtual Task ReadAccountAsync() /// The Cosmos database id /// /// proxy reference doesn't guarantee existence. - /// Please ensure database exists through + /// Please ensure database exists through /// or , before /// operating on it. /// @@ -382,12 +382,21 @@ public virtual Task CreateDatabaseAsync( throw new ArgumentNullException(nameof(id)); } - DatabaseProperties databaseProperties = this.PrepareDatabaseProperties(id); - return TaskHelper.RunInlineIfNeededAsync(() => this.CreateDatabaseAsync( - databaseProperties: databaseProperties, - throughput: throughput, - requestOptions: requestOptions, - cancellationToken: cancellationToken)); + return this.ClientContext.OperationHelperAsync( + nameof(CreateDatabaseAsync), + requestOptions, + (diagnostics) => + { + DatabaseProperties databaseProperties = this.PrepareDatabaseProperties(id); + ThroughputProperties throughputProperties = ThroughputProperties.CreateManualThroughput(throughput); + + return this.CreateDatabaseInternalAsync( + databaseProperties: databaseProperties, + throughputProperties: throughputProperties, + requestOptions: requestOptions, + diagnosticsContext: diagnostics, + cancellationToken: cancellationToken); + }); } /// @@ -418,12 +427,19 @@ public virtual Task CreateDatabaseAsync( throw new ArgumentNullException(nameof(id)); } - DatabaseProperties databaseProperties = this.PrepareDatabaseProperties(id); - return TaskHelper.RunInlineIfNeededAsync(() => this.CreateDatabaseAsync( - databaseProperties: databaseProperties, - throughputProperties: throughputProperties, - requestOptions: requestOptions, - cancellationToken: cancellationToken)); + return this.ClientContext.OperationHelperAsync( + nameof(CreateDatabaseAsync), + requestOptions, + (diagnostics) => + { + DatabaseProperties databaseProperties = this.PrepareDatabaseProperties(id); + return this.CreateDatabaseInternalAsync( + diagnosticsContext: diagnostics, + databaseProperties: databaseProperties, + throughputProperties: throughputProperties, + requestOptions: requestOptions, + cancellationToken: cancellationToken); + }); } /// @@ -468,35 +484,45 @@ public virtual Task CreateDatabaseIfNotExistsAsync( throw new ArgumentNullException(nameof(id)); } - return TaskHelper.RunInlineIfNeededAsync(async () => + return this.ClientContext.OperationHelperAsync( + nameof(CreateDatabaseIfNotExistsAsync), + requestOptions, + async (diagnostics) => { // Doing a Read before Create will give us better latency for existing databases DatabaseProperties databaseProperties = this.PrepareDatabaseProperties(id); - Database database = this.GetDatabase(id); - ResponseMessage readResponse = await database.ReadStreamAsync( + DatabaseCore database = (DatabaseCore)this.GetDatabase(id); + using (ResponseMessage readResponse = await database.ReadStreamAsync( + diagnosticsContext: diagnostics, requestOptions: requestOptions, - cancellationToken: cancellationToken); - - if (readResponse.StatusCode != HttpStatusCode.NotFound) + cancellationToken: cancellationToken)) { - return this.ClientContext.ResponseFactory.CreateDatabaseResponse(database, readResponse); + if (readResponse.StatusCode != HttpStatusCode.NotFound) + { + return this.ClientContext.ResponseFactory.CreateDatabaseResponse(database, readResponse); + } } - ResponseMessage createResponse = await this.CreateDatabaseStreamAsync(databaseProperties, throughputProperties, requestOptions, cancellationToken); - - // Merge the diagnostics with the first read request. - createResponse.DiagnosticsContext.AddDiagnosticsInternal(readResponse.DiagnosticsContext); - if (createResponse.StatusCode != HttpStatusCode.Conflict) + using (ResponseMessage createResponse = await this.CreateDatabaseStreamInternalAsync( + diagnostics, + databaseProperties, + throughputProperties, + requestOptions, + cancellationToken)) { - return this.ClientContext.ResponseFactory.CreateDatabaseResponse(this.GetDatabase(databaseProperties.Id), createResponse); + if (createResponse.StatusCode != HttpStatusCode.Conflict) + { + return this.ClientContext.ResponseFactory.CreateDatabaseResponse(this.GetDatabase(databaseProperties.Id), createResponse); + } } // This second Read is to handle the race condition when 2 or more threads have Read the database and only one succeeds with Create // so for the remaining ones we should do a Read instead of throwing Conflict exception ResponseMessage readResponseAfterConflict = await database.ReadStreamAsync( + diagnosticsContext: diagnostics, requestOptions: requestOptions, cancellationToken: cancellationToken); - readResponseAfterConflict.DiagnosticsContext.AddDiagnosticsInternal(readResponse.DiagnosticsContext); + return this.ClientContext.ResponseFactory.CreateDatabaseResponse(this.GetDatabase(databaseProperties.Id), readResponseAfterConflict); }); } @@ -538,8 +564,7 @@ public virtual Task CreateDatabaseIfNotExistsAsync( RequestOptions requestOptions = null, CancellationToken cancellationToken = default(CancellationToken)) { - ThroughputProperties throughputProperties = throughput.HasValue - ? ThroughputProperties.CreateManualThroughput(throughput.Value) : null; + ThroughputProperties throughputProperties = ThroughputProperties.CreateManualThroughput(throughput); return this.CreateDatabaseIfNotExistsAsync( id, @@ -586,10 +611,10 @@ public virtual FeedIterator GetDatabaseQueryIterator( QueryRequestOptions requestOptions = null) { return new FeedIteratorInlineCore( - this.GetDatabaseQueryIteratorHelper( - queryDefinition, - continuationToken, - requestOptions)); + this.GetDatabaseQueryIteratorHelper( + queryDefinition, + continuationToken, + requestOptions)); } /// @@ -771,14 +796,19 @@ public virtual Task CreateDatabaseStreamAsync( throw new ArgumentNullException(nameof(databaseProperties)); } - this.ClientContext.ValidateResource(databaseProperties.Id); - Stream streamPayload = this.ClientContext.SerializerCore.ToStream(databaseProperties); - - return TaskHelper.RunInlineIfNeededAsync(() => this.CreateDatabaseStreamInternalAsync( - streamPayload, - throughput, - requestOptions, - cancellationToken)); + return this.ClientContext.OperationHelperAsync( + nameof(CreateDatabaseStreamAsync), + requestOptions, + (diagnostics) => + { + this.ClientContext.ValidateResource(databaseProperties.Id); + return this.CreateDatabaseStreamInternalAsync( + diagnostics, + databaseProperties, + ThroughputProperties.CreateManualThroughput(throughput), + requestOptions, + cancellationToken); + }); } internal virtual async Task GetAccountConsistencyLevelAsync() @@ -835,21 +865,27 @@ internal virtual Task CreateDatabaseStreamAsync( throw new ArgumentNullException(nameof(databaseProperties)); } - this.ClientContext.ValidateResource(databaseProperties.Id); - Stream streamPayload = this.ClientContext.SerializerCore.ToStream(databaseProperties); - - return TaskHelper.RunInlineIfNeededAsync(() => this.CreateDatabaseStreamInternalAsync( - streamPayload, - throughputProperties, + return this.ClientContext.OperationHelperAsync( + nameof(CreateDatabaseIfNotExistsAsync), requestOptions, - cancellationToken)); + (diagnostics) => + { + this.ClientContext.ValidateResource(databaseProperties.Id); + return this.CreateDatabaseStreamInternalAsync( + diagnostics, + databaseProperties, + throughputProperties, + requestOptions, + cancellationToken); + }); } - internal async Task CreateDatabaseAsync( - DatabaseProperties databaseProperties, - ThroughputProperties throughputProperties, - RequestOptions requestOptions = null, - CancellationToken cancellationToken = default(CancellationToken)) + private async Task CreateDatabaseInternalAsync( + CosmosDiagnosticsContext diagnosticsContext, + DatabaseProperties databaseProperties, + ThroughputProperties throughputProperties, + RequestOptions requestOptions, + CancellationToken cancellationToken) { ResponseMessage response = await this.ClientContext.ProcessResourceOperationStreamAsync( resourceUri: this.DatabaseRootUri, @@ -860,63 +896,30 @@ internal async Task CreateDatabaseAsync( partitionKey: null, streamPayload: this.ClientContext.SerializerCore.ToStream(databaseProperties), requestEnricher: (httpRequestMessage) => httpRequestMessage.AddThroughputPropertiesHeader(throughputProperties), - diagnosticsContext: null, - cancellationToken: cancellationToken); - - return this.ClientContext.ResponseFactory.CreateDatabaseResponse(this.GetDatabase(databaseProperties.Id), response); - } - - internal async Task CreateDatabaseAsync( - DatabaseProperties databaseProperties, - int? throughput = null, - RequestOptions requestOptions = null, - CancellationToken cancellationToken = default(CancellationToken)) - { - ResponseMessage response = await this.CreateDatabaseStreamInternalAsync( - streamPayload: this.ClientContext.SerializerCore.ToStream(databaseProperties), - throughput: throughput, - requestOptions: requestOptions, + diagnosticsContext: diagnosticsContext, cancellationToken: cancellationToken); return this.ClientContext.ResponseFactory.CreateDatabaseResponse(this.GetDatabase(databaseProperties.Id), response); } private Task CreateDatabaseStreamInternalAsync( - Stream streamPayload, - int? throughput, - RequestOptions requestOptions, - CancellationToken cancellationToken) - { - ThroughputProperties throughputProperties = null; - if (throughput.HasValue) - { - throughputProperties = ThroughputProperties.CreateManualThroughput(throughput.Value); - } - - return this.CreateDatabaseStreamInternalAsync( - streamPayload, - throughputProperties, - requestOptions, - cancellationToken); - - } - - private Task CreateDatabaseStreamInternalAsync( - Stream streamPayload, - ThroughputProperties throughputProperties, - RequestOptions requestOptions, - CancellationToken cancellationToken) + CosmosDiagnosticsContext diagnosticsContext, + DatabaseProperties databaseProperties, + ThroughputProperties throughputProperties, + RequestOptions requestOptions, + CancellationToken cancellationToken) { - return this.ClientContext.ProcessResourceOperationStreamAsync( + return this.ClientContext.ProcessResourceOperationAsync( resourceUri: this.DatabaseRootUri, resourceType: ResourceType.Database, operationType: OperationType.Create, requestOptions: requestOptions, - cosmosContainerCore: null, + containerInternal: null, partitionKey: null, - streamPayload: streamPayload, + streamPayload: this.ClientContext.SerializerCore.ToStream(databaseProperties), requestEnricher: (httpRequestMessage) => httpRequestMessage.AddThroughputPropertiesHeader(throughputProperties), - diagnosticsContext: null, + responseCreator: (response) => response, + diagnosticsContext: diagnosticsContext, cancellationToken: cancellationToken); } diff --git a/Microsoft.Azure.Cosmos/src/Diagnostics/CosmosClientSideRequestStatistics.cs b/Microsoft.Azure.Cosmos/src/Diagnostics/CosmosClientSideRequestStatistics.cs index b8ccdccbc5..fe92b71258 100644 --- a/Microsoft.Azure.Cosmos/src/Diagnostics/CosmosClientSideRequestStatistics.cs +++ b/Microsoft.Azure.Cosmos/src/Diagnostics/CosmosClientSideRequestStatistics.cs @@ -33,7 +33,7 @@ public CosmosClientSideRequestStatistics(CosmosDiagnosticsContext diagnosticsCon this.ContactedReplicas = new List(); this.FailedReplicas = new HashSet(); this.RegionsContacted = new HashSet(); - this.DiagnosticsContext = diagnosticsContext ?? new CosmosDiagnosticsContextCore(); + this.DiagnosticsContext = diagnosticsContext ?? CosmosDiagnosticsContextCore.Create(requestOptions: null); this.DiagnosticsContext.AddDiagnosticsInternal(this); this.clientSideRequestStatisticsCreateTime = Stopwatch.GetTimestamp(); } diff --git a/Microsoft.Azure.Cosmos/src/Diagnostics/CosmosDiagnosticsContext.cs b/Microsoft.Azure.Cosmos/src/Diagnostics/CosmosDiagnosticsContext.cs index 51211ea3d6..01979b9298 100644 --- a/Microsoft.Azure.Cosmos/src/Diagnostics/CosmosDiagnosticsContext.cs +++ b/Microsoft.Azure.Cosmos/src/Diagnostics/CosmosDiagnosticsContext.cs @@ -16,21 +16,25 @@ internal abstract class CosmosDiagnosticsContext : CosmosDiagnosticsInternal, IE { public abstract DateTime StartUtc { get; } - public abstract int TotalRequestCount { get; protected set; } + public abstract string UserAgent { get; } - public abstract int FailedRequestCount { get; protected set; } - - public abstract string UserAgent { get; protected set; } + public abstract string OperationName { get; } internal abstract CosmosDiagnostics Diagnostics { get; } + public abstract int GetTotalRequestCount(); + + public abstract int GetFailedRequestCount(); + internal abstract IDisposable GetOverallScope(); internal abstract IDisposable CreateScope(string name); internal abstract IDisposable CreateRequestHandlerScopeScope(RequestHandler requestHandler); - internal abstract TimeSpan GetClientElapsedTime(); + internal abstract TimeSpan GetRunningElapsedTime(); + + internal abstract bool TryGetTotalElapsedTime(out TimeSpan timeSpan); internal abstract bool IsComplete(); @@ -50,8 +54,6 @@ internal abstract class CosmosDiagnosticsContext : CosmosDiagnosticsInternal, IE internal abstract void AddDiagnosticsInternal(CosmosDiagnosticsContext newContext); - internal abstract void SetSdkUserAgent(string userAgent); - public abstract IEnumerator GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() @@ -59,9 +61,22 @@ IEnumerator IEnumerable.GetEnumerator() return this.GetEnumerator(); } - internal static CosmosDiagnosticsContext Create(RequestOptions requestOptions) + internal static CosmosDiagnosticsContext Create( + RequestOptions requestOptions) + { + return requestOptions?.DiagnosticContextFactory?.Invoke() ?? + new CosmosDiagnosticsContextCore(); + } + + internal static CosmosDiagnosticsContext Create( + string operationName, + RequestOptions requestOptions, + string userAgentString) { - return requestOptions?.DiagnosticContextFactory?.Invoke() ?? new CosmosDiagnosticsContextCore(); + return requestOptions?.DiagnosticContextFactory?.Invoke() ?? + new CosmosDiagnosticsContextCore( + operationName, + userAgentString); } } } \ No newline at end of file diff --git a/Microsoft.Azure.Cosmos/src/Diagnostics/CosmosDiagnosticsContextCore.cs b/Microsoft.Azure.Cosmos/src/Diagnostics/CosmosDiagnosticsContextCore.cs index d7aecc3120..978467be23 100644 --- a/Microsoft.Azure.Cosmos/src/Diagnostics/CosmosDiagnosticsContextCore.cs +++ b/Microsoft.Azure.Cosmos/src/Diagnostics/CosmosDiagnosticsContextCore.cs @@ -8,7 +8,9 @@ namespace Microsoft.Azure.Cosmos using System.Collections.ObjectModel; using System.Diagnostics; using System.Linq; + using System.Security.Policy; using Microsoft.Azure.Cosmos.Diagnostics; + using Microsoft.Azure.Cosmos.Sql; using Microsoft.Azure.Documents.Rntbd; /// @@ -19,16 +21,16 @@ namespace Microsoft.Azure.Cosmos /// internal sealed class CosmosDiagnosticsContextCore : CosmosDiagnosticsContext { + private static readonly string DefaultUserAgentString; + private readonly CosmosDiagnosticScope overallScope; + /// /// Detailed view of all the operations. /// private List ContextList { get; } - private static readonly string DefaultUserAgentString; - - private readonly CosmosDiagnosticScope overallScope; - - private bool IsDefaultUserAgent = true; + private int totalRequestCount = 0; + private int failedRequestCount = 0; static CosmosDiagnosticsContextCore() { @@ -38,7 +40,17 @@ static CosmosDiagnosticsContextCore() } public CosmosDiagnosticsContextCore() + : this(nameof(CosmosDiagnosticsContextCore), + CosmosDiagnosticsContextCore.DefaultUserAgentString) { + } + + public CosmosDiagnosticsContextCore( + string operationName, + string userAgentString) + { + this.UserAgent = userAgentString ?? throw new ArgumentNullException(nameof(userAgentString)); + this.OperationName = operationName ?? throw new ArgumentNullException(nameof(operationName)); this.StartUtc = DateTime.UtcNow; this.ContextList = new List(); this.Diagnostics = new CosmosDiagnosticsCore(this); @@ -47,27 +59,40 @@ public CosmosDiagnosticsContextCore() public override DateTime StartUtc { get; } - public override int TotalRequestCount { get; protected set; } + public override string UserAgent { get; } - public override int FailedRequestCount { get; protected set; } - - public override string UserAgent { get; protected set; } = CosmosDiagnosticsContextCore.DefaultUserAgentString; + public override string OperationName { get; } internal override CosmosDiagnostics Diagnostics { get; } - internal override TimeSpan GetClientElapsedTime() + internal override IDisposable GetOverallScope() + { + return this.overallScope; + } + + internal override TimeSpan GetRunningElapsedTime() { return this.overallScope.GetElapsedTime(); } + internal override bool TryGetTotalElapsedTime(out TimeSpan timeSpan) + { + return this.overallScope.TryGetElapsedTime(out timeSpan); + } + internal override bool IsComplete() { return this.overallScope.IsComplete(); } - internal override IDisposable GetOverallScope() + public override int GetTotalRequestCount() { - return this.overallScope; + return this.totalRequestCount; + } + + public override int GetFailedRequestCount() + { + return this.failedRequestCount; } internal override IDisposable CreateScope(string name) @@ -154,12 +179,6 @@ internal override void AddDiagnosticsInternal(CosmosDiagnosticsContext newContex this.ContextList.AddRange(newContext); } - internal override void SetSdkUserAgent(string userAgent) - { - this.IsDefaultUserAgent = false; - this.UserAgent = userAgent; - } - public override void Accept(CosmosDiagnosticsInternalVisitor cosmosDiagnosticsInternalVisitor) { cosmosDiagnosticsInternalVisitor.Visit(this); @@ -183,10 +202,10 @@ public override IEnumerator GetEnumerator() private void AddRequestCount(int statusCode) { - this.TotalRequestCount++; + this.totalRequestCount++; if (statusCode < 200 || statusCode > 299) { - this.FailedRequestCount++; + this.failedRequestCount++; } } @@ -197,13 +216,8 @@ private void AddSummaryInfo(CosmosDiagnosticsContext newContext) return; } - if (this.IsDefaultUserAgent && newContext.UserAgent != null) - { - this.SetSdkUserAgent(newContext.UserAgent); - } - - this.TotalRequestCount += newContext.TotalRequestCount; - this.FailedRequestCount += newContext.FailedRequestCount; + this.totalRequestCount += newContext.GetTotalRequestCount(); + this.failedRequestCount += newContext.GetFailedRequestCount(); } } } \ No newline at end of file diff --git a/Microsoft.Azure.Cosmos/src/Diagnostics/CosmosDiagnosticsCore.cs b/Microsoft.Azure.Cosmos/src/Diagnostics/CosmosDiagnosticsCore.cs index e9bb8e986e..a9c3817cd2 100644 --- a/Microsoft.Azure.Cosmos/src/Diagnostics/CosmosDiagnosticsCore.cs +++ b/Microsoft.Azure.Cosmos/src/Diagnostics/CosmosDiagnosticsCore.cs @@ -21,7 +21,12 @@ internal CosmosDiagnosticsCore(CosmosDiagnosticsContext diagnosticsContext) /// public override TimeSpan GetClientElapsedTime() { - return this.Context.GetClientElapsedTime(); + if (this.Context.TryGetTotalElapsedTime(out TimeSpan timeSpan)) + { + return timeSpan; + } + + return this.Context.GetRunningElapsedTime(); } /// diff --git a/Microsoft.Azure.Cosmos/src/Diagnostics/CosmosDiagnosticsSerializerVisitor.cs b/Microsoft.Azure.Cosmos/src/Diagnostics/CosmosDiagnosticsSerializerVisitor.cs index b21e1eef3c..5e69bf8d90 100644 --- a/Microsoft.Azure.Cosmos/src/Diagnostics/CosmosDiagnosticsSerializerVisitor.cs +++ b/Microsoft.Azure.Cosmos/src/Diagnostics/CosmosDiagnosticsSerializerVisitor.cs @@ -73,25 +73,25 @@ public override void Visit(CosmosDiagnosticsContext cosmosDiagnosticsContext) this.jsonWriter.WritePropertyName("StartUtc"); this.jsonWriter.WriteValue(cosmosDiagnosticsContext.StartUtc.ToString("o", CultureInfo.InvariantCulture)); - if (cosmosDiagnosticsContext.IsComplete()) + if (cosmosDiagnosticsContext.TryGetTotalElapsedTime(out TimeSpan totalElapsedTime)) { this.jsonWriter.WritePropertyName("TotalElapsedTimeInMs"); + this.jsonWriter.WriteValue(totalElapsedTime.TotalMilliseconds); } else { this.jsonWriter.WritePropertyName("RunningElapsedTimeInMs"); + this.jsonWriter.WriteValue(cosmosDiagnosticsContext.GetRunningElapsedTime().TotalMilliseconds); } - this.jsonWriter.WriteValue(cosmosDiagnosticsContext.GetClientElapsedTime().TotalMilliseconds); - this.jsonWriter.WritePropertyName("UserAgent"); this.jsonWriter.WriteValue(cosmosDiagnosticsContext.UserAgent); this.jsonWriter.WritePropertyName("TotalRequestCount"); - this.jsonWriter.WriteValue(cosmosDiagnosticsContext.TotalRequestCount); + this.jsonWriter.WriteValue(cosmosDiagnosticsContext.GetTotalRequestCount()); this.jsonWriter.WritePropertyName("FailedRequestCount"); - this.jsonWriter.WriteValue(cosmosDiagnosticsContext.FailedRequestCount); + this.jsonWriter.WriteValue(cosmosDiagnosticsContext.GetFailedRequestCount()); this.jsonWriter.WriteEndObject(); diff --git a/Microsoft.Azure.Cosmos/src/Diagnostics/EmptyCosmosDiagnosticsContext.cs b/Microsoft.Azure.Cosmos/src/Diagnostics/EmptyCosmosDiagnosticsContext.cs index 6297678654..f1371c7da2 100644 --- a/Microsoft.Azure.Cosmos/src/Diagnostics/EmptyCosmosDiagnosticsContext.cs +++ b/Microsoft.Azure.Cosmos/src/Diagnostics/EmptyCosmosDiagnosticsContext.cs @@ -18,23 +18,19 @@ internal sealed class EmptyCosmosDiagnosticsContext : CosmosDiagnosticsContext private static readonly CosmosDiagnosticScope DefaultScope = new CosmosDiagnosticScope("DisabledScope"); public static readonly CosmosDiagnosticsContext Singleton = new EmptyCosmosDiagnosticsContext(); - private static readonly DateTime DefaultStartUtc = DateTime.MinValue; - private EmptyCosmosDiagnosticsContext() { this.Diagnostics = new CosmosDiagnosticsCore(this); } - public override DateTime StartUtc { get; } = EmptyCosmosDiagnosticsContext.DefaultStartUtc; - - public override int TotalRequestCount { get; protected set; } + public override DateTime StartUtc => DateTime.MinValue; - public override int FailedRequestCount { get; protected set; } - - public override string UserAgent { get; protected set; } = "Empty Context"; + public override string UserAgent => "Empty Context UserAgent"; internal override CosmosDiagnostics Diagnostics { get; } + public override string OperationName => "Empty Context OperationName"; + internal override IDisposable GetOverallScope() { return EmptyCosmosDiagnosticsContext.DefaultScope; @@ -82,10 +78,6 @@ internal override void AddDiagnosticsInternal(FeedRangeStatistics feedRangeStati { } - internal override void SetSdkUserAgent(string userAgent) - { - } - public override void Accept(CosmosDiagnosticsInternalVisitor cosmosDiagnosticsInternalVisitor) { } @@ -100,7 +92,7 @@ public override IEnumerator GetEnumerator() return EmptyCosmosDiagnosticsContext.EmptyList.GetEnumerator(); } - internal override TimeSpan GetClientElapsedTime() + internal override TimeSpan GetRunningElapsedTime() { return TimeSpan.Zero; } @@ -109,5 +101,20 @@ internal override bool IsComplete() { return true; } + + public override int GetTotalRequestCount() + { + return -1; + } + + public override int GetFailedRequestCount() + { + return -1; + } + + internal override bool TryGetTotalElapsedTime(out TimeSpan timeSpan) + { + return false; + } } } \ No newline at end of file diff --git a/Microsoft.Azure.Cosmos/src/Handler/RequestInvokerHandler.cs b/Microsoft.Azure.Cosmos/src/Handler/RequestInvokerHandler.cs index cc7784e62f..0d867f3cd9 100644 --- a/Microsoft.Azure.Cosmos/src/Handler/RequestInvokerHandler.cs +++ b/Microsoft.Azure.Cosmos/src/Handler/RequestInvokerHandler.cs @@ -112,73 +112,77 @@ public virtual async Task SendAsync( // DEVNOTE: Non-Item operations need to be refactored to always pass // the diagnostic context in. https://github.com/Azure/azure-cosmos-dotnet-v3/issues/1276 - IDisposable overallScope = null; + bool disposeDiagnosticContext = false; if (diagnosticsContext == null) { diagnosticsContext = CosmosDiagnosticsContext.Create(requestOptions); - overallScope = diagnosticsContext.GetOverallScope(); + disposeDiagnosticContext = true; } try { - using (overallScope) + HttpMethod method = RequestInvokerHandler.GetHttpMethod(operationType); + RequestMessage request = new RequestMessage( + method, + resourceUri, + diagnosticsContext) { - HttpMethod method = RequestInvokerHandler.GetHttpMethod(operationType); - RequestMessage request = new RequestMessage( - method, - resourceUri, - diagnosticsContext) - { - OperationType = operationType, - ResourceType = resourceType, - RequestOptions = requestOptions, - Content = streamPayload, - }; + OperationType = operationType, + ResourceType = resourceType, + RequestOptions = requestOptions, + Content = streamPayload, + }; - if (partitionKey.HasValue) + if (partitionKey.HasValue) + { + if (cosmosContainerCore == null && object.ReferenceEquals(partitionKey, Cosmos.PartitionKey.None)) { - if (cosmosContainerCore == null && object.ReferenceEquals(partitionKey, Cosmos.PartitionKey.None)) - { - throw new ArgumentException($"{nameof(cosmosContainerCore)} can not be null with partition key as PartitionKey.None"); - } - else if (partitionKey.Value.IsNone) + throw new ArgumentException($"{nameof(cosmosContainerCore)} can not be null with partition key as PartitionKey.None"); + } + else if (partitionKey.Value.IsNone) + { + using (diagnosticsContext.CreateScope("GetNonePkValue")) { - using (diagnosticsContext.CreateScope("GetNonePkValue")) + try { - try - { - PartitionKeyInternal partitionKeyInternal = await cosmosContainerCore.GetNonePartitionKeyValueAsync(cancellationToken); - request.Headers.PartitionKey = partitionKeyInternal.ToJsonString(); - } - catch (DocumentClientException dce) - { - return dce.ToCosmosResponseMessage(request); - } - catch (CosmosException ce) - { - return ce.ToCosmosResponseMessage(request); - } + PartitionKeyInternal partitionKeyInternal = await cosmosContainerCore.GetNonePartitionKeyValueAsync(cancellationToken); + request.Headers.PartitionKey = partitionKeyInternal.ToJsonString(); + } + catch (DocumentClientException dce) + { + return dce.ToCosmosResponseMessage(request); + } + catch (CosmosException ce) + { + return ce.ToCosmosResponseMessage(request); } - } - else - { - request.Headers.PartitionKey = partitionKey.Value.ToJsonString(); } } - - if (operationType == OperationType.Upsert) + else { - request.Headers.IsUpsert = bool.TrueString; + request.Headers.PartitionKey = partitionKey.Value.ToJsonString(); } + } - requestEnricher?.Invoke(request); - return await this.SendAsync(request, cancellationToken); + if (operationType == OperationType.Upsert) + { + request.Headers.IsUpsert = bool.TrueString; } + + requestEnricher?.Invoke(request); + return await this.SendAsync(request, cancellationToken); } catch (OperationCanceledException oe) { throw new CosmosOperationCanceledException(oe, diagnosticsContext); } + finally + { + if (disposeDiagnosticContext) + { + diagnosticsContext.GetOverallScope().Dispose(); + } + } } internal static HttpMethod GetHttpMethod( diff --git a/Microsoft.Azure.Cosmos/src/Handler/TransportHandler.cs b/Microsoft.Azure.Cosmos/src/Handler/TransportHandler.cs index 90e8eda140..2f69c53b1f 100644 --- a/Microsoft.Azure.Cosmos/src/Handler/TransportHandler.cs +++ b/Microsoft.Azure.Cosmos/src/Handler/TransportHandler.cs @@ -31,6 +31,14 @@ public override async Task SendAsync( RequestMessage request, CancellationToken cancellationToken) { + string stackTrace = new StackTrace().ToString(); + + await Task.Run(() => + { + string st = new StackTrace().ToString(); + Console.WriteLine(st); + }); + try { using (new ActivityScope(Guid.NewGuid())) diff --git a/Microsoft.Azure.Cosmos/src/Resource/ClientContextCore.cs b/Microsoft.Azure.Cosmos/src/Resource/ClientContextCore.cs index 5594037f61..488527acd6 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/ClientContextCore.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/ClientContextCore.cs @@ -179,6 +179,35 @@ internal override void ValidateResource(string resourceId) this.DocumentClient.ValidateResource(resourceId); } + internal override Task OperationHelperAsync( + string operationName, + RequestOptions requestOptions, + Func> task) + { + if (SynchronizationContext.Current == null) + { + return this.RunWithDiagnosticsHelperAsync( + operationName, + requestOptions, + task); + } + + return this.RunWithSynchronizationContextAndDiagnosticsHelperAsync( + operationName, + requestOptions, + task); + } + + internal override CosmosDiagnosticsContext CreateDiagnosticContext( + string operationName, + RequestOptions requestOptions) + { + return CosmosDiagnosticsContextCore.Create( + operationName, + requestOptions, + this.UserAgent); + } + internal override Task ProcessResourceOperationStreamAsync( Uri resourceUri, ResourceType resourceType, @@ -271,6 +300,7 @@ internal override Task ProcessResourceOperationAsync( CancellationToken cancellationToken) { this.ThrowIfDisposed(); + return this.RequestHandler.SendAsync( resourceUri: resourceUri, resourceType: resourceType, @@ -290,22 +320,26 @@ internal override async Task GetCachedContainerPropertiesAs CancellationToken cancellationToken) { this.ThrowIfDisposed(); - CosmosDiagnosticsContextCore diagnosticsContext = new CosmosDiagnosticsContextCore(); - ClientCollectionCache collectionCache = await this.DocumentClient.GetCollectionCacheAsync(); - try + CosmosDiagnosticsContext diagnosticsContext = CosmosDiagnosticsContextCore.Create(requestOptions: null); + using (diagnosticsContext.GetOverallScope()) { - using (diagnosticsContext.CreateScope("ContainerCache.ResolveByNameAsync")) + ClientCollectionCache collectionCache = await this.DocumentClient.GetCollectionCacheAsync(); + try { - return await collectionCache.ResolveByNameAsync( - HttpConstants.Versions.CurrentVersion, - containerUri, - cancellationToken); + using (diagnosticsContext.CreateScope("ContainerCache.ResolveByNameAsync")) + { + return await collectionCache.ResolveByNameAsync( + HttpConstants.Versions.CurrentVersion, + containerUri, + cancellationToken); + } + } + catch (DocumentClientException ex) + { + throw CosmosExceptionFactory.Create(ex, diagnosticsContext); } } - catch (DocumentClientException ex) - { - throw CosmosExceptionFactory.Create(ex, diagnosticsContext); - } + } internal override BatchAsyncContainerExecutor GetExecutorForContainer(ContainerInternal container) @@ -343,6 +377,42 @@ protected virtual void Dispose(bool disposing) } } + private Task RunWithSynchronizationContextAndDiagnosticsHelperAsync( + string operationName, + RequestOptions requestOptions, + Func> task) + { + Debug.Assert(SynchronizationContext.Current != null, "This should only be used when a SynchronizationContext is specified"); + + CosmosDiagnosticsContext diagnosticsContext = this.CreateDiagnosticContext( + operationName, + requestOptions); + + // Used on NETFX applications with SynchronizationContext when doing locking calls + return Task.Run(async () => + { + using (diagnosticsContext.GetOverallScope()) + using (diagnosticsContext.CreateScope("SynchronizationContext")) + { + return await task(diagnosticsContext); + } + }); + } + + private async Task RunWithDiagnosticsHelperAsync( + string operationName, + RequestOptions requestOptions, + Func> task) + { + CosmosDiagnosticsContext diagnosticsContext = this.CreateDiagnosticContext( + operationName, + requestOptions); + using (diagnosticsContext.GetOverallScope()) + { + return await task(diagnosticsContext).ConfigureAwait(false); + } + } + private async Task ProcessResourceOperationAsBulkStreamAsync( Uri resourceUri, ResourceType resourceType, @@ -433,4 +503,4 @@ private void ThrowIfDisposed() } } } -} \ No newline at end of file +} diff --git a/Microsoft.Azure.Cosmos/src/Resource/CosmosClientContext.cs b/Microsoft.Azure.Cosmos/src/Resource/CosmosClientContext.cs index 19c8b86a68..53d6d8009e 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/CosmosClientContext.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/CosmosClientContext.cs @@ -56,7 +56,16 @@ internal abstract Uri CreateLink( internal abstract Task GetCachedContainerPropertiesAsync( string containerUri, - CancellationToken cancellationToken = default(CancellationToken)); + CancellationToken cancellationToken); + + internal abstract Task OperationHelperAsync( + string operationName, + RequestOptions requestOptions, + Func> task); + + internal abstract CosmosDiagnosticsContext CreateDiagnosticContext( + string operationName, + RequestOptions requestOptions); /// /// This is a wrapper around ExecUtil method. This allows the calls to be mocked so logic done @@ -100,7 +109,7 @@ internal abstract Task ProcessResourceOperationAsync( ResourceType resourceType, OperationType operationType, RequestOptions requestOptions, - ContainerInternal cosmosContainerCore, + ContainerInternal containerInternal, PartitionKey? partitionKey, Stream streamPayload, Action requestEnricher, diff --git a/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseCore.cs b/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseCore.cs index fc50a16990..6247b46f7e 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseCore.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseCore.cs @@ -18,7 +18,7 @@ namespace Microsoft.Azure.Cosmos /// /// for or creating new databases, and reading/querying all databases; use `client.Databases`. /// - internal class DatabaseCore : DatabaseInternal + internal abstract class DatabaseCore : DatabaseInternal { protected DatabaseCore( CosmosClientContext clientContext, @@ -40,38 +40,44 @@ protected DatabaseCore( internal override CosmosClientContext ClientContext { get; } - public override async Task ReadAsync( - RequestOptions requestOptions = null, - CancellationToken cancellationToken = default(CancellationToken)) + public async Task ReadAsync( + CosmosDiagnosticsContext diagnosticsContext, + RequestOptions requestOptions, + CancellationToken cancellationToken) { ResponseMessage response = await this.ReadStreamAsync( - requestOptions: requestOptions, - cancellationToken: cancellationToken); + diagnosticsContext: diagnosticsContext, + requestOptions: requestOptions, + cancellationToken: cancellationToken); return this.ClientContext.ResponseFactory.CreateDatabaseResponse(this, response); } - public override async Task DeleteAsync( - RequestOptions requestOptions = null, - CancellationToken cancellationToken = default(CancellationToken)) + public async Task DeleteAsync( + CosmosDiagnosticsContext diagnosticsContext, + RequestOptions requestOptions, + CancellationToken cancellationToken) { ResponseMessage response = await this.DeleteStreamAsync( - requestOptions: requestOptions, - cancellationToken: cancellationToken); + diagnosticsContext: diagnosticsContext, + requestOptions: requestOptions, + cancellationToken: cancellationToken); return this.ClientContext.ResponseFactory.CreateDatabaseResponse(this, response); } - public async override Task ReadThroughputAsync( - CancellationToken cancellationToken = default(CancellationToken)) + public async Task ReadThroughputAsync( + CosmosDiagnosticsContext diagnosticsContext, + CancellationToken cancellationToken) { ThroughputResponse response = await this.ReadThroughputIfExistsAsync(null, cancellationToken); return response.Resource?.Throughput; } - public async override Task ReadThroughputAsync( + public async Task ReadThroughputAsync( + CosmosDiagnosticsContext diagnosticsContext, RequestOptions requestOptions, - CancellationToken cancellationToken = default(CancellationToken)) + CancellationToken cancellationToken) { string rid = await this.GetRIDAsync(cancellationToken); CosmosOffers cosmosOffers = new CosmosOffers(this.ClientContext); @@ -83,17 +89,18 @@ public async override Task ReadThroughputAsync( internal override async Task ReadThroughputIfExistsAsync( RequestOptions requestOptions, - CancellationToken cancellationToken = default(CancellationToken)) + CancellationToken cancellationToken) { string rid = await this.GetRIDAsync(cancellationToken); CosmosOffers cosmosOffers = new CosmosOffers(this.ClientContext); return await cosmosOffers.ReadThroughputIfExistsAsync(targetRID: rid, requestOptions: requestOptions, cancellationToken: cancellationToken); } - public async override Task ReplaceThroughputAsync( + public async Task ReplaceThroughputAsync( + CosmosDiagnosticsContext diagnosticsContext, int throughput, - RequestOptions requestOptions = null, - CancellationToken cancellationToken = default(CancellationToken)) + RequestOptions requestOptions, + CancellationToken cancellationToken) { string rid = await this.GetRIDAsync(cancellationToken); CosmosOffers cosmosOffers = new CosmosOffers(this.ClientContext); @@ -106,8 +113,8 @@ public async override Task ReplaceThroughputAsync( internal override async Task ReplaceThroughputIfExistsAsync( int throughput, - RequestOptions requestOptions = null, - CancellationToken cancellationToken = default(CancellationToken)) + RequestOptions requestOptions, + CancellationToken cancellationToken) { string rid = await this.GetRIDAsync(cancellationToken); CosmosOffers cosmosOffers = new CosmosOffers(this.ClientContext); @@ -118,11 +125,12 @@ internal override async Task ReplaceThroughputIfExistsAsync( cancellationToken: cancellationToken); } - public override Task CreateContainerStreamAsync( + public Task CreateContainerStreamAsync( + CosmosDiagnosticsContext diagnosticsContext, ContainerProperties containerProperties, ThroughputProperties throughputProperties, - RequestOptions requestOptions = null, - CancellationToken cancellationToken = default(CancellationToken)) + RequestOptions requestOptions, + CancellationToken cancellationToken) { if (containerProperties == null) { @@ -131,18 +139,19 @@ public override Task CreateContainerStreamAsync( this.ValidateContainerProperties(containerProperties); - Stream streamPayload = this.ClientContext.SerializerCore.ToStream(containerProperties); return this.ProcessCollectionCreateAsync( + diagnosticsContext: diagnosticsContext, streamPayload: this.ClientContext.SerializerCore.ToStream(containerProperties), throughputProperties: throughputProperties, requestOptions: requestOptions, cancellationToken: cancellationToken); } - public override async Task CreateContainerAsync( + public async Task CreateContainerAsync( + CosmosDiagnosticsContext diagnosticsContext, ContainerProperties containerProperties, ThroughputProperties throughputProperties, - RequestOptions requestOptions = null, + RequestOptions requestOptions, CancellationToken cancellationToken = default) { if (containerProperties == null) @@ -153,6 +162,7 @@ public override async Task CreateContainerAsync( this.ValidateContainerProperties(containerProperties); ResponseMessage response = await this.ProcessCollectionCreateAsync( + diagnosticsContext: diagnosticsContext, streamPayload: this.ClientContext.SerializerCore.ToStream(containerProperties), throughputProperties: throughputProperties, requestOptions: requestOptions, @@ -160,11 +170,12 @@ public override async Task CreateContainerAsync( return this.ClientContext.ResponseFactory.CreateContainerResponse(this.GetContainer(containerProperties.Id), response); } - public override async Task CreateContainerIfNotExistsAsync( + public async Task CreateContainerIfNotExistsAsync( + CosmosDiagnosticsContext diagnosticsContext, ContainerProperties containerProperties, ThroughputProperties throughputProperties, - RequestOptions requestOptions = null, - CancellationToken cancellationToken = default(CancellationToken)) + RequestOptions requestOptions, + CancellationToken cancellationToken) { if (containerProperties == null) { @@ -173,7 +184,7 @@ public override async Task CreateContainerIfNotExistsAsync( this.ValidateContainerProperties(containerProperties); - Container container = this.GetContainer(containerProperties.Id); + ContainerInternal container = (ContainerInternal)this.GetContainer(containerProperties.Id); ResponseMessage readResponse = await container.ReadContainerStreamAsync( cancellationToken: cancellationToken); @@ -198,6 +209,7 @@ public override async Task CreateContainerIfNotExistsAsync( this.ValidateContainerProperties(containerProperties); ResponseMessage createResponse = await this.CreateContainerStreamAsync( + diagnosticsContext, containerProperties, throughputProperties, requestOptions, @@ -221,9 +233,10 @@ public override async Task CreateContainerIfNotExistsAsync( return this.ClientContext.ResponseFactory.CreateContainerResponse(container, readResponseAfterCreate); } - public override async Task ReplaceThroughputAsync( + public async Task ReplaceThroughputAsync( + CosmosDiagnosticsContext diagnosticsContext, ThroughputProperties throughputProperties, - RequestOptions requestOptions = null, + RequestOptions requestOptions, CancellationToken cancellationToken = default) { string rid = await this.GetRIDAsync(cancellationToken); @@ -237,8 +250,8 @@ public override async Task ReplaceThroughputAsync( internal override async Task ReplaceThroughputPropertiesIfExistsAsync( ThroughputProperties throughputProperties, - RequestOptions requestOptions = null, - CancellationToken cancellationToken = default(CancellationToken)) + RequestOptions requestOptions, + CancellationToken cancellationToken) { string rid = await this.GetRIDAsync(cancellationToken); CosmosOffers cosmosOffers = new CosmosOffers(this.ClientContext); @@ -249,31 +262,42 @@ internal override async Task ReplaceThroughputPropertiesIfEx cancellationToken: cancellationToken); } - public override Task ReadStreamAsync( - RequestOptions requestOptions = null, - CancellationToken cancellationToken = default(CancellationToken)) + public Task ReadStreamAsync( + CosmosDiagnosticsContext diagnosticsContext, + RequestOptions requestOptions, + CancellationToken cancellationToken) { - return this.ProcessAsync( - OperationType.Read, - requestOptions, - cancellationToken); + return this.ProcessResourceOperationStreamAsync( + diagnosticsContext: diagnosticsContext, + streamPayload: null, + operationType: OperationType.Read, + linkUri: this.LinkUri, + resourceType: ResourceType.Database, + requestOptions: requestOptions, + cancellationToken: cancellationToken); } - public override Task DeleteStreamAsync( - RequestOptions requestOptions = null, - CancellationToken cancellationToken = default(CancellationToken)) + public Task DeleteStreamAsync( + CosmosDiagnosticsContext diagnosticsContext, + RequestOptions requestOptions, + CancellationToken cancellationToken) { - return this.ProcessAsync( - OperationType.Delete, - requestOptions, - cancellationToken); + return this.ProcessResourceOperationStreamAsync( + diagnosticsContext: diagnosticsContext, + streamPayload: null, + operationType: OperationType.Delete, + linkUri: this.LinkUri, + resourceType: ResourceType.Database, + requestOptions: requestOptions, + cancellationToken: cancellationToken); } - public override async Task CreateContainerAsync( - ContainerProperties containerProperties, - int? throughput = null, - RequestOptions requestOptions = null, - CancellationToken cancellationToken = default(CancellationToken)) + public async Task CreateContainerAsync( + CosmosDiagnosticsContext diagnosticsContext, + ContainerProperties containerProperties, + int? throughput, + RequestOptions requestOptions, + CancellationToken cancellationToken) { if (containerProperties == null) { @@ -282,7 +306,8 @@ public override async Task CreateContainerAsync( this.ValidateContainerProperties(containerProperties); - ResponseMessage response = await this.CreateContainerStreamInternalAsync( + ResponseMessage response = await this.ProcessCollectionCreateAsync( + diagnosticsContext: diagnosticsContext, streamPayload: this.ClientContext.SerializerCore.ToStream(containerProperties), throughput: throughput, requestOptions: requestOptions, @@ -291,12 +316,13 @@ public override async Task CreateContainerAsync( return this.ClientContext.ResponseFactory.CreateContainerResponse(this.GetContainer(containerProperties.Id), response); } - public override Task CreateContainerAsync( + public Task CreateContainerAsync( + CosmosDiagnosticsContext diagnosticsContext, string id, string partitionKeyPath, - int? throughput = null, - RequestOptions requestOptions = null, - CancellationToken cancellationToken = default(CancellationToken)) + int? throughput, + RequestOptions requestOptions, + CancellationToken cancellationToken) { if (string.IsNullOrEmpty(id)) { @@ -311,17 +337,19 @@ public override Task CreateContainerAsync( ContainerProperties containerProperties = new ContainerProperties(id, partitionKeyPath); return this.CreateContainerAsync( + diagnosticsContext, containerProperties, throughput, requestOptions, cancellationToken); } - public override async Task CreateContainerIfNotExistsAsync( + public async Task CreateContainerIfNotExistsAsync( + CosmosDiagnosticsContext diagnosticsContext, ContainerProperties containerProperties, - int? throughput = null, - RequestOptions requestOptions = null, - CancellationToken cancellationToken = default(CancellationToken)) + int? throughput, + RequestOptions requestOptions, + CancellationToken cancellationToken) { if (containerProperties == null) { @@ -332,12 +360,13 @@ public override async Task CreateContainerIfNotExistsAsync( ContainerInternal container = (ContainerInternal)this.GetContainer(containerProperties.Id); ResponseMessage readResponse = await this.ProcessResourceOperationStreamAsync( - null, - OperationType.Read, - container.LinkUri, - ResourceType.Collection, - requestOptions, - cancellationToken); + diagnosticsContext: diagnosticsContext, + streamPayload: null, + operationType: OperationType.Read, + linkUri: container.LinkUri, + resourceType: ResourceType.Collection, + requestOptions: requestOptions, + cancellationToken: cancellationToken); if (readResponse.StatusCode != HttpStatusCode.NotFound) { @@ -360,14 +389,12 @@ public override async Task CreateContainerIfNotExistsAsync( this.ValidateContainerProperties(containerProperties); ResponseMessage createResponse = await this.CreateContainerStreamAsync( + diagnosticsContext, containerProperties, throughput, requestOptions, cancellationToken); - // Merge the previous message diagnostics - createResponse.DiagnosticsContext.AddDiagnosticsInternal(readResponse.DiagnosticsContext); - if (readResponse.StatusCode != HttpStatusCode.Conflict) { return this.ClientContext.ResponseFactory.CreateContainerResponse(container, createResponse); @@ -376,24 +403,25 @@ public override async Task CreateContainerIfNotExistsAsync( // This second Read is to handle the race condition when 2 or more threads have Read the database and only one succeeds with Create // so for the remaining ones we should do a Read instead of throwing Conflict exception ResponseMessage readResponseAfterCreate = await this.ProcessResourceOperationStreamAsync( - null, - OperationType.Read, - container.LinkUri, - ResourceType.Collection, - requestOptions, - cancellationToken); + diagnosticsContext: diagnosticsContext, + streamPayload: null, + operationType: OperationType.Read, + linkUri: container.LinkUri, + resourceType: ResourceType.Collection, + requestOptions: requestOptions, + cancellationToken: cancellationToken); // Merge the previous message diagnostics - createResponse.DiagnosticsContext.AddDiagnosticsInternal(readResponse.DiagnosticsContext); return this.ClientContext.ResponseFactory.CreateContainerResponse(container, readResponseAfterCreate); } - public override Task CreateContainerIfNotExistsAsync( + public Task CreateContainerIfNotExistsAsync( + CosmosDiagnosticsContext diagnosticsContext, string id, string partitionKeyPath, - int? throughput = null, - RequestOptions requestOptions = null, - CancellationToken cancellationToken = default(CancellationToken)) + int? throughput, + RequestOptions requestOptions, + CancellationToken cancellationToken) { if (string.IsNullOrEmpty(id)) { @@ -406,7 +434,7 @@ public override Task CreateContainerIfNotExistsAsync( } ContainerProperties containerProperties = new ContainerProperties(id, partitionKeyPath); - return this.CreateContainerIfNotExistsAsync(containerProperties, throughput, requestOptions, cancellationToken); + return this.CreateContainerIfNotExistsAsync(diagnosticsContext, containerProperties, throughput, requestOptions, cancellationToken); } public override Container GetContainer(string id) @@ -422,11 +450,12 @@ public override Container GetContainer(string id) id); } - public override Task CreateContainerStreamAsync( + public Task CreateContainerStreamAsync( + CosmosDiagnosticsContext diagnosticsContext, ContainerProperties containerProperties, - int? throughput = null, - RequestOptions requestOptions = null, - CancellationToken cancellationToken = default(CancellationToken)) + int? throughput, + RequestOptions requestOptions, + CancellationToken cancellationToken) { if (containerProperties == null) { @@ -436,16 +465,19 @@ public override Task CreateContainerStreamAsync( this.ValidateContainerProperties(containerProperties); Stream streamPayload = this.ClientContext.SerializerCore.ToStream(containerProperties); - return this.CreateContainerStreamInternalAsync(streamPayload, + return this.ProcessCollectionCreateAsync( + diagnosticsContext, + streamPayload, throughput, requestOptions, cancellationToken); } - public override async Task CreateUserAsync( + public async Task CreateUserAsync( + CosmosDiagnosticsContext diagnosticsContext, string id, - RequestOptions requestOptions = null, - CancellationToken cancellationToken = default(CancellationToken)) + RequestOptions requestOptions, + CancellationToken cancellationToken) { if (string.IsNullOrEmpty(id)) { @@ -455,6 +487,7 @@ public override async Task CreateUserAsync( UserProperties userProperties = new UserProperties(id); ResponseMessage response = await this.CreateUserStreamAsync( + diagnosticsContext: diagnosticsContext, userProperties: userProperties, requestOptions: requestOptions, cancellationToken: cancellationToken); @@ -476,9 +509,10 @@ public override User GetUser(string id) } public Task CreateUserStreamAsync( + CosmosDiagnosticsContext diagnosticsContext, UserProperties userProperties, - RequestOptions requestOptions = null, - CancellationToken cancellationToken = default(CancellationToken)) + RequestOptions requestOptions, + CancellationToken cancellationToken) { if (userProperties == null) { @@ -489,14 +523,17 @@ public Task CreateUserStreamAsync( Stream streamPayload = this.ClientContext.SerializerCore.ToStream(userProperties); return this.ProcessUserCreateAsync( + diagnosticsContext: diagnosticsContext, streamPayload: streamPayload, requestOptions: requestOptions, cancellationToken: cancellationToken); } - public override async Task UpsertUserAsync(string id, + public async Task UpsertUserAsync( + CosmosDiagnosticsContext diagnosticsContext, + string id, RequestOptions requestOptions, - CancellationToken cancellationToken = default(CancellationToken)) + CancellationToken cancellationToken) { if (string.IsNullOrEmpty(id)) { @@ -506,6 +543,7 @@ public override async Task UpsertUserAsync(string id, this.ClientContext.ValidateResource(id); ResponseMessage response = await this.ProcessUserUpsertAsync( + diagnosticsContext: diagnosticsContext, streamPayload: this.ClientContext.SerializerCore.ToStream(new UserProperties(id)), requestOptions: requestOptions, cancellationToken: cancellationToken); @@ -675,6 +713,7 @@ private void ValidateContainerProperties(ContainerProperties containerProperties } private Task ProcessCollectionCreateAsync( + CosmosDiagnosticsContext diagnosticsContext, Stream streamPayload, ThroughputProperties throughputProperties, RequestOptions requestOptions, @@ -689,11 +728,12 @@ private Task ProcessCollectionCreateAsync( streamPayload: streamPayload, requestOptions: requestOptions, requestEnricher: (httpRequestMessage) => httpRequestMessage.AddThroughputPropertiesHeader(throughputProperties), - diagnosticsContext: null, + diagnosticsContext: diagnosticsContext, cancellationToken: cancellationToken); } private Task ProcessCollectionCreateAsync( + CosmosDiagnosticsContext diagnosticsContext, Stream streamPayload, int? throughput, RequestOptions requestOptions, @@ -708,11 +748,12 @@ private Task ProcessCollectionCreateAsync( streamPayload: streamPayload, requestOptions: requestOptions, requestEnricher: (httpRequestMessage) => httpRequestMessage.AddThroughputHeader(throughput), - diagnosticsContext: null, + diagnosticsContext: diagnosticsContext, cancellationToken: cancellationToken); } private Task ProcessUserCreateAsync( + CosmosDiagnosticsContext diagnosticsContext, Stream streamPayload, RequestOptions requestOptions, CancellationToken cancellationToken) @@ -726,14 +767,15 @@ private Task ProcessUserCreateAsync( streamPayload: streamPayload, requestOptions: requestOptions, requestEnricher: null, - diagnosticsContext: null, + diagnosticsContext: diagnosticsContext, cancellationToken: cancellationToken); } private Task ProcessUserUpsertAsync( + CosmosDiagnosticsContext diagnosticsContext, Stream streamPayload, - RequestOptions requestOptions = null, - CancellationToken cancellationToken = default(CancellationToken)) + RequestOptions requestOptions, + CancellationToken cancellationToken) { return this.ClientContext.ProcessResourceOperationStreamAsync( resourceUri: this.LinkUri, @@ -744,44 +786,18 @@ private Task ProcessUserUpsertAsync( streamPayload: streamPayload, requestOptions: requestOptions, requestEnricher: null, - diagnosticsContext: null, + diagnosticsContext: diagnosticsContext, cancellationToken: cancellationToken); } - internal override async Task GetRIDAsync(CancellationToken cancellationToken = default(CancellationToken)) + internal override async Task GetRIDAsync(CancellationToken cancellationToken) { DatabaseResponse databaseResponse = await this.ReadAsync(cancellationToken: cancellationToken); return databaseResponse?.Resource?.ResourceId; } - private Task CreateContainerStreamInternalAsync( - Stream streamPayload, - int? throughput, - RequestOptions requestOptions, - CancellationToken cancellationToken) - { - return this.ProcessCollectionCreateAsync( - streamPayload: streamPayload, - throughput: throughput, - requestOptions: requestOptions, - cancellationToken: cancellationToken); - } - - private Task ProcessAsync( - OperationType operationType, - RequestOptions requestOptions, - CancellationToken cancellationToken) - { - return this.ProcessResourceOperationStreamAsync( - streamPayload: null, - operationType: operationType, - requestOptions: requestOptions, - linkUri: this.LinkUri, - resourceType: ResourceType.Database, - cancellationToken: cancellationToken); - } - private Task ProcessResourceOperationStreamAsync( + CosmosDiagnosticsContext diagnosticsContext, Stream streamPayload, OperationType operationType, Uri linkUri, @@ -798,7 +814,7 @@ private Task ProcessResourceOperationStreamAsync( streamPayload: streamPayload, requestOptions: requestOptions, requestEnricher: null, - diagnosticsContext: null, + diagnosticsContext: diagnosticsContext, cancellationToken: cancellationToken); } } diff --git a/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseInlineCore.cs b/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseInlineCore.cs index ed0207b573..63bc2733d9 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseInlineCore.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseInlineCore.cs @@ -27,7 +27,10 @@ public override Task CreateContainerAsync( RequestOptions requestOptions = null, CancellationToken cancellationToken = default) { - return TaskHelper.RunInlineIfNeededAsync(() => base.CreateContainerAsync(containerProperties, throughput, requestOptions, cancellationToken)); + return this.ClientContext.OperationHelperAsync( + nameof(CreateContainerAsync), + requestOptions, + (diagnostics) => base.CreateContainerAsync(diagnostics, containerProperties, throughput, requestOptions, cancellationToken)); } public override Task CreateContainerAsync(string id, @@ -36,7 +39,10 @@ public override Task CreateContainerAsync(string id, RequestOptions requestOptions = null, CancellationToken cancellationToken = default) { - return TaskHelper.RunInlineIfNeededAsync(() => base.CreateContainerAsync(id, partitionKeyPath, throughput, requestOptions, cancellationToken)); + return this.ClientContext.OperationHelperAsync( + nameof(CreateContainerAsync), + requestOptions, + (diagnostics) => base.CreateContainerAsync(diagnostics, id, partitionKeyPath, throughput, requestOptions, cancellationToken)); } public override Task CreateContainerIfNotExistsAsync( @@ -45,7 +51,10 @@ public override Task CreateContainerIfNotExistsAsync( RequestOptions requestOptions = null, CancellationToken cancellationToken = default) { - return TaskHelper.RunInlineIfNeededAsync(() => base.CreateContainerIfNotExistsAsync(containerProperties, throughput, requestOptions, cancellationToken)); + return this.ClientContext.OperationHelperAsync( + nameof(CreateContainerIfNotExistsAsync), + requestOptions, + (diagnostics) => base.CreateContainerIfNotExistsAsync(diagnostics, containerProperties, throughput, requestOptions, cancellationToken)); } public override Task CreateContainerIfNotExistsAsync( @@ -55,7 +64,10 @@ public override Task CreateContainerIfNotExistsAsync( RequestOptions requestOptions = null, CancellationToken cancellationToken = default) { - return TaskHelper.RunInlineIfNeededAsync(() => base.CreateContainerIfNotExistsAsync(id, partitionKeyPath, throughput, requestOptions, cancellationToken)); + return this.ClientContext.OperationHelperAsync( + nameof(CreateContainerIfNotExistsAsync), + requestOptions, + (diagnostics) => base.CreateContainerIfNotExistsAsync(diagnostics, id, partitionKeyPath, throughput, requestOptions, cancellationToken)); } public override Task CreateContainerStreamAsync( @@ -64,14 +76,20 @@ public override Task CreateContainerStreamAsync( RequestOptions requestOptions = null, CancellationToken cancellationToken = default) { - return TaskHelper.RunInlineIfNeededAsync(() => base.CreateContainerStreamAsync(containerProperties, throughput, requestOptions, cancellationToken)); + return this.ClientContext.OperationHelperAsync( + nameof(CreateContainerStreamAsync), + requestOptions, + (diagnostics) => base.CreateContainerStreamAsync(diagnostics, containerProperties, throughput, requestOptions, cancellationToken)); } public override Task CreateUserAsync(string id, RequestOptions requestOptions = null, CancellationToken cancellationToken = default) { - return TaskHelper.RunInlineIfNeededAsync(() => base.CreateUserAsync(id, requestOptions, cancellationToken)); + return this.ClientContext.OperationHelperAsync( + nameof(CreateUserAsync), + requestOptions, + (diagnostics) => base.CreateUserAsync(diagnostics, id, requestOptions, cancellationToken)); } public override ContainerBuilder DefineContainer( @@ -85,14 +103,20 @@ public override Task DeleteAsync( RequestOptions requestOptions = null, CancellationToken cancellationToken = default) { - return TaskHelper.RunInlineIfNeededAsync(() => base.DeleteAsync(requestOptions, cancellationToken)); + return this.ClientContext.OperationHelperAsync( + nameof(DeleteAsync), + requestOptions, + (diagnostics) => base.DeleteAsync(diagnostics, requestOptions, cancellationToken)); } public override Task DeleteStreamAsync( RequestOptions requestOptions = null, CancellationToken cancellationToken = default) { - return TaskHelper.RunInlineIfNeededAsync(() => base.DeleteStreamAsync(requestOptions, cancellationToken)); + return this.ClientContext.OperationHelperAsync( + nameof(DeleteStreamAsync), + requestOptions, + (diagnostics) => base.DeleteStreamAsync(diagnostics, requestOptions, cancellationToken)); } public override Container GetContainer(string id) @@ -101,9 +125,9 @@ public override Container GetContainer(string id) } public override FeedIterator GetContainerQueryIterator( - QueryDefinition queryDefinition, - string continuationToken = null, - QueryRequestOptions requestOptions = null) + QueryDefinition queryDefinition, + string continuationToken = null, + QueryRequestOptions requestOptions = null) { return new FeedIteratorInlineCore(base.GetContainerQueryIterator( queryDefinition, @@ -173,26 +197,38 @@ public override FeedIterator GetUserQueryIterator( public override Task ReadAsync(RequestOptions requestOptions = null, CancellationToken cancellationToken = default) { - return TaskHelper.RunInlineIfNeededAsync(() => base.ReadAsync(requestOptions, cancellationToken)); + return this.ClientContext.OperationHelperAsync( + nameof(ReadAsync), + requestOptions, + (diagnostics) => base.ReadAsync(diagnostics, requestOptions, cancellationToken)); } public override Task ReadStreamAsync( RequestOptions requestOptions = null, CancellationToken cancellationToken = default) { - return TaskHelper.RunInlineIfNeededAsync(() => base.ReadStreamAsync(requestOptions, cancellationToken)); + return this.ClientContext.OperationHelperAsync( + nameof(ReadStreamAsync), + requestOptions, + (diagnostics) => base.ReadStreamAsync(diagnostics, requestOptions, cancellationToken)); } public override Task ReadThroughputAsync(CancellationToken cancellationToken = default) { - return TaskHelper.RunInlineIfNeededAsync(() => base.ReadThroughputAsync(cancellationToken)); + return this.ClientContext.OperationHelperAsync( + nameof(ReadThroughputAsync), + null, + (diagnostics) => base.ReadThroughputAsync(diagnostics, cancellationToken)); } public override Task ReadThroughputAsync( RequestOptions requestOptions, CancellationToken cancellationToken = default) { - return TaskHelper.RunInlineIfNeededAsync(() => base.ReadThroughputAsync(requestOptions, cancellationToken)); + return this.ClientContext.OperationHelperAsync( + nameof(ReadThroughputAsync), + requestOptions, + (diagnostics) => base.ReadThroughputAsync(diagnostics, requestOptions, cancellationToken)); } public override Task ReplaceThroughputAsync( @@ -200,17 +236,33 @@ public override Task ReplaceThroughputAsync( RequestOptions requestOptions = null, CancellationToken cancellationToken = default) { - return TaskHelper.RunInlineIfNeededAsync(() => base.ReplaceThroughputAsync(throughput, requestOptions, cancellationToken)); + return this.ClientContext.OperationHelperAsync( + nameof(ReplaceThroughputAsync), + requestOptions, + (diagnostics) => base.ReplaceThroughputAsync(diagnostics, throughput, requestOptions, cancellationToken)); } - public override Task ReplaceThroughputAsync(ThroughputProperties throughputProperties, RequestOptions requestOptions = null, CancellationToken cancellationToken = default) + public override Task ReplaceThroughputAsync( + ThroughputProperties throughputProperties, + RequestOptions requestOptions = null, + CancellationToken cancellationToken = default) { - return TaskHelper.RunInlineIfNeededAsync(() => base.ReplaceThroughputAsync(throughputProperties, requestOptions, cancellationToken)); + return this.ClientContext.OperationHelperAsync( + nameof(ReplaceThroughputAsync), + requestOptions, + (diagnostics) => base.ReplaceThroughputAsync(diagnostics, throughputProperties, requestOptions, cancellationToken)); } - public override Task CreateContainerAsync(ContainerProperties containerProperties, ThroughputProperties throughputProperties, RequestOptions requestOptions = null, CancellationToken cancellationToken = default) + public override Task CreateContainerAsync( + ContainerProperties containerProperties, + ThroughputProperties throughputProperties, + RequestOptions requestOptions = null, + CancellationToken cancellationToken = default) { - return TaskHelper.RunInlineIfNeededAsync(() => base.CreateContainerAsync(containerProperties, throughputProperties, requestOptions, cancellationToken)); + return this.ClientContext.OperationHelperAsync( + nameof(CreateContainerAsync), + requestOptions, + (diagnostics) => base.CreateContainerAsync(diagnostics, containerProperties, throughputProperties, requestOptions, cancellationToken)); } public override Task CreateContainerIfNotExistsAsync( @@ -219,7 +271,10 @@ public override Task CreateContainerIfNotExistsAsync( RequestOptions requestOptions = null, CancellationToken cancellationToken = default(CancellationToken)) { - return TaskHelper.RunInlineIfNeededAsync(() => base.CreateContainerIfNotExistsAsync(containerProperties, throughputProperties, requestOptions, cancellationToken)); + return this.ClientContext.OperationHelperAsync( + nameof(CreateContainerIfNotExistsAsync), + requestOptions, + (diagnostics) => base.CreateContainerIfNotExistsAsync(diagnostics, containerProperties, throughputProperties, requestOptions, cancellationToken)); } public override Task CreateContainerStreamAsync( @@ -228,7 +283,10 @@ public override Task CreateContainerStreamAsync( RequestOptions requestOptions = null, CancellationToken cancellationToken = default) { - return TaskHelper.RunInlineIfNeededAsync(() => base.CreateContainerStreamAsync(containerProperties, throughputProperties, requestOptions, cancellationToken)); + return this.ClientContext.OperationHelperAsync( + nameof(CreateContainerStreamAsync), + requestOptions, + (diagnostics) => base.CreateContainerStreamAsync(diagnostics, containerProperties, throughputProperties, requestOptions, cancellationToken)); } public override Task UpsertUserAsync( @@ -236,7 +294,10 @@ public override Task UpsertUserAsync( RequestOptions requestOptions = null, CancellationToken cancellationToken = default) { - return TaskHelper.RunInlineIfNeededAsync(() => base.UpsertUserAsync(id, requestOptions, cancellationToken)); + return this.ClientContext.OperationHelperAsync( + nameof(UpsertUserAsync), + requestOptions, + (diagnostics) => base.UpsertUserAsync(diagnostics, id, requestOptions, cancellationToken)); } } } diff --git a/Microsoft.Azure.Cosmos/src/Resource/FeedIterators/FeedIteratorCore.cs b/Microsoft.Azure.Cosmos/src/Resource/FeedIterators/FeedIteratorCore.cs index 2af94128b7..a3704db8aa 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/FeedIterators/FeedIteratorCore.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/FeedIterators/FeedIteratorCore.cs @@ -62,10 +62,10 @@ public FeedIteratorCore( /// A query response from cosmos service public override async Task ReadNextAsync(CancellationToken cancellationToken = default) { - CosmosDiagnosticsContext diagnostics = CosmosDiagnosticsContext.Create(this.requestOptions); - using (diagnostics.GetOverallScope()) + CosmosDiagnosticsContext diagnosticsContext = CosmosDiagnosticsContext.Create(this.requestOptions); + using (diagnosticsContext.GetOverallScope()) { - return await this.ReadNextInternalAsync(diagnostics, cancellationToken); + return await this.ReadNextInternalAsync(diagnosticsContext, cancellationToken); } } diff --git a/Microsoft.Azure.Cosmos/src/Resource/QueryResponses/StandByFeedIteratorCore.cs b/Microsoft.Azure.Cosmos/src/Resource/QueryResponses/StandByFeedIteratorCore.cs index 589e38ba2d..e0bc59164a 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/QueryResponses/StandByFeedIteratorCore.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/QueryResponses/StandByFeedIteratorCore.cs @@ -158,7 +158,7 @@ internal virtual Task NextResultSetDelegateAsync( resourceType: Documents.ResourceType.Document, operationType: Documents.OperationType.ReadFeed, requestOptions: options, - cosmosContainerCore: this.container, + containerInternal: this.container, requestEnricher: request => { ChangeFeedRequestOptions.FillContinuationToken(request, continuationToken); diff --git a/Microsoft.Azure.Cosmos/src/Resource/Settings/ThroughputProperties.cs b/Microsoft.Azure.Cosmos/src/Resource/Settings/ThroughputProperties.cs index 4defe38f94..49cae439bb 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Settings/ThroughputProperties.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Settings/ThroughputProperties.cs @@ -118,6 +118,16 @@ public static ThroughputProperties CreateAutoscaleThroughput( autoUpgradeMaxThroughputIncrementPercentage: null)); } + internal static ThroughputProperties CreateManualThroughput(int? throughput) + { + if (!throughput.HasValue) + { + return null; + } + + return CreateManualThroughput(throughput.Value); + } + internal static ThroughputProperties CreateAutoscaleThroughput( int maxAutoscaleThroughput, int? autoUpgradeMaxThroughputIncrementPercentage = null) diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosDiagnosticsTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosDiagnosticsTests.cs index a35b1ad34d..2bb67afc78 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosDiagnosticsTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosDiagnosticsTests.cs @@ -618,7 +618,7 @@ public static void VerifyQueryDiagnostics( CosmosDiagnosticsContext diagnosticsContext = (diagnostics as CosmosDiagnosticsCore).Context; // If all the pages are buffered then several of the normal summary validation will fail. - if (diagnosticsContext.TotalRequestCount > 0) + if (diagnosticsContext.GetTotalRequestCount() > 0) { DiagnosticValidator.ValidateCosmosDiagnosticsContext(diagnosticsContext); } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Utils/DiagnosticValidators.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Utils/DiagnosticValidators.cs index 66a97c770a..dbb49b5d15 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Utils/DiagnosticValidators.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Utils/DiagnosticValidators.cs @@ -52,9 +52,9 @@ internal static void ValidateCosmosDiagnosticsContext( { Assert.IsTrue((cosmosDiagnosticsContext.StartUtc - DateTime.UtcNow) < TimeSpan.FromHours(12), $"Start Time is not valid {cosmosDiagnosticsContext.StartUtc}"); Assert.AreNotEqual(cosmosDiagnosticsContext.UserAgent.ToString(), new UserAgentContainer().UserAgent.ToString(), "User agent not set"); - Assert.IsTrue(cosmosDiagnosticsContext.TotalRequestCount > 0, "No request found"); + Assert.IsTrue(cosmosDiagnosticsContext.GetTotalRequestCount() > 0, "No request found"); Assert.IsTrue(cosmosDiagnosticsContext.IsComplete(), "OverallClientRequestTime should be stopped"); - Assert.IsTrue(cosmosDiagnosticsContext.GetClientElapsedTime() > TimeSpan.Zero, "OverallClientRequestTime should have time."); + Assert.IsTrue(cosmosDiagnosticsContext.GetRunningElapsedTime() > TimeSpan.Zero, "OverallClientRequestTime should have time."); string info = cosmosDiagnosticsContext.ToString(); Assert.IsNotNull(info); @@ -161,7 +161,7 @@ private static void ValidateClientSideRequestStatistics(CosmosClientSideRequestS Assert.IsNotNull(stats.RegionsContacted); Assert.IsNotNull(stats.FailedReplicas); - if (stats.DiagnosticsContext.FailedRequestCount == 0) + if (stats.DiagnosticsContext.GetFailedRequestCount() == 0) { Assert.AreEqual(stats.EstimatedClientDelayFromAllCauses, TimeSpan.Zero); Assert.AreEqual(stats.EstimatedClientDelayFromRateLimiting, TimeSpan.Zero); @@ -173,7 +173,7 @@ private static void ValidateClientSideRequestStatistics(CosmosClientSideRequestS } // If all the request failed it's possible to not contact a region or replica. - if (stats.DiagnosticsContext.TotalRequestCount < stats.DiagnosticsContext.FailedRequestCount) + if (stats.DiagnosticsContext.GetTotalRequestCount() < stats.DiagnosticsContext.GetFailedRequestCount()) { Assert.IsTrue(stats.RegionsContacted.Count > 0); Assert.IsTrue(stats.ContactedReplicas.Count > 0); @@ -277,10 +277,10 @@ public override void Visit(CosmosDiagnosticsContext cosmosDiagnosticsContext) { this.isContextVisited = true; this.StartTimeUtc = cosmosDiagnosticsContext.StartUtc; - this.TotalElapsedTime = cosmosDiagnosticsContext.GetClientElapsedTime(); + this.TotalElapsedTime = cosmosDiagnosticsContext.GetRunningElapsedTime(); // Buffered pages are normal and have 0 request. This causes most validation to fail. - if(cosmosDiagnosticsContext.TotalRequestCount > 0) + if(cosmosDiagnosticsContext.GetTotalRequestCount() > 0) { DiagnosticValidator.ValidateCosmosDiagnosticsContext(cosmosDiagnosticsContext); } @@ -379,7 +379,7 @@ public override void Visit(CosmosDiagnosticsContext cosmosDiagnosticsContext) Assert.IsFalse(this.isContextVisited, "Point operations should only have a single context"); this.isContextVisited = true; this.StartTimeUtc = cosmosDiagnosticsContext.StartUtc; - this.TotalElapsedTime = cosmosDiagnosticsContext.GetClientElapsedTime(); + this.TotalElapsedTime = cosmosDiagnosticsContext.GetRunningElapsedTime(); DiagnosticValidator.ValidateCosmosDiagnosticsContext(cosmosDiagnosticsContext); @@ -477,7 +477,7 @@ public override void Visit(CosmosDiagnosticsContext cosmosDiagnosticsContext) Assert.IsFalse(this.isContextVisited, "Point operations should only have a single context"); this.isContextVisited = true; this.StartTimeUtc = cosmosDiagnosticsContext.StartUtc; - this.TotalElapsedTime = cosmosDiagnosticsContext.GetClientElapsedTime(); + this.TotalElapsedTime = cosmosDiagnosticsContext.GetRunningElapsedTime(); DiagnosticValidator.ValidateCosmosDiagnosticsContext(cosmosDiagnosticsContext); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosDiagnosticsUnitTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosDiagnosticsUnitTests.cs index 8b2c06c670..59b7059216 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosDiagnosticsUnitTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosDiagnosticsUnitTests.cs @@ -21,7 +21,9 @@ public class CosmosDiagnosticsUnitTests [TestMethod] public void ValidateDiagnosticsContext() { - CosmosDiagnosticsContext cosmosDiagnostics = new CosmosDiagnosticsContextCore(); + CosmosDiagnosticsContext cosmosDiagnostics = new CosmosDiagnosticsContextCore( + nameof(ValidateDiagnosticsContext), + "cosmos-netstandard-sdk"); cosmosDiagnostics.GetOverallScope().Dispose(); string diagnostics = cosmosDiagnostics.ToString(); @@ -30,7 +32,9 @@ public void ValidateDiagnosticsContext() JToken summary = jObject["Summary"]; Assert.IsTrue(summary["UserAgent"].ToString().Contains("cosmos-netstandard-sdk"), "Diagnostics should have user agent string"); - cosmosDiagnostics = new CosmosDiagnosticsContextCore(); + cosmosDiagnostics = new CosmosDiagnosticsContextCore( + nameof(ValidateDiagnosticsContext), + "MyCustomUserAgentString"); using (cosmosDiagnostics.GetOverallScope()) { // Test all the different operations on diagnostics context @@ -67,8 +71,6 @@ public void ValidateDiagnosticsContext() } } - cosmosDiagnostics.SetSdkUserAgent("MyCustomUserAgentString"); - string result = cosmosDiagnostics.ToString(); string regex = @"\{""DiagnosticVersion"":""2"",""Summary"":\{""StartUtc"":"".+Z"",""TotalElapsedTimeInMs"":.+,""UserAgent"":""MyCustomUserAgentString"",""TotalRequestCount"":2,""FailedRequestCount"":1\},""Context"":\[\{""Id"":""ValidateScope"",""ElapsedTimeInMs"":.+\},\{""Id"":""PointOperationStatistics"",""ActivityId"":""692ab2f2-41ba-486b-aad7-8c7c6c52379f"",""ResponseTimeUtc"":"".+Z"",""StatusCode"":429,""SubStatusCode"":0,""RequestCharge"":42.0,""RequestUri"":""http://MockUri.com"",""RequestSessionToken"":null,""ResponseSessionToken"":null\},\{""Id"":""SuccessScope"",""ElapsedTimeInMs"":.+\},\{""Id"":""PointOperationStatistics"",""ActivityId"":""de09baab-71a4-4897-a163-470711c93ed3"",""ResponseTimeUtc"":"".+Z"",""StatusCode"":200,""SubStatusCode"":0,""RequestCharge"":42.0,""RequestUri"":""http://MockUri.com"",""RequestSessionToken"":null,""ResponseSessionToken"":null\}\]\}"; @@ -87,7 +89,9 @@ public void ValidateDiagnosticsContext() [TestMethod] public void ValidateDiagnosticsAppendContext() { - CosmosDiagnosticsContext cosmosDiagnostics = new CosmosDiagnosticsContextCore(); + CosmosDiagnosticsContext cosmosDiagnostics = new CosmosDiagnosticsContextCore( + nameof(ValidateDiagnosticsAppendContext), + "MyCustomUserAgentString"); CosmosDiagnosticsContext cosmosDiagnostics2; using (cosmosDiagnostics.GetOverallScope()) @@ -98,9 +102,9 @@ public void ValidateDiagnosticsAppendContext() Thread.Sleep(TimeSpan.FromSeconds(2)); } - cosmosDiagnostics.SetSdkUserAgent("MyCustomUserAgentString"); - - cosmosDiagnostics2 = new CosmosDiagnosticsContextCore(); + cosmosDiagnostics2 = new CosmosDiagnosticsContextCore( + nameof(ValidateDiagnosticsAppendContext), + "MyCustomUserAgentString"); cosmosDiagnostics2.GetOverallScope().Dispose(); using (cosmosDiagnostics.CreateScope("CosmosDiagnostics2Scope")) @@ -121,7 +125,7 @@ public void ValidateDiagnosticsAppendContext() public void ValidateClientSideRequestStatisticsToString() { // Verify that API using the interface get the older v2 string - CosmosDiagnosticsContext diagnosticsContext = new CosmosDiagnosticsContextCore(); + CosmosDiagnosticsContext diagnosticsContext = MockCosmosUtil.CreateDiagnosticsContext(); diagnosticsContext.GetOverallScope().Dispose(); CosmosClientSideRequestStatistics clientSideRequestStatistics = new CosmosClientSideRequestStatistics(diagnosticsContext); @@ -174,7 +178,7 @@ public void ValidateClientSideRequestStatisticsToString() [TestMethod] public void TestUpdatesWhileVisiting() { - CosmosDiagnosticsContext cosmosDiagnostics = new CosmosDiagnosticsContextCore(); + CosmosDiagnosticsContext cosmosDiagnostics = MockCosmosUtil.CreateDiagnosticsContext(); cosmosDiagnostics.CreateScope("FirstScope"); bool isFirst = true; @@ -185,9 +189,9 @@ public void TestUpdatesWhileVisiting() cosmosDiagnostics.CreateScope("SecondScope"); isFirst = false; } - + diagnostic.ToString(); } } } -} +} \ No newline at end of file diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosQueryUnitTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosQueryUnitTests.cs index b8a69351ca..492409158b 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosQueryUnitTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosQueryUnitTests.cs @@ -42,7 +42,7 @@ public void VerifyNegativeCosmosQueryResponseStream() double requestCharge = 42.42; CosmosDiagnosticsContext diagnostics = new CosmosDiagnosticsContextCore(); CosmosException cosmosException = CosmosExceptionFactory.CreateBadRequestException(errorMessage, diagnosticsContext: diagnostics); - + diagnostics.GetOverallScope().Dispose(); QueryResponse queryResponse = QueryResponse.CreateFailure( statusCode: HttpStatusCode.NotFound, diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Utils/MockCosmosUtil.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Utils/MockCosmosUtil.cs index 0257379417..b631482daf 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Utils/MockCosmosUtil.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Utils/MockCosmosUtil.cs @@ -46,6 +46,13 @@ public static CosmosClient CreateMockCosmosClient( return cosmosClientBuilder.Build(documentClient); } + public static CosmosDiagnosticsContext CreateDiagnosticsContext() + { + return new CosmosDiagnosticsContextCore( + nameof(CreateDiagnosticsContext), + "DiagnosticValidatorUserAgentString"); + } + public static Mock CreateMockContainer( string dbName = "myDb", string containerName = "myContainer")