Skip to content

Commit

Permalink
Merge pull request #27 from Worth-NL/feature/Sentry_Logging
Browse files Browse the repository at this point in the history
Feature/sentry logging
  • Loading branch information
Thomas-M-Krystyan authored May 6, 2024
2 parents 670276f + 6e014f9 commit 71eef0d
Show file tree
Hide file tree
Showing 23 changed files with 211 additions and 158 deletions.
2 changes: 1 addition & 1 deletion Documentation/OMC - Documentation.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# OMC Documentation

v.1.6.9
v.1.7.0

© 2024, Worth Systems.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public struct CitizenData : IJsonSerializable
[JsonInclude]
[JsonPropertyName("geslachtsaanduiding")]
[JsonPropertyOrder(3)]
public string GenderCode { get; internal set; } = string.Empty;
public string GenderCode { get; internal set; } = string.Empty; // TODO: Remove Gender Code in the future

/// <inheritdoc cref="DistributionChannels"/>
[JsonInclude]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ public struct Case : IJsonSerializable
[JsonPropertyOrder(2)]
public string Identification { get; internal set; } = string.Empty;

// TODO: "zaaktype" might be used as well

/// <summary>
/// Initializes a new instance of the <see cref="Case"/> struct.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ public struct CaseStatusType : IJsonSerializable
[JsonPropertyOrder(1)]
public bool IsFinalStatus { get; internal set; }

// TODO: "informeren" JSON property might be used in the future

/// <summary>
/// Initializes a new instance of the <see cref="CaseStatusType"/> struct.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,11 @@ protected BaseApiStandardResponseBody(HttpStatusCode statusCode, string statusDe
this.StatusCode = statusCode;
this.StatusDescription = statusDescription;
}

/// <inheritdoc cref="object.ToString()"/>
public override string ToString()
{
return StatusDescription;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,11 @@ protected BaseEnhancedStandardResponseBody(HttpStatusCode statusCode, string sta
{
this.Details = details;
}

/// <inheritdoc cref="object.ToString()"/>
public sealed override string ToString()
{
return $"{StatusDescription} | {Details.Message}";
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,11 @@ protected BaseSimpleStandardResponseBody(HttpStatusCode statusCode, string statu
{
this.Details = details;
}

/// <inheritdoc cref="object.ToString()"/>
public sealed override string ToString()
{
return $"{StatusDescription} | {Details.Message}";
}
}
}
2 changes: 1 addition & 1 deletion EventsHandler/Api/EventsHandler/Constants/DefaultValues.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ internal static class ApiController
{
internal const string Route = "[controller]";

internal const string Version = "1.69";
internal const string Version = "1.70";
}
#endregion

Expand Down
91 changes: 61 additions & 30 deletions EventsHandler/Api/EventsHandler/Controllers/Base/OmcController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,56 +19,87 @@ namespace EventsHandler.Controllers.Base
[ProducesResponseType(StatusCodes.Status401Unauthorized, Type = typeof(string))] // REASON: JWT Token is invalid or expired
public abstract class OmcController : Controller
{
private readonly ILogger _logger;
// ReSharper disable MemberCanBeMadeStatic.Global

/// <summary>
/// Initializes a new instance of the <see cref="OmcController"/> class.
/// Logs the message and returns the API response.
/// </summary>
/// <param name="logger">The generic logger to be used.</param>
protected OmcController(ILogger logger)
/// <param name="logLevel">The severity of the log.</param>
/// <param name="objectResult">The result to be analyzed before logging it.</param>
protected ObjectResult LogApiResponse(LogLevel logLevel, ObjectResult objectResult)
{
this._logger = logger;
LogMessage(logLevel, DetermineResultMessage(objectResult));

return objectResult;
}

/// <summary>
/// Logs and returns the API response.
/// Logs the message.
/// </summary>
protected ObjectResult LogAndReturnApiResponse(LogLevel logLevel, ObjectResult objectResult)
/// <param name="logLevel">The severity of the log.</param>
/// <param name="logMessage">The message to be logged.</param>
protected void LogApiResponse(LogLevel logLevel, string logMessage)
{
// Determine log message based on the received ObjectResult
string logMessage = objectResult.Value switch
{
// Description with message
BaseEnhancedStandardResponseBody detailedResponseBody
=> $"{detailedResponseBody.StatusDescription} | {detailedResponseBody.Details.Message}",

// Only description
BaseApiStandardResponseBody shortResponseBody
=> shortResponseBody.StatusDescription,

// Unknown object result
_ => $"Not standardized API response | {objectResult.StatusCode} | {nameof(objectResult.Value)}"
};
LogMessage(logLevel, logMessage);
}

LogApiResponse(logLevel, logMessage);
/// <summary>
/// Logs the exception and returns the API response.
/// </summary>
/// <param name="exception">The exception to be passed.</param>
/// <param name="objectResult">The result to be analyzed before logging it.</param>
protected ObjectResult LogApiResponse(Exception exception, ObjectResult objectResult)
{
LogException(exception);

return objectResult;
}

// ReSharper enable MemberCanBeMadeStatic.Global

/// <summary>
/// Logs the API response.
/// </summary>
protected void LogApiResponse(LogLevel logLevel, string logMessage)
#region Sentry logging
private static readonly Dictionary<LogLevel, SentryLevel> s_logMapping = new()
{
{ LogLevel.Trace, SentryLevel.Debug },
{ LogLevel.Debug, SentryLevel.Debug },
{ LogLevel.Information, SentryLevel.Info },
{ LogLevel.Warning, SentryLevel.Warning },
{ LogLevel.Error, SentryLevel.Error },
{ LogLevel.Critical, SentryLevel.Fatal }
};

/// <inheritdoc cref="SentrySdk.CaptureMessage(string, SentryLevel)"/>
private static void LogMessage(LogLevel logLevel, string logMessage)
{
this._logger.Log(logLevel, $"OMC: {logMessage} | {DateTime.Now}");
_ = SentrySdk.CaptureMessage($"OMC | {logMessage}", s_logMapping[logLevel]);
}

/// <inheritdoc cref="SentrySdk.CaptureException(Exception)"/>
private static void LogException(Exception exception)
{
_ = SentrySdk.CaptureException(exception);
}
#endregion

#region Helper methods
/// <summary>
/// Logs the API response.
/// Determines the log message based on the received <see cref="ObjectResult"/>.
/// </summary>
protected void LogApiResponse(LogLevel logLevel, ObjectResult objectResult)
private static string DetermineResultMessage(ObjectResult objectResult)
{
_ = LogAndReturnApiResponse(logLevel, objectResult);
return objectResult.Value switch
{
// Description with message
BaseEnhancedStandardResponseBody enhancedResponse => enhancedResponse.ToString(),
BaseSimpleStandardResponseBody simpleResponse => simpleResponse.ToString(),

// Only description
BaseApiStandardResponseBody baseResponse => baseResponse.ToString(),

// Unknown object result
_ => $"Not standardized API response | {objectResult.StatusCode} | {nameof(objectResult.Value)}"
};
}
#endregion
}
}
14 changes: 7 additions & 7 deletions EventsHandler/Api/EventsHandler/Controllers/EventsController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,11 @@ private static readonly (ProcessingResult, string) s_failedResult =
/// <param name="validator">The input validating service.</param>
/// <param name="processor">The input processing service (business logic).</param>
/// <param name="responder">The output standardization service (UX/UI).</param>
/// <param name="logger">The logging service registering API events.</param>
public EventsController(
ISerializationService serializer,
IValidationService<NotificationEvent> validator,
IProcessingService<NotificationEvent> processor,
IRespondingService<NotificationEvent> responder,
ILogger<EventsController> logger)
: base(logger)
IRespondingService<NotificationEvent> responder)
{
this._serializer = serializer;
this._validator = validator;
Expand Down Expand Up @@ -89,15 +86,16 @@ public async Task<IActionResult> ListenAsync([Required, FromBody] object json)
return this._validator.Validate(ref notification) is HealthCheck.OK_Valid
or HealthCheck.OK_Inconsistent
// Try to process received notification
? LogAndReturnApiResponse(LogLevel.Information,
? LogApiResponse(LogLevel.Information,
this._responder.Get_Processing_Status_ActionResult(await this._processor.ProcessAsync(notification), notification.Details))

// Notification cannot be processed
: LogAndReturnApiResponse(LogLevel.Error,
: LogApiResponse(LogLevel.Error,
this._responder.Get_Processing_Status_ActionResult(s_failedResult, notification.Details));
}
catch (Exception exception)
{
return LogAndReturnApiResponse(LogLevel.Critical,
return LogApiResponse(exception,
this._responder.Get_Exception_ActionResult(exception));
}
}
Expand All @@ -115,6 +113,8 @@ or HealthCheck.OK_Inconsistent
[ProducesResponseType(StatusCodes.Status200OK)]
public IActionResult Version()
{
LogApiResponse(LogLevel.Trace, Resources.Events_ApiVersionRequested);

return Ok(DefaultValues.ApiController.Version);
}
}
Expand Down
40 changes: 19 additions & 21 deletions EventsHandler/Api/EventsHandler/Controllers/NotifyController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,10 @@ public sealed class NotifyController : OmcController
/// <param name="serializer">The input de(serializing) service.</param>
/// <param name="responder">The output standardization service (UX/UI).</param>
/// <param name="telemetry">The telemetry service registering API events.</param>
/// <param name="logger">The logging service registering API events.</param>
public NotifyController(
ISerializationService serializer,
IRespondingService<ProcessingResult, string> responder,
ITelemetryService telemetry,
ILogger<NotifyController> logger)
: base(logger)
ITelemetryService telemetry)
{
this._serializer = serializer;
this._responder = responder;
Expand Down Expand Up @@ -76,28 +73,28 @@ public async Task<IActionResult> ConfirmAsync([Required, FromBody] object json)
// Deserialize received JSON payload
callback = this._serializer.Deserialize<DeliveryReceipt>(json);

if (callback.Status is not (DeliveryStatus.PermanentFailure or
DeliveryStatus.TemporaryFailure or
DeliveryStatus.TechnicalFailure))
{
return LogAndReturnApiResponse(LogLevel.Information,
this._responder.Get_Processing_Status_ActionResult(ProcessingResult.Success, callbackDetails = GetCallbackDetails(callback)));
}
return callback.Status is not (DeliveryStatus.PermanentFailure or
DeliveryStatus.TemporaryFailure or
DeliveryStatus.TechnicalFailure)
// Positive status was returned by Notify NL
? LogApiResponse(LogLevel.Information,
this._responder.Get_Processing_Status_ActionResult(ProcessingResult.Success, callbackDetails = GetCallbackDetails(callback)))

return LogAndReturnApiResponse(LogLevel.Error,
this._responder.Get_Processing_Status_ActionResult(ProcessingResult.Failure, callbackDetails = GetCallbackDetails(callback)));
// Failure status was returned by Notify NL
: LogApiResponse(LogLevel.Error,
this._responder.Get_Processing_Status_ActionResult(ProcessingResult.Failure, callbackDetails = GetCallbackDetails(callback)));
}
catch (Exception exception)
{
// NOTE: If callback.Id == Guid.Empty then to be suspected is exception during DeliveryReceipt deserialization
// NOTE: If callback.Id == Guid.Empty then it might be suspected that exception occurred during DeliveryReceipt deserialization
callbackDetails = GetErrorDetails(callback, exception);

return LogAndReturnApiResponse(LogLevel.Critical,
return LogApiResponse(exception,
this._responder.Get_Exception_ActionResult(exception));
}
finally
{
await ReportAndLogStatusAsync(callback, callbackDetails);
await LogContactRegistrationAsync(callback, callbackDetails);
}
}

Expand All @@ -112,7 +109,7 @@ private static string GetErrorDetails(DeliveryReceipt callback, Exception except
return $"{Resources.Feedback_NotifyNL_ERROR_UnexpectedFailure} {callback.Id}: {exception.Message}.";
}

private async Task ReportAndLogStatusAsync(DeliveryReceipt callback, string callbackDetails)
private async Task LogContactRegistrationAsync(DeliveryReceipt callback, string callbackDetails)
{
if (callback.Reference != null)
{
Expand All @@ -122,13 +119,14 @@ private async Task ReportAndLogStatusAsync(DeliveryReceipt callback, string call

try
{
string result = await this._telemetry.ReportCompletionAsync(notification, notificationMethod, callbackDetails);

LogApiResponse(LogLevel.Information, result);
LogApiResponse(LogLevel.Information,
await this._telemetry.ReportCompletionAsync(notification, notificationMethod, callbackDetails));
}
catch (Exception exception)
{
LogApiResponse(LogLevel.Critical, this._responder.Get_Exception_ActionResult(exception));
// It wasn't possible to report completion because of issue with Telemetry Service
LogApiResponse(exception,
this._responder.Get_Exception_ActionResult(exception));
}
}
}
Expand Down
Loading

0 comments on commit 71eef0d

Please sign in to comment.