Skip to content

Commit 65d46f6

Browse files
committed
removed PII in CW; nhs_number (only) to Splunk
1 parent f737a78 commit 65d46f6

File tree

2 files changed

+136
-6
lines changed

2 files changed

+136
-6
lines changed

backend/src/log_structure.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@ def _log_data_from_body(event) -> dict:
3333
log_data["local_id"] = local_id
3434
except Exception:
3535
pass
36+
try:
37+
patient_data = [item for item in imms.get("contained") if item.get("resourceType") == "Patient"]
38+
nhs_number = patient_data[0]["identifier"][0]["value"]
39+
log_data["nhs_number"] = nhs_number
40+
except Exception:
41+
pass
3642
return log_data
3743

3844

@@ -42,7 +48,6 @@ def function_info(func):
4248
@wraps(func)
4349
def wrapper(*args, **kwargs):
4450
event = args[0] if args else {}
45-
logger.info(f"Event: {event}")
4651
headers = event.get("headers", {})
4752
correlation_id = headers.get("X-Correlation-ID", "X-Correlation-ID not passed")
4853
request_id = headers.get("X-Request-ID", "X-Request-ID not passed")
@@ -64,7 +69,6 @@ def wrapper(*args, **kwargs):
6469
start = time.time()
6570
try:
6671
result = func(*args, **kwargs)
67-
logger.info(f"Result:{result}")
6872
end = time.time()
6973
log_data["time_taken"] = f"{round(end - start, 5)}s"
7074
log_data.update(_log_data_from_body(event))

backend/tests/test_log_structure_wrapper.py

Lines changed: 130 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ def test_successful_execution(self, mock_logger, mock_firehose_logger):
4141
},
4242
'path': test_actual_path,
4343
'requestContext': {'resourcePath': test_resource_path},
44-
'body': "{\"identifier\": [{\"system\": \"http://test\", \"value\": \"12345\"}], \"protocolApplied\": [{\"targetDisease\": [{\"coding\": [{\"system\": \"http://snomed.info/sct\", \"code\": \"840539006\", \"display\": \"Disease caused by severe acute respiratory syndrome coronavirus 2\"}]}]}]}"
44+
'body': "{\"identifier\": [{\"system\": \"http://test\", \"value\": \"12345\"}], \"contained\": [{\"resourceType\": \"Patient\", \"id\": \"Pat1\", \"identifier\": [{\"system\": \"https://fhir.nhs.uk/Id/nhs-number\", \"value\": \"9693632109\"}]}], \"protocolApplied\": [{\"targetDisease\": [{\"coding\": [{\"system\": \"http://snomed.info/sct\", \"code\": \"840539006\", \"display\": \"Disease caused by severe acute respiratory syndrome coronavirus 2\"}]}]}]}"
4545
}
4646

4747
# Act
@@ -64,6 +64,7 @@ def test_successful_execution(self, mock_logger, mock_firehose_logger):
6464
self.assertEqual(logged_info['resource_path'], test_resource_path)
6565
self.assertEqual(logged_info['local_id'], '12345^http://test')
6666
self.assertEqual(logged_info['vaccine_type'], 'FLU')
67+
self.assertEqual(logged_info['nhs_number'], '9693632109')
6768

6869
def test_exception_handling(self, mock_logger, mock_firehose_logger):
6970
# Arrange
@@ -86,7 +87,7 @@ def test_exception_handling(self, mock_logger, mock_firehose_logger):
8687
'SupplierSystem': test_supplier
8788
},
8889
'path': test_actual_path, 'requestContext': {'resourcePath': test_resource_path},
89-
'body': "{\"identifier\": [{\"system\": \"http://test\", \"value\": \"12345\"}], \"protocolApplied\": [{\"targetDisease\": [{\"coding\": [{\"system\": \"http://snomed.info/sct\", \"code\": \"840539006\", \"display\": \"Disease caused by severe acute respiratory syndrome coronavirus 2\"}]}]}]}"}
90+
'body': "{\"identifier\": [{\"system\": \"http://test\", \"value\": \"12345\"}], \"contained\": [{\"resourceType\": \"Patient\", \"id\": \"Pat1\", \"identifier\": [{\"system\": \"https://fhir.nhs.uk/Id/nhs-number\", \"value\": \"9693632109\"}]}], \"protocolApplied\": [{\"targetDisease\": [{\"coding\": [{\"system\": \"http://snomed.info/sct\", \"code\": \"840539006\", \"display\": \"Disease caused by severe acute respiratory syndrome coronavirus 2\"}]}]}]}"}
9091

9192
context = {}
9293
decorated_function_raises(event, context)
@@ -108,6 +109,7 @@ def test_exception_handling(self, mock_logger, mock_firehose_logger):
108109
self.assertEqual(logged_info['error'], str(ValueError("Test error")))
109110
self.assertEqual(logged_info['local_id'], '12345^http://test')
110111
self.assertEqual(logged_info['vaccine_type'], 'FLU')
112+
self.assertEqual(logged_info['nhs_number'], '9693632109')
111113

112114
def test_body_missing(self, mock_logger, mock_firehose_logger):
113115
# Arrange
@@ -142,6 +144,7 @@ def test_body_missing(self, mock_logger, mock_firehose_logger):
142144
self.assertEqual(logged_info['resource_path'], test_resource_path)
143145
self.assertNotIn('local_id', logged_info)
144146
self.assertNotIn('vaccine_type', logged_info)
147+
self.assertNotIn('nhs_number', logged_info)
145148

146149
def test_body_not_json(self, mock_logger, mock_firehose_logger):
147150
# Arrange
@@ -178,6 +181,7 @@ def test_body_not_json(self, mock_logger, mock_firehose_logger):
178181
self.assertEqual(logged_info['resource_path'], test_resource_path)
179182
self.assertNotIn('local_id', logged_info)
180183
self.assertNotIn('vaccine_type', logged_info)
184+
self.assertNotIn('nhs_number', logged_info)
181185

182186
def test_body_invalid_identifier(self, mock_logger, mock_firehose_logger):
183187
# Arrange
@@ -200,7 +204,7 @@ def test_body_invalid_identifier(self, mock_logger, mock_firehose_logger):
200204
'SupplierSystem': test_supplier
201205
},
202206
'path': test_actual_path, 'requestContext': {'resourcePath': test_resource_path},
203-
'body': "{\"identifier\": [], \"protocolApplied\": [{\"targetDisease\": [{\"coding\": [{\"system\": \"http://snomed.info/sct\", \"code\": \"840539006\", \"display\": \"Disease caused by severe acute respiratory syndrome coronavirus 2\"}]}]}]}"}
207+
'body': "{\"identifier\": [], \"contained\": [{\"resourceType\": \"Patient\", \"id\": \"Pat1\", \"identifier\": [{\"system\": \"https://fhir.nhs.uk/Id/nhs-number\", \"value\": \"9693632109\"}]}], \"protocolApplied\": [{\"targetDisease\": [{\"coding\": [{\"system\": \"http://snomed.info/sct\", \"code\": \"840539006\", \"display\": \"Disease caused by severe acute respiratory syndrome coronavirus 2\"}]}]}]}"}
204208

205209
context = {}
206210
decorated_function_raises(event, context)
@@ -216,6 +220,7 @@ def test_body_invalid_identifier(self, mock_logger, mock_firehose_logger):
216220
self.assertEqual(logged_info['resource_path'], test_resource_path)
217221
self.assertNotIn('local_id', logged_info)
218222
self.assertEqual(logged_info['vaccine_type'], 'FLU')
223+
self.assertEqual(logged_info['nhs_number'], '9693632109')
219224

220225
def test_body_invalid_protocol_applied(self, mock_logger, mock_firehose_logger):
221226
# Arrange
@@ -238,7 +243,7 @@ def test_body_invalid_protocol_applied(self, mock_logger, mock_firehose_logger):
238243
'SupplierSystem': test_supplier
239244
},
240245
'path': test_actual_path, 'requestContext': {'resourcePath': test_resource_path},
241-
'body': "{\"identifier\": [{\"system\": \"http://test\", \"value\": \"12345\"}], \"protocolApplied\": []}"}
246+
'body': "{\"identifier\": [{\"system\": \"http://test\", \"value\": \"12345\"}], \"contained\": [{\"resourceType\": \"Patient\", \"id\": \"Pat1\", \"identifier\": [{\"system\": \"https://fhir.nhs.uk/Id/nhs-number\", \"value\": \"9693632109\"}]}], \"protocolApplied\": []}"}
242247

243248
context = {}
244249
decorated_function_raises(event, context)
@@ -254,3 +259,124 @@ def test_body_invalid_protocol_applied(self, mock_logger, mock_firehose_logger):
254259
self.assertEqual(logged_info['resource_path'], test_resource_path)
255260
self.assertEqual(logged_info['local_id'], '12345^http://test')
256261
self.assertNotIn('vaccine_type', logged_info)
262+
self.assertEqual(logged_info['nhs_number'], '9693632109')
263+
264+
def test_contained_invalid(self, mock_logger, mock_firehose_logger):
265+
# Arrange
266+
test_correlation = "failed_test_correlation_contained_invalid"
267+
test_request = "failed_test_request_contained_invalid"
268+
test_supplier = "failed_test_supplier_contained_invalid"
269+
test_actual_path = "/failed_test_contained_invalid"
270+
test_resource_path = "/failed_test_contained_invalid"
271+
272+
self.mock_redis_client.hget.return_value = "FLU"
273+
274+
wrapped_function = function_info(self.mock_success_function)
275+
event = {
276+
'headers': {
277+
'X-Correlation-ID': test_correlation,
278+
'X-Request-ID': test_request,
279+
'SupplierSystem': test_supplier
280+
},
281+
'path': test_actual_path,
282+
'requestContext': {'resourcePath': test_resource_path},
283+
'body': "{\"identifier\": [{\"system\": \"http://test\", \"value\": \"12345\"}], \"contained\": \"invalid\", \"protocolApplied\": [{\"targetDisease\": [{\"coding\": [{\"system\": \"http://snomed.info/sct\", \"code\": \"840539006\", \"display\": \"Disease caused by severe acute respiratory syndrome coronavirus 2\"}]}]}]}"
284+
}
285+
286+
# Act
287+
result = wrapped_function(event, {})
288+
289+
# Assert
290+
args, kwargs = mock_logger.info.call_args
291+
logged_info = json.loads(args[0])
292+
293+
self.assertIn('function_name', logged_info)
294+
self.assertIn('time_taken', logged_info)
295+
self.assertEqual(logged_info['X-Correlation-ID'], test_correlation)
296+
self.assertEqual(logged_info['X-Request-ID'], test_request)
297+
self.assertEqual(logged_info['supplier'], test_supplier)
298+
self.assertEqual(logged_info['actual_path'], test_actual_path)
299+
self.assertEqual(logged_info['resource_path'], test_resource_path)
300+
self.assertEqual(logged_info['local_id'], '12345^http://test')
301+
self.assertEqual(logged_info['vaccine_type'], 'FLU')
302+
self.assertNotIn('nhs_number', logged_info)
303+
304+
def test_patient_data_invalid(self, mock_logger, mock_firehose_logger):
305+
# Arrange
306+
test_correlation = "failed_test_correlation_patient_data_invalid"
307+
test_request = "failed_test_request_patient_data_invalid"
308+
test_supplier = "failed_test_supplier_patient_data_invalid"
309+
test_actual_path = "/failed_test_patient_data_invalid"
310+
test_resource_path = "/failed_test_patient_data_invalid"
311+
312+
self.mock_redis_client.hget.return_value = "FLU"
313+
314+
wrapped_function = function_info(self.mock_success_function)
315+
event = {
316+
'headers': {
317+
'X-Correlation-ID': test_correlation,
318+
'X-Request-ID': test_request,
319+
'SupplierSystem': test_supplier
320+
},
321+
'path': test_actual_path,
322+
'requestContext': {'resourcePath': test_resource_path},
323+
'body': "{\"identifier\": [{\"system\": \"http://test\", \"value\": \"12345\"}],\"contained\": [{\"resourceType\": \"Patient\", \"id\": \"Pat1\", \"identifier\": []}], \"protocolApplied\": [{\"targetDisease\": [{\"coding\": [{\"system\": \"http://snomed.info/sct\", \"code\": \"840539006\", \"display\": \"Disease caused by severe acute respiratory syndrome coronavirus 2\"}]}]}]}"
324+
}
325+
326+
# Act
327+
result = wrapped_function(event, {})
328+
329+
# Assert
330+
args, kwargs = mock_logger.info.call_args
331+
logged_info = json.loads(args[0])
332+
333+
self.assertIn('function_name', logged_info)
334+
self.assertIn('time_taken', logged_info)
335+
self.assertEqual(logged_info['X-Correlation-ID'], test_correlation)
336+
self.assertEqual(logged_info['X-Request-ID'], test_request)
337+
self.assertEqual(logged_info['supplier'], test_supplier)
338+
self.assertEqual(logged_info['actual_path'], test_actual_path)
339+
self.assertEqual(logged_info['resource_path'], test_resource_path)
340+
self.assertEqual(logged_info['local_id'], '12345^http://test')
341+
self.assertEqual(logged_info['vaccine_type'], 'FLU')
342+
self.assertNotIn('nhs_number', logged_info)
343+
344+
def test_nhs_number_missing(self, mock_logger, mock_firehose_logger):
345+
# Arrange
346+
test_correlation = "failed_test_correlation_nhs_number_missing"
347+
test_request = "failed_test_request_nhs_number_missing"
348+
test_supplier = "failed_test_supplier_nhs_number_missing"
349+
test_actual_path = "/failed_test_nhs_number_missing"
350+
test_resource_path = "/failed_test_nhs_number_missing"
351+
352+
self.mock_redis_client.hget.return_value = "FLU"
353+
354+
wrapped_function = function_info(self.mock_success_function)
355+
event = {
356+
'headers': {
357+
'X-Correlation-ID': test_correlation,
358+
'X-Request-ID': test_request,
359+
'SupplierSystem': test_supplier
360+
},
361+
'path': test_actual_path,
362+
'requestContext': {'resourcePath': test_resource_path},
363+
'body': "{\"identifier\": [{\"system\": \"http://test\", \"value\": \"12345\"}], \"contained\": [{\"resourceType\": \"Patient\", \"id\": \"Pat1\", \"identifier\": [{\"system\": \"https://fhir.nhs.uk/Id/nhs-number\"}]}], \"protocolApplied\": [{\"targetDisease\": [{\"coding\": [{\"system\": \"http://snomed.info/sct\", \"code\": \"840539006\", \"display\": \"Disease caused by severe acute respiratory syndrome coronavirus 2\"}]}]}]}"
364+
}
365+
366+
# Act
367+
result = wrapped_function(event, {})
368+
369+
# Assert
370+
args, kwargs = mock_logger.info.call_args
371+
logged_info = json.loads(args[0])
372+
373+
self.assertIn('function_name', logged_info)
374+
self.assertIn('time_taken', logged_info)
375+
self.assertEqual(logged_info['X-Correlation-ID'], test_correlation)
376+
self.assertEqual(logged_info['X-Request-ID'], test_request)
377+
self.assertEqual(logged_info['supplier'], test_supplier)
378+
self.assertEqual(logged_info['actual_path'], test_actual_path)
379+
self.assertEqual(logged_info['resource_path'], test_resource_path)
380+
self.assertEqual(logged_info['local_id'], '12345^http://test')
381+
self.assertEqual(logged_info['vaccine_type'], 'FLU')
382+
self.assertNotIn('nhs_number', logged_info)

0 commit comments

Comments
 (0)