-
Notifications
You must be signed in to change notification settings - Fork 67
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
17 changed files
with
739 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
32 changes: 32 additions & 0 deletions
32
src/lib/Microsoft.Health.Extensions.Fhir.R4/FhirServiceValidator.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
// ------------------------------------------------------------------------------------------------- | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. | ||
// ------------------------------------------------------------------------------------------------- | ||
|
||
using System; | ||
using EnsureThat; | ||
using Hl7.Fhir.Rest; | ||
using Microsoft.Health.Extensions.Fhir.Telemetry.Exceptions; | ||
using Microsoft.Health.Logging.Telemetry; | ||
|
||
namespace Microsoft.Health.Extensions.Fhir | ||
{ | ||
public static class FhirServiceValidator | ||
{ | ||
public static bool ValidateFhirService(FhirClient client, ITelemetryLogger logger) | ||
{ | ||
EnsureArg.IsNotNull(client, nameof(client)); | ||
|
||
try | ||
{ | ||
client.CapabilityStatement(SummaryType.True); | ||
return true; | ||
} | ||
catch (Exception exception) | ||
{ | ||
FhirServiceExceptionProcessor.ProcessException(exception, logger); | ||
return false; | ||
} | ||
} | ||
} | ||
} |
40 changes: 40 additions & 0 deletions
40
src/lib/Microsoft.Health.Extensions.Fhir.R4/Telemetry/Exceptions/FhirServiceErrorCode.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
// ------------------------------------------------------------------------------------------------- | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. | ||
// ------------------------------------------------------------------------------------------------- | ||
|
||
namespace Microsoft.Health.Extensions.Fhir.Telemetry.Exceptions | ||
{ | ||
public enum FhirServiceErrorCode | ||
{ | ||
/// <summary> | ||
/// Error code that categorizes invalid configurations (e.g. invalid FHIR service URL) | ||
/// </summary> | ||
ConfigurationError, | ||
|
||
/// <summary> | ||
/// Error code that categorizes authorization errors (e.g. missing role with permission to write FHIR data) | ||
/// </summary> | ||
AuthorizationError, | ||
|
||
/// <summary> | ||
/// Error code that categorizes invalid arguments (i.e. exceptions encountered of type ArgumentException), which may occur when FhirClient's endpoint is validated | ||
/// </summary> | ||
ArgumentError, | ||
|
||
/// <summary> | ||
/// Error code that categorizes HTTP request exceptions (i.e. exceptions encountered of type HttpRequestException) | ||
/// </summary> | ||
HttpRequestError, | ||
|
||
/// <summary> | ||
/// Error code that categorizes MSAL.NET exceptions (i.e. exceptions encountered of type MsalServiceException) | ||
/// </summary> | ||
MsalServiceError, | ||
|
||
/// <summary> | ||
/// Error code that categorizes all other generic exceptions | ||
/// </summary> | ||
GeneralError, | ||
} | ||
} |
105 changes: 105 additions & 0 deletions
105
...Microsoft.Health.Extensions.Fhir.R4/Telemetry/Exceptions/FhirServiceExceptionProcessor.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
// ------------------------------------------------------------------------------------------------- | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. | ||
// ------------------------------------------------------------------------------------------------- | ||
|
||
using System; | ||
using System.Net; | ||
using System.Net.Http; | ||
using EnsureThat; | ||
using Hl7.Fhir.Rest; | ||
using Microsoft.Health.Common.Telemetry; | ||
using Microsoft.Health.Extensions.Fhir.Resources; | ||
using Microsoft.Health.Extensions.Fhir.Telemetry.Metrics; | ||
using Microsoft.Health.Logging.Telemetry; | ||
using Microsoft.Identity.Client; | ||
|
||
namespace Microsoft.Health.Extensions.Fhir.Telemetry.Exceptions | ||
{ | ||
public static class FhirServiceExceptionProcessor | ||
{ | ||
private static readonly IExceptionTelemetryProcessor _exceptionTelemetryProcessor = new ExceptionTelemetryProcessor(); | ||
|
||
public static void ProcessException(Exception exception, ITelemetryLogger logger) | ||
{ | ||
EnsureArg.IsNotNull(logger, nameof(logger)); | ||
|
||
var (customException, errorName) = CustomizeException(exception); | ||
|
||
logger.LogError(customException); | ||
|
||
string exceptionName = customException.Equals(exception) ? $"{ErrorType.FHIRServiceError}{errorName}" : customException.GetType().Name; | ||
_exceptionTelemetryProcessor.LogExceptionMetric(customException, logger, FhirClientMetrics.HandledException(exceptionName, ErrorSeverity.Critical)); | ||
} | ||
|
||
public static (Exception customException, string errorName) CustomizeException(Exception exception) | ||
{ | ||
EnsureArg.IsNotNull(exception, nameof(exception)); | ||
|
||
string message; | ||
string errorName; | ||
|
||
switch (exception) | ||
{ | ||
case FhirOperationException _: | ||
var status = ((FhirOperationException)exception).Status; | ||
switch (status) | ||
{ | ||
case HttpStatusCode.Forbidden: | ||
message = FhirResources.FhirServiceAccessForbidden; | ||
string helpLink = "https://docs.microsoft.com/azure/healthcare-apis/iot/deploy-iot-connector-in-azure#accessing-the-iot-connector-from-the-fhir-service"; | ||
errorName = nameof(FhirServiceErrorCode.AuthorizationError); | ||
return (new UnauthorizedAccessFhirServiceException(message, exception, helpLink, errorName), errorName); | ||
case HttpStatusCode.NotFound: | ||
message = FhirResources.FhirServiceNotFound; | ||
errorName = nameof(FhirServiceErrorCode.ConfigurationError); | ||
return (new InvalidFhirServiceException(message, exception, errorName), errorName); | ||
default: | ||
return (exception, status.ToString()); | ||
} | ||
|
||
case ArgumentException _: | ||
var paramName = ((ArgumentException)exception).ParamName; | ||
if (paramName.Contains("endpoint", StringComparison.OrdinalIgnoreCase)) | ||
{ | ||
message = FhirResources.FhirServiceEndpointInvalid; | ||
errorName = nameof(FhirServiceErrorCode.ConfigurationError); | ||
return (new InvalidFhirServiceException(message, exception, errorName), errorName); | ||
} | ||
|
||
return (exception, $"{FhirServiceErrorCode.ArgumentError}{paramName}"); | ||
|
||
case UriFormatException _: | ||
message = FhirResources.FhirServiceUriFormatInvalid; | ||
errorName = nameof(FhirServiceErrorCode.ConfigurationError); | ||
return (new InvalidFhirServiceException(message, exception, errorName), errorName); | ||
|
||
case HttpRequestException _: | ||
// TODO: In .NET 5 and later, check HttpRequestException's StatusCode property instead of the Message property | ||
if (exception.Message.Contains(FhirResources.HttpRequestErrorNotKnown, StringComparison.CurrentCultureIgnoreCase)) | ||
{ | ||
message = FhirResources.FhirServiceHttpRequestError; | ||
errorName = nameof(FhirServiceErrorCode.ConfigurationError); | ||
return (new InvalidFhirServiceException(message, exception, errorName), errorName); | ||
} | ||
|
||
return (exception, nameof(FhirServiceErrorCode.HttpRequestError)); | ||
|
||
case MsalServiceException _: | ||
var errorCode = ((MsalServiceException)exception).ErrorCode; | ||
if (string.Equals(errorCode, "invalid_resource", StringComparison.OrdinalIgnoreCase) | ||
|| string.Equals(errorCode, "invalid_scope", StringComparison.OrdinalIgnoreCase)) | ||
{ | ||
message = FhirResources.FhirServiceMsalServiceError; | ||
errorName = nameof(FhirServiceErrorCode.ConfigurationError); | ||
return (new InvalidFhirServiceException(message, exception, errorName), errorName); | ||
} | ||
|
||
return (exception, $"{FhirServiceErrorCode.MsalServiceError}{errorCode}"); | ||
|
||
default: | ||
return (exception, nameof(FhirServiceErrorCode.GeneralError)); | ||
} | ||
} | ||
} | ||
} |
48 changes: 48 additions & 0 deletions
48
...b/Microsoft.Health.Extensions.Fhir.R4/Telemetry/Exceptions/InvalidFhirServiceException.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
// ------------------------------------------------------------------------------------------------- | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. | ||
// ------------------------------------------------------------------------------------------------- | ||
|
||
using System; | ||
using Microsoft.Health.Common.Telemetry; | ||
using Microsoft.Health.Common.Telemetry.Exceptions; | ||
|
||
namespace Microsoft.Health.Extensions.Fhir.Telemetry.Exceptions | ||
{ | ||
public sealed class InvalidFhirServiceException : IomtTelemetryFormattableException | ||
{ | ||
private static readonly string _errorType = ErrorType.FHIRServiceError; | ||
|
||
public InvalidFhirServiceException() | ||
{ | ||
} | ||
|
||
public InvalidFhirServiceException(string message) | ||
: base(message) | ||
{ | ||
} | ||
|
||
public InvalidFhirServiceException(string message, Exception innerException) | ||
: base(message, innerException) | ||
{ | ||
} | ||
|
||
public InvalidFhirServiceException( | ||
string message, | ||
Exception innerException, | ||
string errorName) | ||
: base( | ||
message, | ||
innerException, | ||
name: $"{_errorType}{errorName}", | ||
operation: ConnectorOperation.FHIRConversion) | ||
{ | ||
} | ||
|
||
public override string ErrType => _errorType; | ||
|
||
public override string ErrSeverity => ErrorSeverity.Critical; | ||
|
||
public override string ErrSource => nameof(ErrorSource.User); | ||
} | ||
} |
Oops, something went wrong.