Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added stack trace to CosmosException, ResponseMessage.ErrorMessage includes full exception info. #1213

Merged
merged 27 commits into from
Feb 28, 2020
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
d4b9c9c
Removed Error since it is not being used anywhere.
Feb 11, 2020
ef9a94b
Removed error since it's not being used
Feb 11, 2020
87b363c
Refactored added new exception types
Feb 13, 2020
d1406ec
ResponseMessage.ErrorMessage will now return the full CosmosException…
Feb 14, 2020
eb37121
Fixed build issue
Feb 14, 2020
e8422e3
Renamed exception to add Cosmos to avoid confusion with Document name…
Feb 18, 2020
f783e54
Fixed exception handling and updated tests.
Feb 19, 2020
61905b1
Fixed tests
Feb 20, 2020
23a7a99
Fixed ExceptionWithStackTraceException to use original exception stac…
Feb 20, 2020
73d5632
Merge remote-tracking branch 'origin/master' into users/jawilley/diag…
Feb 20, 2020
97fae63
Fixed merge conflicts with latest
Feb 20, 2020
968fb97
Added diagnostic context to exceptions.
Feb 20, 2020
1162ce1
Fixed test for retail build
Feb 20, 2020
32343f2
Updated error message field in linq tests
Feb 21, 2020
064c1f5
Converted the stack trace to a string. Removed creating the stack tra…
Feb 21, 2020
a41b615
Updated changelog
Feb 21, 2020
0d2e970
Removed typed exceptions to avoid exposing internal types.
Feb 25, 2020
b5507e0
Merged to latest
Feb 25, 2020
74beae5
Adding transport client exception tests.
Feb 26, 2020
300872b
Update Microsoft.Azure.Cosmos/src/Resource/CosmosExceptions/CosmosExc…
j82w Feb 27, 2020
fce942a
Update Microsoft.Azure.Cosmos/src/Resource/CosmosExceptions/CosmosExc…
j82w Feb 27, 2020
680cb2e
Removed diagnostics from Response.ErrorMessage
Feb 27, 2020
c4e9490
Fixed unit test
Feb 27, 2020
46d9b1c
Adding Error object to CosmosException for back compatability.
Feb 27, 2020
4a72093
Adding unit test for Error handling
Feb 27, 2020
cad13c7
Fixed DocumentServiceResponse handling
Feb 28, 2020
553a761
Increased EndpointFailureMockTest wait time to avoid transient failures.
Feb 28, 2020
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
Original file line number Diff line number Diff line change
Expand Up @@ -212,9 +212,8 @@ internal ResponseMessage ToResponseMessage()
ResponseMessage responseMessage = new ResponseMessage(
statusCode: this.StatusCode,
requestMessage: null,
errorMessage: null,
error: null,
headers: headers,
cosmosException: null,
diagnostics: this.DiagnosticsContext ?? CosmosDiagnosticsContext.Create())
{
Content = this.ResourceStream
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace Microsoft.Azure.Cosmos
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Azure.Cosmos.Resource.CosmosExceptions;
using Microsoft.Azure.Documents;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
Expand Down Expand Up @@ -134,7 +135,7 @@ public async Task<Stream> DecryptAsync(
EncryptionProperties encryptionProperties = encryptionPropertiesJObj.ToObject<EncryptionProperties>();
if (encryptionProperties.EncryptionFormatVersion != 1)
{
throw new CosmosException(HttpStatusCode.InternalServerError, $"Unknown encryption format version: {encryptionProperties.EncryptionFormatVersion}. Please upgrade your SDK to the latest version.");
throw new CosmosInternalServerErrorException($"Unknown encryption format version: {encryptionProperties.EncryptionFormatVersion}. Please upgrade your SDK to the latest version.");
}

DataEncryptionKeyCore tempDek = (DataEncryptionKeyInlineCore)database.GetDataEncryptionKey(id: "unknown");
Expand Down
76 changes: 17 additions & 59 deletions Microsoft.Azure.Cosmos/src/Handler/ResponseMessage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ namespace Microsoft.Azure.Cosmos
using System.Diagnostics;
using System.IO;
using System.Net;
using Microsoft.Azure.Cosmos.Resource.CosmosExceptions;
using Microsoft.Azure.Documents;

/// <summary>
Expand All @@ -22,6 +23,7 @@ public ResponseMessage()
{
this.Headers = new Headers();
this.DiagnosticsContext = CosmosDiagnosticsContext.Create();
this.CosmosException = null;
}

/// <summary>
Expand All @@ -42,32 +44,36 @@ public ResponseMessage(

this.StatusCode = statusCode;
this.RequestMessage = requestMessage;
this.ErrorMessage = errorMessage;
this.Headers = new Headers();
this.DiagnosticsContext = requestMessage?.DiagnosticsContext ?? CosmosDiagnosticsContext.Create();

if (!string.IsNullOrEmpty(errorMessage))
{
this.CosmosException = CosmosExceptionFactory.Create(
statusCode,
requestMessage,
errorMessage);
}
}

/// <summary>
/// Create a <see cref="ResponseMessage"/>
/// </summary>
/// <param name="statusCode">The HttpStatusCode of the response</param>
/// <param name="requestMessage">The <see cref="Cosmos.RequestMessage"/> object</param>
/// <param name="errorMessage">The reason for failures if any.</param>
/// <param name="error">The inner error object</param>
/// <param name="headers">The headers for the response.</param>
/// <param name="cosmosException">The exception if the response is from an error.</param>
/// <param name="diagnostics">The diagnostics for the request</param>
internal ResponseMessage(
HttpStatusCode statusCode,
RequestMessage requestMessage,
string errorMessage,
Error error,
Headers headers,
CosmosException cosmosException,
CosmosDiagnosticsContext diagnostics)
{
this.StatusCode = statusCode;
this.RequestMessage = requestMessage;
this.ErrorMessage = errorMessage;
this.Error = error;
this.CosmosException = cosmosException;
this.Headers = headers ?? new Headers();
this.DiagnosticsContext = diagnostics ?? throw new ArgumentNullException(nameof(diagnostics));
}
Expand All @@ -93,7 +99,7 @@ public virtual Stream Content
/// <summary>
/// Gets the reason for a failure in the current response.
/// </summary>
public virtual string ErrorMessage { get; internal set; }
public virtual string ErrorMessage => this.CosmosException?.ToString();

/// <summary>
/// Gets the current <see cref="ResponseMessage"/> HTTP headers.
Expand All @@ -120,10 +126,7 @@ public virtual Stream Content

internal CosmosDiagnosticsContext DiagnosticsContext { get; }

/// <summary>
/// Gets the internal error object.
/// </summary>
internal virtual Error Error { get; set; }
internal CosmosException CosmosException { get; }
j82w marked this conversation as resolved.
Show resolved Hide resolved

private bool disposed;

Expand All @@ -137,19 +140,13 @@ public virtual Stream Content
/// <summary>
/// Checks if the current <see cref="ResponseMessage"/> has a successful status code, otherwise, throws.
/// </summary>
/// <exception cref="CosmosException">An instance of <see cref="CosmosException"/> representing the error state.</exception>
/// <exception cref="Cosmos.CosmosException">An instance of <see cref="Cosmos.CosmosException"/> representing the error state.</exception>
/// <returns>The current <see cref="ResponseMessage"/>.</returns>
public virtual ResponseMessage EnsureSuccessStatusCode()
{
if (!this.IsSuccessStatusCode)
{
this.EnsureErrorMessage();
string message = $"Response status code does not indicate success: {(int)this.StatusCode} Substatus: {(int)this.Headers.SubStatusCode} Reason: ({this.ErrorMessage}).";

throw new CosmosException(
this,
message,
this.Error);
throw CosmosExceptionFactory.Create(this);
}

return this;
Expand Down Expand Up @@ -210,44 +207,5 @@ private void CheckDisposed()
throw new ObjectDisposedException(this.GetType().ToString());
}
}

private void EnsureErrorMessage()
{
if (this.Error != null
|| !string.IsNullOrEmpty(this.ErrorMessage))
{
return;
}

if (this.content != null
&& this.content.CanRead)
{
try
{
Error error = Documents.Resource.LoadFrom<Error>(this.content);
if (error != null)
{
// Error format is not consistent across modes
if (!string.IsNullOrEmpty(error.Message))
{
this.ErrorMessage = error.Message;
}
else
{
this.ErrorMessage = error.ToString();
}
}
}
catch (Newtonsoft.Json.JsonReaderException)
{
// Content is not Json
this.content.Position = 0;
using (StreamReader streamReader = new StreamReader(this.content))
{
this.ErrorMessage = streamReader.ReadToEnd();
}
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -401,12 +401,7 @@ protected async Task<TryCatch> TryInitializeAsync(
if (failureResponse.HasValue)
{
return TryCatch.FromException(
new CosmosException(
statusCode: failureResponse.Value.StatusCode,
subStatusCode: (int)failureResponse.Value.SubStatusCode.GetValueOrDefault(0),
message: failureResponse.Value.ErrorMessage,
activityId: failureResponse.Value.ActivityId,
requestCharge: failureResponse.Value.RequestCharge));
failureResponse.Value.CosmosException);
}

if (!movedToNextPage)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ namespace Microsoft.Azure.Cosmos.Query.Core.ExecutionContext.ItemProducers
using Microsoft.Azure.Cosmos.Query.Core.Collections;
using Microsoft.Azure.Cosmos.Query.Core.Metrics;
using Microsoft.Azure.Cosmos.Query.Core.QueryClient;
using Microsoft.Azure.Cosmos.Resource.CosmosExceptions;
using Microsoft.Azure.Documents;
using PartitionKeyRange = Documents.PartitionKeyRange;
using PartitionKeyRangeIdentity = Documents.PartitionKeyRangeIdentity;

Expand Down Expand Up @@ -289,7 +291,7 @@ public async Task BufferMoreDocumentsAsync(CancellationToken token)
feedResponse = QueryResponseCore.CreateFailure(
statusCode: (System.Net.HttpStatusCode)429,
subStatusCodes: null,
errorMessage: "Request Rate Too Large",
cosmosException: new CosmosThrottledException("Request Rate Too Large"),
requestCharge: 0,
activityId: QueryResponseCore.EmptyGuidString,
diagnostics: QueryResponseCore.EmptyDiagnostics);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -641,12 +641,7 @@ private async Task<TryCatch> TryFilterAsync(
if (failureResponse.HasValue)
{
return TryCatch.FromException(
new CosmosException(
statusCode: failureResponse.Value.StatusCode,
subStatusCode: (int)failureResponse.Value.SubStatusCode.GetValueOrDefault(0),
message: failureResponse.Value.ErrorMessage,
activityId: failureResponse.Value.ActivityId,
requestCharge: 0));
failureResponse.Value.CosmosException);
}

break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ public ExceptionWithStackTraceException(

public override string StackTrace => this.stackTrace.ToString();

public StackTrace GetStackTrace()
{
return this.stackTrace;
}

public override string ToString()
{
// core2.x does not honor the StackTrace property in .ToString() (it uses the private internal stack trace).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ private QueryResponseCore(
long responseLengthBytes,
string disallowContinuationTokenMessage,
string continuationToken,
string errorMessage,
CosmosException cosmosException,
SubStatusCodes? subStatusCode)
{
this.IsSuccess = isSuccess;
Expand All @@ -47,13 +47,13 @@ private QueryResponseCore(
this.RequestCharge = requestCharge;
this.DisallowContinuationTokenMessage = disallowContinuationTokenMessage;
this.ContinuationToken = continuationToken;
this.ErrorMessage = errorMessage;
this.CosmosException = cosmosException;
this.SubStatusCode = subStatusCode;
}

internal IReadOnlyList<CosmosElement> CosmosElements { get; }

internal string ErrorMessage { get; }
internal CosmosException CosmosException { get; }

internal SubStatusCodes? SubStatusCode { get; }

Expand Down Expand Up @@ -92,7 +92,7 @@ internal static QueryResponseCore CreateSuccess(
responseLengthBytes: responseLengthBytes,
disallowContinuationTokenMessage: disallowContinuationTokenMessage,
continuationToken: continuationToken,
errorMessage: null,
cosmosException: null,
subStatusCode: null);

return cosmosQueryResponse;
Expand All @@ -101,7 +101,7 @@ internal static QueryResponseCore CreateSuccess(
internal static QueryResponseCore CreateFailure(
HttpStatusCode statusCode,
SubStatusCodes? subStatusCodes,
string errorMessage,
CosmosException cosmosException,
double requestCharge,
string activityId,
IReadOnlyCollection<QueryPageDiagnostics> diagnostics)
Expand All @@ -116,7 +116,7 @@ internal static QueryResponseCore CreateFailure(
responseLengthBytes: 0,
disallowContinuationTokenMessage: null,
continuationToken: null,
errorMessage: errorMessage,
cosmosException: cosmosException,
subStatusCode: subStatusCodes);

return cosmosQueryResponse;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ namespace Microsoft.Azure.Cosmos.Query.Core.QueryPlan
using System.Threading.Tasks;
using Microsoft.Azure.Cosmos.Query.Core.Monads;
using Microsoft.Azure.Cosmos.Query.Core.QueryClient;
using Microsoft.Azure.Cosmos.Resource.CosmosExceptions;
using OperationType = Documents.OperationType;
using PartitionKeyDefinition = Documents.PartitionKeyDefinition;
using ResourceType = Documents.ResourceType;
Expand Down Expand Up @@ -62,9 +63,22 @@ public static async Task<PartitionedQueryExecutionInfo> GetQueryPlanWithServiceI

if (!tryGetQueryPlan.Succeeded)
{
throw new CosmosException(
System.Net.HttpStatusCode.BadRequest,
tryGetQueryPlan.Exception.ToString());
if (tryGetQueryPlan.Exception is CosmosException)
{
throw tryGetQueryPlan.Exception;
}

throw CosmosExceptionFactory.Create(
statusCode: System.Net.HttpStatusCode.BadRequest,
subStatusCode: default,
message: tryGetQueryPlan.Exception.ToString(),
stackTrace: new System.Diagnostics.StackTrace(tryGetQueryPlan.Exception),
activityId: default,
requestCharge: default,
retryAfter: default,
headers: default,
diagnosticsContext: default,
innerException: default);
}

return tryGetQueryPlan.Result;
Expand Down
Loading