add terminology troubleshooting log (#5439)

* init rev

* init rev

* changelog and additional logging

* changelog and additional logging

* changelog and additional logging

* spotless

* review feedback
This commit is contained in:
Ken Stevens 2023-11-10 14:54:51 -05:00 committed by GitHub
parent 8a39da4e91
commit 3bba9fb1f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 173 additions and 3 deletions

View File

@ -99,6 +99,11 @@ public class DefaultProfileValidationSupport implements IValidationSupport {
} }
} }
@Override
public String getName() {
return myCtx.getVersion().getVersion() + " FHIR Standard Profile Validation Support";
}
@Override @Override
public List<IBaseResource> fetchAllConformanceResources() { public List<IBaseResource> fetchAllConformanceResources() {
return myDelegate.fetchAllConformanceResources(); return myDelegate.fetchAllConformanceResources();

View File

@ -27,6 +27,7 @@ import ca.uhn.fhir.util.UrlUtil;
import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.hl7.fhir.instance.model.api.IBase; import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseCoding; import org.hl7.fhir.instance.model.api.IBaseCoding;
import org.hl7.fhir.instance.model.api.IBaseParameters; import org.hl7.fhir.instance.model.api.IBaseParameters;
@ -409,6 +410,13 @@ public interface IValidationSupport {
return null; return null;
} }
/**
* This field is used by the Terminology Troubleshooting Log to log which validation support module was used for the operation being logged.
*/
default String getName() {
return "Unknown " + getFhirContext().getVersion().getVersion() + " Validation Support";
}
enum IssueSeverity { enum IssueSeverity {
/** /**
* The issue caused the action to fail, and no further checking could be performed. * The issue caused the action to fail, and no further checking could be performed.
@ -990,6 +998,16 @@ public interface IValidationSupport {
public boolean isReverse() { public boolean isReverse() {
return myReverse; return myReverse;
} }
@Override
public String toString() {
return new ToStringBuilder(this)
.append("sourceValueSetUrl", mySourceValueSetUrl)
.append("targetSystemUrl", myTargetSystemUrl)
.append("targetValueSetUrl", myTargetValueSetUrl)
.append("reverse", myReverse)
.toString();
}
} }
/** /**

View File

@ -28,6 +28,9 @@ public class Logs {
private static final Logger ourNarrativeGenerationTroubleshootingLog = private static final Logger ourNarrativeGenerationTroubleshootingLog =
LoggerFactory.getLogger("ca.uhn.fhir.log.narrative_generation_troubleshooting"); LoggerFactory.getLogger("ca.uhn.fhir.log.narrative_generation_troubleshooting");
private static final Logger ourTerminologyTroubleshootingLog =
LoggerFactory.getLogger("ca.uhn.fhir.log.terminology_troubleshooting");
private static final Logger ourSubscriptionTroubleshootingLog = private static final Logger ourSubscriptionTroubleshootingLog =
LoggerFactory.getLogger("ca.cdr.log.subscription_troubleshooting"); LoggerFactory.getLogger("ca.cdr.log.subscription_troubleshooting");
@ -42,6 +45,10 @@ public class Logs {
return ourBatchTroubleshootingLog; return ourBatchTroubleshootingLog;
} }
public static Logger getTerminologyTroubleshootingLog() {
return ourTerminologyTroubleshootingLog;
}
public static Logger getSubscriptionTroubleshootingLog() { public static Logger getSubscriptionTroubleshootingLog() {
return ourSubscriptionTroubleshootingLog; return ourSubscriptionTroubleshootingLog;
} }

View File

@ -36,6 +36,11 @@ public class LoadingValidationSupportDstu2 implements IValidationSupport {
private static final org.slf4j.Logger ourLog = private static final org.slf4j.Logger ourLog =
org.slf4j.LoggerFactory.getLogger(LoadingValidationSupportDstu2.class); org.slf4j.LoggerFactory.getLogger(LoadingValidationSupportDstu2.class);
@Override
public String getName() {
return "Dstu2 CLI Loading Validation Support";
}
@Override @Override
public <T extends IBaseResource> T fetchResource(Class<T> theClass, String theUri) { public <T extends IBaseResource> T fetchResource(Class<T> theClass, String theUri) {
String resName = myCtx.getResourceType(theClass); String resName = myCtx.getResourceType(theClass);

View File

@ -35,6 +35,11 @@ public class LoadingValidationSupportDstu3 implements IValidationSupport {
private static final org.slf4j.Logger ourLog = private static final org.slf4j.Logger ourLog =
org.slf4j.LoggerFactory.getLogger(LoadingValidationSupportDstu3.class); org.slf4j.LoggerFactory.getLogger(LoadingValidationSupportDstu3.class);
@Override
public String getName() {
return "Dstu3 CLI Loading Validation Support";
}
@Override @Override
public <T extends IBaseResource> T fetchResource(Class<T> theClass, String theUri) { public <T extends IBaseResource> T fetchResource(Class<T> theClass, String theUri) {
String resName = myCtx.getResourceType(theClass); String resName = myCtx.getResourceType(theClass);

View File

@ -0,0 +1,4 @@
---
type: add
issue: 5439
title: "Added Terminology Troubleshooting Log to support troubleshooting terminology issues."

View File

@ -103,6 +103,11 @@ public class JpaPersistedResourceValidationSupport implements IValidationSupport
myNoMatch = myFhirContext.getResourceDefinition("Basic").newInstance(); myNoMatch = myFhirContext.getResourceDefinition("Basic").newInstance();
} }
@Override
public String getName() {
return myFhirContext.getVersion().getVersion() + " JPA Validation Support";
}
@Override @Override
public IBaseResource fetchCodeSystem(String theSystem) { public IBaseResource fetchCodeSystem(String theSystem) {
if (TermReadSvcUtil.isLoincUnversionedCodeSystem(theSystem)) { if (TermReadSvcUtil.isLoincUnversionedCodeSystem(theSystem)) {

View File

@ -69,6 +69,11 @@ public class TermConceptMappingSvcImpl extends TermConceptClientMappingSvcImpl i
@Autowired @Autowired
protected ITermConceptMapGroupElementTargetDao myConceptMapGroupElementTargetDao; protected ITermConceptMapGroupElementTargetDao myConceptMapGroupElementTargetDao;
@Override
public String getName() {
return getFhirContext().getVersion().getVersion() + " ConceptMap Validation Support";
}
@Override @Override
@Transactional @Transactional
public void deleteConceptMapAndChildren(ResourceTable theResourceTable) { public void deleteConceptMapAndChildren(ResourceTable theResourceTable) {

View File

@ -86,6 +86,11 @@ public class CommonCodeSystemsTerminologyService implements IValidationSupport {
myVersionCanonicalizer = new VersionCanonicalizer(theFhirContext); myVersionCanonicalizer = new VersionCanonicalizer(theFhirContext);
} }
@Override
public String getName() {
return myFhirContext.getVersion().getVersion() + " Common Code Systems Validation Support";
}
@Override @Override
public CodeValidationResult validateCodeInValueSet( public CodeValidationResult validateCodeInValueSet(
ValidationSupportContext theValidationSupportContext, ValidationSupportContext theValidationSupportContext,

View File

@ -39,4 +39,9 @@ public class DefaultProfileValidationSupportNpmStrategy extends NpmPackageValida
ourLog.info("Loaded {} Core+Extension resources in {}", countAll(), sw); ourLog.info("Loaded {} Core+Extension resources in {}", countAll(), sw);
} }
@Override
public String getName() {
return getFhirContext().getVersion().getVersion() + " FHIR Standard Profile NPM Validation Support";
}
} }

View File

@ -72,6 +72,11 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu
myVersionCanonicalizer = new VersionCanonicalizer(theCtx); myVersionCanonicalizer = new VersionCanonicalizer(theCtx);
} }
@Override
public String getName() {
return myCtx.getVersion().getVersion() + " In-Memory Validation Support";
}
/** /**
* This setting controls the validation issue severity to report when a code validation * This setting controls the validation issue severity to report when a code validation
* finds that the code is present in the given CodeSystem, but the display name being * finds that the code is present in the given CodeSystem, but the display name being

View File

@ -33,6 +33,11 @@ public class LocalFileValidationSupport extends PrePopulatedValidationSupport {
super(ctx); super(ctx);
} }
@Override
public String getName() {
return getFhirContext().getVersion().getVersion() + " Local File Validation Support";
}
@Override @Override
public FhirContext getFhirContext() { public FhirContext getFhirContext() {
return myCtx; return myCtx;

View File

@ -18,7 +18,7 @@ import javax.annotation.Nonnull;
/** /**
* This interceptor loads and parses FHIR NPM Conformance Packages, and makes the * This interceptor loads and parses FHIR NPM Conformance Packages, and makes the
* artifacts foudn within them available to the FHIR validator. * artifacts found within them available to the FHIR validator.
* *
* @since 5.5.0 * @since 5.5.0
*/ */

View File

@ -54,6 +54,11 @@ public class PrePopulatedValidationSupport extends BaseStaticResourceValidationS
this(theContext, new HashMap<>(), new HashMap<>(), new HashMap<>(), new HashMap<>(), new HashMap<>()); this(theContext, new HashMap<>(), new HashMap<>(), new HashMap<>(), new HashMap<>(), new HashMap<>());
} }
@Override
public String getName() {
return getFhirContext().getVersion().getVersion() + " Pre-populated Validation Support";
}
/** /**
* Constructor * Constructor
* *

View File

@ -57,6 +57,11 @@ public class RemoteTerminologyServiceValidationSupport extends BaseValidationSup
myBaseUrl = theBaseUrl; myBaseUrl = theBaseUrl;
} }
@Override
public String getName() {
return getFhirContext().getVersion().getVersion() + " Remote Terminology Service Validation Support";
}
@Override @Override
public CodeValidationResult validateCode( public CodeValidationResult validateCode(
@Nonnull ValidationSupportContext theValidationSupportContext, @Nonnull ValidationSupportContext theValidationSupportContext,

View File

@ -179,4 +179,9 @@ public class SnapshotGeneratingValidationSupport implements IValidationSupport {
public FhirContext getFhirContext() { public FhirContext getFhirContext() {
return myCtx; return myCtx;
} }
@Override
public String getName() {
return getFhirContext().getVersion().getVersion() + " Snapshot Generating Validation Support";
}
} }

View File

@ -33,6 +33,11 @@ public class UnknownCodeSystemWarningValidationSupport extends BaseValidationSup
super(theFhirContext); super(theFhirContext);
} }
@Override
public String getName() {
return getFhirContext().getVersion().getVersion() + " Unknown Code System Warning Validation Support";
}
@Override @Override
public boolean isValueSetSupported(ValidationSupportContext theValidationSupportContext, String theValueSetUrl) { public boolean isValueSetSupported(ValidationSupportContext theValidationSupportContext, String theValueSetUrl) {
return true; return true;

View File

@ -9,9 +9,11 @@ import ca.uhn.fhir.context.support.TranslateConceptResults;
import ca.uhn.fhir.context.support.ValidationSupportContext; import ca.uhn.fhir.context.support.ValidationSupportContext;
import ca.uhn.fhir.context.support.ValueSetExpansionOptions; import ca.uhn.fhir.context.support.ValueSetExpansionOptions;
import ca.uhn.fhir.i18n.Msg; import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.util.Logs;
import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IPrimitiveType; import org.hl7.fhir.instance.model.api.IPrimitiveType;
import org.slf4j.Logger;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
@ -25,6 +27,7 @@ import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank;
public class ValidationSupportChain implements IValidationSupport { public class ValidationSupportChain implements IValidationSupport {
static Logger ourLog = Logs.getTerminologyTroubleshootingLog();
private List<IValidationSupport> myChain; private List<IValidationSupport> myChain;
@ -66,14 +69,25 @@ public class ValidationSupportChain implements IValidationSupport {
retVal.setMessage(translations.getMessage()); retVal.setMessage(translations.getMessage());
} }
if (!translations.isEmpty()) {
if (ourLog.isDebugEnabled()) {
ourLog.debug(
"{} found {} concept translation{} for {}",
next.getName(),
translations.size(),
translations.size() > 1 ? "s" : "",
theRequest);
}
retVal.getResults().addAll(translations.getResults()); retVal.getResults().addAll(translations.getResults());
} }
} }
}
return retVal; return retVal;
} }
@Override @Override
public void invalidateCaches() { public void invalidateCaches() {
ourLog.debug("Invalidating caches in {} validation support modules", myChain.size());
for (IValidationSupport next : myChain) { for (IValidationSupport next : myChain) {
next.invalidateCaches(); next.invalidateCaches();
} }
@ -84,6 +98,9 @@ public class ValidationSupportChain implements IValidationSupport {
for (IValidationSupport next : myChain) { for (IValidationSupport next : myChain) {
boolean retVal = next.isValueSetSupported(theValidationSupportContext, theValueSetUrl); boolean retVal = next.isValueSetSupported(theValidationSupportContext, theValueSetUrl);
if (retVal) { if (retVal) {
if (ourLog.isDebugEnabled()) {
ourLog.debug("ValueSet {} found in {}", theValueSetUrl, next.getName());
}
return true; return true;
} }
} }
@ -101,6 +118,9 @@ public class ValidationSupportChain implements IValidationSupport {
IBaseResource retVal = IBaseResource retVal =
next.generateSnapshot(theValidationSupportContext, theInput, theUrl, theWebUrl, theProfileName); next.generateSnapshot(theValidationSupportContext, theInput, theUrl, theWebUrl, theProfileName);
if (retVal != null) { if (retVal != null) {
if (ourLog.isDebugEnabled()) {
ourLog.debug("Profile snapshot for {} generated by {}", theInput.getIdElement(), next.getName());
}
return retVal; return retVal;
} }
} }
@ -178,6 +198,9 @@ public class ValidationSupportChain implements IValidationSupport {
ValueSetExpansionOutcome expanded = ValueSetExpansionOutcome expanded =
next.expandValueSet(theValidationSupportContext, theExpansionOptions, theValueSetToExpand); next.expandValueSet(theValidationSupportContext, theExpansionOptions, theValueSetToExpand);
if (expanded != null) { if (expanded != null) {
if (ourLog.isDebugEnabled()) {
ourLog.debug("ValueSet {} expanded by {}", theValueSetToExpand.getIdElement(), next.getName());
}
return expanded; return expanded;
} }
} }
@ -246,6 +269,13 @@ public class ValidationSupportChain implements IValidationSupport {
for (IValidationSupport next : myChain) { for (IValidationSupport next : myChain) {
IBaseResource retVal = next.fetchCodeSystem(theSystem); IBaseResource retVal = next.fetchCodeSystem(theSystem);
if (retVal != null) { if (retVal != null) {
if (ourLog.isDebugEnabled()) {
ourLog.debug(
"CodeSystem {} with System {} fetched by {}",
retVal.getIdElement(),
theSystem,
next.getName());
}
return retVal; return retVal;
} }
} }
@ -257,6 +287,10 @@ public class ValidationSupportChain implements IValidationSupport {
for (IValidationSupport next : myChain) { for (IValidationSupport next : myChain) {
IBaseResource retVal = next.fetchValueSet(theUrl); IBaseResource retVal = next.fetchValueSet(theUrl);
if (retVal != null) { if (retVal != null) {
if (ourLog.isDebugEnabled()) {
ourLog.debug(
"ValueSet {} with URL {} fetched by {}", retVal.getIdElement(), theUrl, next.getName());
}
return retVal; return retVal;
} }
} }
@ -268,6 +302,10 @@ public class ValidationSupportChain implements IValidationSupport {
for (IValidationSupport next : myChain) { for (IValidationSupport next : myChain) {
T retVal = next.fetchResource(theClass, theUri); T retVal = next.fetchResource(theClass, theUri);
if (retVal != null) { if (retVal != null) {
if (ourLog.isDebugEnabled()) {
ourLog.debug(
"Resource {} with URI {} fetched by {}", retVal.getIdElement(), theUri, next.getName());
}
return retVal; return retVal;
} }
} }
@ -279,6 +317,9 @@ public class ValidationSupportChain implements IValidationSupport {
for (IValidationSupport next : myChain) { for (IValidationSupport next : myChain) {
byte[] retVal = next.fetchBinary(key); byte[] retVal = next.fetchBinary(key);
if (retVal != null) { if (retVal != null) {
if (ourLog.isDebugEnabled()) {
ourLog.debug("Binary with key {} fetched by {}", key, next.getName());
}
return retVal; return retVal;
} }
} }
@ -290,6 +331,9 @@ public class ValidationSupportChain implements IValidationSupport {
for (IValidationSupport next : myChain) { for (IValidationSupport next : myChain) {
IBaseResource retVal = next.fetchStructureDefinition(theUrl); IBaseResource retVal = next.fetchStructureDefinition(theUrl);
if (retVal != null) { if (retVal != null) {
if (ourLog.isDebugEnabled()) {
ourLog.debug("StructureDefinition with URL {} fetched by {}", theUrl, next.getName());
}
return retVal; return retVal;
} }
} }
@ -300,6 +344,9 @@ public class ValidationSupportChain implements IValidationSupport {
public boolean isCodeSystemSupported(ValidationSupportContext theValidationSupportContext, String theSystem) { public boolean isCodeSystemSupported(ValidationSupportContext theValidationSupportContext, String theSystem) {
for (IValidationSupport next : myChain) { for (IValidationSupport next : myChain) {
if (next.isCodeSystemSupported(theValidationSupportContext, theSystem)) { if (next.isCodeSystemSupported(theValidationSupportContext, theSystem)) {
if (ourLog.isDebugEnabled()) {
ourLog.debug("CodeSystem with System {} is supported by {}", theSystem, next.getName());
}
return true; return true;
} }
} }
@ -321,6 +368,15 @@ public class ValidationSupportChain implements IValidationSupport {
CodeValidationResult retVal = next.validateCode( CodeValidationResult retVal = next.validateCode(
theValidationSupportContext, theOptions, theCodeSystem, theCode, theDisplay, theValueSetUrl); theValidationSupportContext, theOptions, theCodeSystem, theCode, theDisplay, theValueSetUrl);
if (retVal != null) { if (retVal != null) {
if (ourLog.isDebugEnabled()) {
ourLog.debug(
"Code {}|{} '{}' in ValueSet {} validated by {}",
theCodeSystem,
theCode,
theDisplay,
theValueSetUrl,
next.getName());
}
return retVal; return retVal;
} }
} }
@ -342,6 +398,15 @@ public class ValidationSupportChain implements IValidationSupport {
CodeValidationResult retVal = next.validateCodeInValueSet( CodeValidationResult retVal = next.validateCodeInValueSet(
theValidationSupportContext, theOptions, theCodeSystem, theCode, theDisplay, theValueSet); theValidationSupportContext, theOptions, theCodeSystem, theCode, theDisplay, theValueSet);
if (retVal != null) { if (retVal != null) {
if (ourLog.isDebugEnabled()) {
ourLog.debug(
"Code {}|{} '{}' in ValueSet {} validated by {}",
theCodeSystem,
theCode,
theDisplay,
theValueSet.getIdElement(),
next.getName());
}
return retVal; return retVal;
} }
} }
@ -357,7 +422,18 @@ public class ValidationSupportChain implements IValidationSupport {
String theDisplayLanguage) { String theDisplayLanguage) {
for (IValidationSupport next : myChain) { for (IValidationSupport next : myChain) {
if (next.isCodeSystemSupported(theValidationSupportContext, theSystem)) { if (next.isCodeSystemSupported(theValidationSupportContext, theSystem)) {
return next.lookupCode(theValidationSupportContext, theSystem, theCode, theDisplayLanguage); LookupCodeResult lookupCodeResult =
next.lookupCode(theValidationSupportContext, theSystem, theCode, theDisplayLanguage);
if (ourLog.isDebugEnabled()) {
ourLog.debug(
"Code {}|{}{} {} by {}",
theSystem,
theCode,
isBlank(theDisplayLanguage) ? "" : " (" + theDisplayLanguage + ")",
lookupCodeResult != null && lookupCodeResult.isFound() ? "found" : "not found",
next.getName());
}
return lookupCodeResult;
} }
} }
return null; return null;