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

Segment logging #130

Merged
merged 17 commits into from
Apr 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions Services/ClaimService/src/appsettings.dev.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
"Microsoft": "Information"
}
},
"Hl7v2Authorization": {
"LoggableSegments": ["MSH", "ZCA", "ZCB", "ZZZ"]
},
"AllowedHosts": "*",
"PharmanetProxy": {
"Endpoint": "https://d1pnetgwy.hibc.gov.bc.ca/pnetIntegration/submitTransaction",
Expand Down
1 change: 1 addition & 0 deletions Services/ClaimService/src/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
}
},
"Hl7v2Authorization": {
"LoggableSegments": [],
"MessageConfig": [
{
"Name": "TACTDU_01_REQUEST-*",
Expand Down
3 changes: 3 additions & 0 deletions Services/ClaimService/src/appsettings.prd.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
"Microsoft": "Information"
}
},
"HL7v2Authorization": {
"LoggableSegments": ["MSH", "ZCA", "ZCB", "ZZZ"]
},
"AllowedHosts": "*",
"PharmanetProxy": {
"Endpoint": "https://pnetgwy.hibc.gov.bc.ca/pnetIntegration/submitTransaction",
Expand Down
3 changes: 3 additions & 0 deletions Services/ClaimService/src/appsettings.tr1.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
"Microsoft": "Information"
}
},
"HL7v2Authorization": {
"LoggableSegments": ["MSH", "ZCA", "ZCB", "ZZZ"]
},
"AllowedHosts": "*",
"PharmanetProxy": {
"Endpoint": "https://t1pnetgwy.hibc.gov.bc.ca/pnetIntegrationTR1/submitTransaction",
Expand Down
3 changes: 3 additions & 0 deletions Services/ClaimService/src/appsettings.vc1.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
"Microsoft": "Information"
}
},
"HL7v2Authorization": {
"LoggableSegments": ["MSH", "ZCA", "ZCB", "ZZZ"]
},
"AllowedHosts": "*",
"PharmanetProxy": {
"Endpoint": "https://t1pnetgwy.hibc.gov.bc.ca/pnetIntegrationVC1/submitTransaction",
Expand Down
3 changes: 3 additions & 0 deletions Services/ClaimService/src/appsettings.vc2.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
"Microsoft": "Information"
}
},
"HL7v2Authorization": {
"LoggableSegments": ["MSH", "ZCA", "ZCB", "ZZZ"]
},
"AllowedHosts": "*",
"PharmanetProxy": {
"Endpoint": "https://t1pnetgwy.hibc.gov.bc.ca/pnetIntegrationVC2/submitTransaction",
Expand Down
3 changes: 3 additions & 0 deletions Services/ClaimService/src/appsettings.vs1.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
"Microsoft": "Information"
}
},
"HL7v2Authorization": {
"LoggableSegments": ["MSH", "ZCA", "ZCB", "ZZZ"]
},
"AllowedHosts": "*",
"PharmanetProxy": {
"Endpoint": "https://t1pnetgwy.hibc.gov.bc.ca/pnetIntegrationVS1/submitTransaction",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
namespace Health.PharmaNet.Authorization
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

Expand Down Expand Up @@ -54,6 +55,22 @@ public Hl7v2AuthorizationHandler(ILogger<Hl7v2AuthorizationHandler> logger)
/// <returns>A context Task.</returns>
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, Hl7v2AuthorizationRequirement requirement, Message resource)
{
// Get information from the configuration about which segments to log
IList<string> loggableSegments = requirement.LoggableSegments();
string loggedMessage = "Logged HL7v2 message:";

// Extract each matching segment of the message
foreach (string segmentName in loggableSegments)
{
foreach (HL7.Dotnetcore.Segment segment in resource.Segments(segmentName))
{
loggedMessage += " [ " + segment.Value + " ] ";
}
}

// Log the extracted segments of the message
Logger.LogInformation(this.logger, loggedMessage);

// If user does not have the scope claim, get out of here
if (!context.User.HasClaim(c => c.Type == PharmanetAPIClaims.Scope))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,15 @@ public string[] ScopesNeededForMessage(HL7.Dotnetcore.Message message)
return this.GetMessageAuthorizationScope(message);
}

/// <summary>
/// Returns the list of segment names that are allowed to be logged.
/// </summary>
/// <returns>Returns an IList&lt;string&gt; of segment names, or empty array when the message was unknown/not supported.</returns>
public IList<string> LoggableSegments()
{
return this.hl7AuthConfig.Hl7v2Authorization.LoggableSegments;
}

/// <summary>
/// Checks that the message passed has all the fields.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ namespace Health.PharmaNet.Authorization.Requirements.Models
/// </summary>
public class Hl7v2Authorization
{
/// <summary>
/// Gets the list of segment fields that are allowed to be logged.
/// </summary>
[JsonPropertyName("LoggableSegments")]
public IList<string> LoggableSegments { get; } = new List<string>();

/// <summary>
/// Gets the Messages configured.
/// </summary>
Expand Down
19 changes: 18 additions & 1 deletion Services/Common/src/Controllers/ServiceBaseController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
namespace Health.PharmaNet.Controllers
{
using System;

using System.Linq;
using System.Net;
using System.Security.Claims;
using System.Threading.Tasks;
Expand Down Expand Up @@ -111,9 +113,17 @@ public class ServiceBaseController : ControllerBase
[Authorize]
protected async Task<ActionResult<DocumentReference>> PharmanetRequest()
{
Logger.LogInformation(this.logger, $"ServiceBaseController.PharmanetRequest start");

ClaimsPrincipal? user = this.HttpContext!.User;

var traceId = this.Request.Headers.TryGetValue("Kong-Request-ID", out var value) ? value.FirstOrDefault() : "";
Logger.LogInformation(this.logger, $"Trace ID: {traceId}: ServiceBaseController.PharmanetRequest. Extracted Kong-Request-ID header as the Trace ID.");

string jsonString = await this.Request.GetRawBodyStringAsync().ConfigureAwait(true);

Logger.LogInformation(this.logger, $"Trace ID: {traceId}: ServiceBaseController.PharmanetRequest: Got the body from the request.");

DocumentReference fhirRequest;
Message hl7v2Message;
try
Expand All @@ -130,6 +140,10 @@ protected async Task<ActionResult<DocumentReference>> PharmanetRequest()
return this.StatusCode((int)HttpStatusCode.BadRequest, ex.Message);
}

HL7.Dotnetcore.Segment? mshSegment = hl7v2Message.Segments("MSH").FirstOrDefault();
Logger.LogInformation(this.logger, $"Trace ID: {traceId}: ServiceBaseController.PharmanetRequest: Message MSH: {mshSegment?.Value}");

Logger.LogInformation(this.logger, $"Trace ID: {traceId}: ServiceBaseController.PharmanetRequest: Authorizing...");
AuthorizationResult authResult = await this.authorizationService.AuthorizeAsync(
user,
hl7v2Message,
Expand All @@ -138,8 +152,9 @@ protected async Task<ActionResult<DocumentReference>> PharmanetRequest()
{
return new ChallengeResult();
}
Logger.LogInformation(this.logger, $"Trace ID: {traceId}: ServiceBaseController.PharmanetRequest: Authorization completed. Submitting request...");

RequestResult<DocumentReference> response = await this.service.SubmitRequest(fhirRequest).ConfigureAwait(true);
RequestResult<DocumentReference> response = await this.service.SubmitRequest(fhirRequest, traceId + "").ConfigureAwait(true);
if (response.IsSuccessStatusCode == false)
{
Logger.LogError(this.logger, $"An Error occurred while invoking Pharmanet endpoint: {response.ErrorMessage}");
Expand All @@ -150,11 +165,13 @@ protected async Task<ActionResult<DocumentReference>> PharmanetRequest()
ContentType = "application/json",
};
}
Logger.LogInformation(this.logger, $"Trace ID: {traceId}: ServiceBaseController.PharmanetRequest: Request completed.");

DocumentReference? docRef = response.Payload;

FhirJsonSerializer serializer = new FhirJsonSerializer(new SerializerSettings() { Pretty = true });

Logger.LogInformation(this.logger, $"Trace ID: {traceId}: ServiceBaseController.PharmanetRequest end");
return new ContentResult()
{
Content = serializer.SerializeToString(docRef),
Expand Down
17 changes: 14 additions & 3 deletions Services/Common/src/Delegates/PharmanetDelegate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,16 @@ private string TrimBadCharactersInMessage(string hl7base64Message = @"")

Span<byte> span = bytes;
int i = 0;
foreach(byte aByte in span)
foreach (byte aByte in span)
{
newBytes[i] = 0x00;
if ((aByte > 0x00) && (aByte <= 0xff)) // only bytes in UTF8 range
{
newBytes[i] = aByte;
i++;
}
else {
else
{
Logger.LogInformation(this.logger, $"WORKAROUND: Removed {aByte:X4} character from HL7v2 response.");
}
}
Expand Down Expand Up @@ -96,6 +97,8 @@ public PharmanetDelegate(HttpClient client, ILogger<PharmanetDelegate> logger, I
/// <returns>A PharmanetMessage response.</returns>
public async Task<RequestResult<PharmanetMessageModel>> SubmitRequest(PharmanetMessageModel request)
{
Logger.LogInformation(this.logger, $"Transaction UUID: {request.TransactionId}: PharmanetDelegate.SubmitRequest start");

RequestResult<PharmanetMessageModel> requestResult = new RequestResult<PharmanetMessageModel>();

JsonSerializerOptions options = new JsonSerializerOptions();
Expand All @@ -108,10 +111,14 @@ public async Task<RequestResult<PharmanetMessageModel>> SubmitRequest(PharmanetM
{
Uri delegateUri = new Uri(this.pharmanetDelegateConfig.Endpoint);

Logger.LogInformation(this.logger, $"Transaction UUID: {request.TransactionId}: PharmanetDelegate.SubmitRequest: Sending message to PharmaNet...");
// This log statement logs sensitive health information - use it only for debugging in a development environment
// Logger.LogDebug(this.logger, $"PharmanetDelegate Proxy POST {delegateUri}. Payload: {jsonOutput}");

HttpResponseMessage response = await this.httpClient.PostAsync(delegateUri, content).ConfigureAwait(true);

Logger.LogInformation(this.logger, $"Transaction UUID: {request.TransactionId}: PharmanetDelegate.SubmitRequest: Received response from PharmaNet with Status Code: {response.StatusCode}.");

requestResult.IsSuccessStatusCode = response.IsSuccessStatusCode;
requestResult.StatusCode = response.StatusCode;

Expand All @@ -124,13 +131,16 @@ public async Task<RequestResult<PharmanetMessageModel>> SubmitRequest(PharmanetM
}
else
{
Logger.LogInformation(this.logger, $"Transaction UUID: {request.TransactionId}: PharmanetDelegate.SubmitRequest: Response success, extracting response content...");
string? result = await response.Content.ReadAsStringAsync().ConfigureAwait(true);
Logger.LogInformation(this.logger, $"Transaction UUID: {request.TransactionId}: PharmanetDelegate.SubmitRequest: Extracting response content. Deserializing message...");
PharmanetMessageModel? responseMessage = JsonSerializer.Deserialize<PharmanetMessageModel>(result);
Logger.LogInformation(this.logger, $"Transaction UUID: {request.TransactionId}: PharmanetDelegate.SubmitRequest: Deserialized message. Building response...");

responseMessage!.Hl7Message = TrimBadCharactersInMessage(responseMessage!.Hl7Message); // Workaround stray chars from Delegate
requestResult.Payload = responseMessage;
// This log statement does not log sensitive health information, even though it looks like it might
Logger.LogDebug(this.logger, $"PharmanetDelegate Proxy Response: {responseMessage}");
Logger.LogDebug(this.logger, $"Transaction UUID: {request.TransactionId}: PharmanetDelegate Proxy Response: {responseMessage}");
}
}
#pragma warning disable CA1031 // Do not catch general exception types
Expand All @@ -146,6 +156,7 @@ public async Task<RequestResult<PharmanetMessageModel>> SubmitRequest(PharmanetM
return requestResult;
}

Logger.LogInformation(this.logger, $"Transaction UUID: {request.TransactionId}: PharmanetDelegate.SubmitRequest end ");
return requestResult;
}
}
Expand Down
3 changes: 2 additions & 1 deletion Services/Common/src/Services/IPharmanetService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ public interface IPharmanetService
/// Submit request of type DocumentReference containing HL7v2 message to PharmaNet.
/// </summary>
/// <param name="request">An HL7 FHIR DocumentReference request containing HL7v2 payload.</param>
/// <param name="traceId">The value used to track messages from API Gateway.</param>
/// <returns>Returns a DocumentReference response.</returns>
Task<RequestResult<DocumentReference>> SubmitRequest(DocumentReference request);
Task<RequestResult<DocumentReference>> SubmitRequest(DocumentReference request, string traceId);
}
}
10 changes: 9 additions & 1 deletion Services/Common/src/Services/PharmanetService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,17 @@ public class PharmanetService : IPharmanetService
/// Submit Request to Pharmanet.
/// </summary>
/// <param name="request">The DocumentReference to be submitted.</param>
/// <param name="traceId">The value used to track messages from API Gateway.</param>
/// <returns>Returns a DocumentReference containing the response from PharmaNet.</returns>
public async Task<RequestResult<DocumentReference>> SubmitRequest(DocumentReference request)
public async Task<RequestResult<DocumentReference>> SubmitRequest(DocumentReference request, string traceId)
{
Logger.LogInformation(this.logger, $"Trace ID: {traceId}: PharmanetService.SubmitRequest start");

RequestResult<DocumentReference> response = new RequestResult<DocumentReference>();
bool base64Encode = this.configuration.GetSection(PharmanetDelegateConfig.ConfigurationSectionKey).GetValue<bool>("Base64EncodeHl7Message");
Logger.LogInformation(this.logger, $"Trace ID: {traceId}: PharmanetService.SubmitRequest: UUID exists in FHIR? {request.MasterIdentifier != null} ");
PharmanetMessageModel requestMessage = PharmanetDelegateAdapter.ToPharmanetMessageModel(request, base64Encode);
Logger.LogInformation(this.logger, $"Trace ID: {traceId}: Transaction UUID: {requestMessage.TransactionId}: PharmanetService.SubmitRequest: PharmanetMessageModel created.");

try
{
Expand All @@ -80,8 +85,10 @@ public async Task<RequestResult<DocumentReference>> SubmitRequest(DocumentRefere
// This log statement logs sensitive health information - use it only for debugging in a development environment
// this.logger.LogDebug($"Pharmanet Response: {message!.Hl7Message}");

Logger.LogInformation(this.logger, $"Transaction UUID: {requestMessage.TransactionId}: PharmanetService.SubmitRequest: Building DocumentReference response...");
ResourceReference reference = PharmanetDelegateAdapter.RelatedToDocumentReference(request);
response.Payload = PharmanetDelegateAdapter.ToDocumentReference(message!, reference);
Logger.LogInformation(this.logger, $"Transaction UUID: {requestMessage.TransactionId}: PharmanetService.SubmitRequest: DocumentReference response built.");

// This log statement does not log sensitive health information, even though it looks like it might
this.logger.LogDebug($"FHIR Response: {response!.Payload.ToString()}");
Expand All @@ -104,6 +111,7 @@ public async Task<RequestResult<DocumentReference>> SubmitRequest(DocumentRefere
response.ErrorMessage = ex.Message;
}

Logger.LogInformation(this.logger, $"Transaction UUID: {requestMessage.TransactionId}: PharmanetService.SubmitRequest end");
return response;
}
}
Expand Down
3 changes: 3 additions & 0 deletions Services/ConsentService/src/appsettings.dev.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
"Microsoft": "Information"
}
},
"HL7v2Authorization": {
"LoggableSegments": ["MSH", "ZCA", "ZCB", "ZZZ"]
},
"AllowedHosts": "*",
"PharmanetProxy": {
"Endpoint": "https://d1pnetgwy.hibc.gov.bc.ca/pnetIntegration/submitTransaction",
Expand Down
1 change: 1 addition & 0 deletions Services/ConsentService/src/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
}
},
"Hl7v2Authorization": {
"LoggableSegments": [],
"MessageConfig": [
{
"Name": "TCP_00 REQUEST-998015",
Expand Down
3 changes: 3 additions & 0 deletions Services/ConsentService/src/appsettings.prd.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
"Microsoft": "Information"
}
},
"HL7v2Authorization": {
"LoggableSegments": ["MSH", "ZCA", "ZCB", "ZZZ"]
},
"AllowedHosts": "*",
"PharmanetProxy": {
"Endpoint": "https://pnetgwy.hibc.gov.bc.ca/pnetIntegration/submitTransaction",
Expand Down
3 changes: 3 additions & 0 deletions Services/ConsentService/src/appsettings.tr1.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
"Microsoft": "Information"
}
},
"HL7v2Authorization": {
"LoggableSegments": ["MSH", "ZCA", "ZCB", "ZZZ"]
},
"AllowedHosts": "*",
"PharmanetProxy": {
"Endpoint": "https://t1pnetgwy.hibc.gov.bc.ca/pnetIntegrationTR1/submitTransaction",
Expand Down
3 changes: 3 additions & 0 deletions Services/ConsentService/src/appsettings.vc1.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
"Microsoft": "Information"
}
},
"HL7v2Authorization": {
"LoggableSegments": ["MSH", "ZCA", "ZCB", "ZZZ"]
},
"AllowedHosts": "*",
"PharmanetProxy": {
"Endpoint": "https://t1pnetgwy.hibc.gov.bc.ca/pnetIntegrationVC1/submitTransaction",
Expand Down
3 changes: 3 additions & 0 deletions Services/ConsentService/src/appsettings.vc2.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
"Microsoft": "Information"
}
},
"HL7v2Authorization": {
"LoggableSegments": ["MSH", "ZCA", "ZCB", "ZZZ"]
},
"AllowedHosts": "*",
"PharmanetProxy": {
"Endpoint": "https://t1pnetgwy.hibc.gov.bc.ca/pnetIntegrationVC2/submitTransaction",
Expand Down
3 changes: 3 additions & 0 deletions Services/ConsentService/src/appsettings.vs1.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
"Microsoft": "Information"
}
},
"HL7v2Authorization": {
"LoggableSegments": ["MSH", "ZCA", "ZCB", "ZZZ"]
},
"AllowedHosts": "*",
"PharmanetProxy": {
"Endpoint": "https://t1pnetgwy.hibc.gov.bc.ca/pnetIntegrationVS1/submitTransaction",
Expand Down
3 changes: 3 additions & 0 deletions Services/LocationService/src/appsettings.dev.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
"Microsoft": "Information"
}
},
"HL7v2Authorization": {
"LoggableSegments": ["MSH", "ZCA", "ZCB", "ZZZ"]
},
"AllowedHosts": "*",
"PharmanetProxy": {
"Endpoint": "https://d1pnetgwy.hibc.gov.bc.ca/pnetIntegration/submitTransaction",
Expand Down
1 change: 1 addition & 0 deletions Services/LocationService/src/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
}
},
"Hl7v2Authorization": {
"LoggableSegments": [],
"MessageConfig": [
{
"Name": "TIL_00_REQUEST - 1111 & 197001",
Expand Down
Loading
Loading