Skip to content

TRUNK-6243: Add a new runtime property to determine if app is running in development or production mode #4992

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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
7 changes: 7 additions & 0 deletions api/src/main/java/org/openmrs/util/OpenmrsConstants.java
Original file line number Diff line number Diff line change
Expand Up @@ -558,6 +558,13 @@ public static final Collection<String> AUTO_ROLES() {
public static final String ENCRYPTION_KEY_RUNTIME_PROPERTY = "encryption.key";

public static final String ENCRYPTION_KEY_DEFAULT = "dTfyELRrAICGDwzjHDjuhw==";

/**
* Runtime property that will tell the system if app is running in development or production mode.
*/
public static final String DEVELOPMENT_MODE_RUNTIME_PROPERTY = "development.mode";

public static final String DEVELOPMENT_MODE_DEFAULT = "true";

/**
* Global property name for the visit type(s) to automatically close
Expand Down
65 changes: 65 additions & 0 deletions api/src/main/java/org/openmrs/util/OpenmrsUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -1946,6 +1946,71 @@ public static String shortenedStackTrace(String stackTrace) {
return StringUtils.join(results, "\n");
}

/**
* Convert a stack trace into a formatted message version for easier viewing In production mode, instead of a page
* with stack traces. In development mode, we should continue to have stack traces.
*
* @param stackTrace original stack trace from an error
* @return formatted stack trace message
* <strong>Should</strong> return null if stackTrace is null
* <strong>Should</strong> return the Error and the Cause
* @since 2.8
*/
public static String formattedStackTrace(String stackTrace) {
if (stackTrace == null) {
return null;
}

// If not in dev mode, convert a stack trace into a formatted message version
String props = Context.getRuntimeProperties().getProperty(OpenmrsConstants.DEVELOPMENT_MODE_RUNTIME_PROPERTY);
if (StringUtils.equals(props, "false")) {
// Pattern to match the first exception and first "Caused by"
Pattern pattern = Pattern.compile("(?m)^(([\\w.$]+Exception|Error|Throwable): .*)|"
+ "(Caused by: [\\w.$]+(Exception|Error|Throwable): .*)");

Matcher matcher = pattern.matcher(stackTrace);
StringBuilder result = new StringBuilder();
boolean foundFirst = false;
boolean foundCause = false;

while (matcher.find()) {
String line = matcher.group().trim();
if (!foundFirst) {
if (isExceptionLine(line)) {
result.append(detectExceptionType(line)).append(": ").append(line);
}
foundFirst = true;
} else if (line.startsWith("Caused by:")) {
result.append("\n").append(line);
foundCause = true;
}

if (foundCause) {
break;
}
}

return result.toString();
} else {
return stackTrace;
}
}

private static boolean isExceptionLine(String line) {
return line.matches("([\\w$]+\\.)*[\\w$]+(Exception|Error|Throwable): .*");
}

private static String detectExceptionType(String line) {
if (line.contains(".hl7")) {
return "Error (HL7)";
} else if (line.contains("org.springframework.")) {
return "Error (Spring)";
} else if (line.contains("java.") || line.contains("javax.")) {
return "Error (Java)";
}
return "Error";
}

/**
* <pre>
* Finds and loads the runtime properties file for a specific OpenMRS application.
Expand Down
48 changes: 48 additions & 0 deletions api/src/test/java/org/openmrs/util/OpenmrsUtilTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -672,6 +672,54 @@ public void shortenedStackTrace_shouldRemoveSpringframeworkAndReflectionRelatedL
assertEquals(expected, OpenmrsUtil.shortenedStackTrace(test), "stack trace was not shortened properly");
}

/**
* @see OpenmrsUtil#formattedStackTrace(String)
*/
@Test
public void formattedStackTrace_shouldReturnTheErrorAndCauseAfterFormattingIfNotInDevMode() {
Properties props = Context.getRuntimeProperties();
props.setProperty(OpenmrsConstants.DEVELOPMENT_MODE_RUNTIME_PROPERTY, "false");
Context.setRuntimeProperties(props);

String test = "ca.uhn.hl7v2.HL7Exception: Error while processing HL7 message: ORU_R01\n"
+ "\tat org.openmrs.hl7.impl.HL7ServiceImpl.processHL7Message(HL7ServiceImpl.java:752)\n"
+ "Caused by: ca.uhn.hl7v2.app.ApplicationException: ca.uhn.hl7v2.HL7Exception: Could not resolve patient by identifier\n"
+ "\tat org.openmrs.hl7.handler.ORUR01Handler.processMessage(ORUR01Handler.java:132)\n"
+ "Caused by: ca.uhn.hl7v2.HL7Exception: Could not resolve patient by identifier\n"
+ "\tat org.openmrs.hl7.handler.ORUR01Handler.getPatientByIdentifier(ORUR01Handler.java:998)";

String expected = "Error (HL7): ca.uhn.hl7v2.HL7Exception: Error while processing HL7 message: ORU_R01\n"
+ "Caused by: ca.uhn.hl7v2.app.ApplicationException: ca.uhn.hl7v2.HL7Exception: Could not resolve patient by identifier";

assertEquals(expected, OpenmrsUtil.formattedStackTrace(test), "stack trace was not formatted properly");
}

/**
* @see OpenmrsUtil#formattedStackTrace(String)
*/
@Test
public void formattedStackTrace_shouldReturnTheUnFormattedStackTraceIfInDevMode() {
Properties props = Context.getRuntimeProperties();
props.setProperty(OpenmrsConstants.DEVELOPMENT_MODE_RUNTIME_PROPERTY, "true");
Context.setRuntimeProperties(props);

String test = "ca.uhn.hl7v2.HL7Exception: Error while processing HL7 message: ORU_R01\n"
+ "\tat org.openmrs.hl7.impl.HL7ServiceImpl.processHL7Message(HL7ServiceImpl.java:752)\n"
+ "Caused by: ca.uhn.hl7v2.app.ApplicationException: ca.uhn.hl7v2.HL7Exception: Could not resolve patient by identifier\n"
+ "\tat org.openmrs.hl7.handler.ORUR01Handler.processMessage(ORUR01Handler.java:132)\n"
+ "Caused by: ca.uhn.hl7v2.HL7Exception: Could not resolve patient by identifier\n"
+ "\tat org.openmrs.hl7.handler.ORUR01Handler.getPatientByIdentifier(ORUR01Handler.java:998)";

String expected = "ca.uhn.hl7v2.HL7Exception: Error while processing HL7 message: ORU_R01\n"
+ "\tat org.openmrs.hl7.impl.HL7ServiceImpl.processHL7Message(HL7ServiceImpl.java:752)\n"
+ "Caused by: ca.uhn.hl7v2.app.ApplicationException: ca.uhn.hl7v2.HL7Exception: Could not resolve patient by identifier\n"
+ "\tat org.openmrs.hl7.handler.ORUR01Handler.processMessage(ORUR01Handler.java:132)\n"
+ "Caused by: ca.uhn.hl7v2.HL7Exception: Could not resolve patient by identifier\n"
+ "\tat org.openmrs.hl7.handler.ORUR01Handler.getPatientByIdentifier(ORUR01Handler.java:998)";

assertEquals(expected, OpenmrsUtil.formattedStackTrace(test), "stack trace was not returned properly");
}

/**
* @see OpenmrsUtil#shortenedStackTrace(String)
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1533,6 +1533,8 @@ public void run() {
new String(base64.encode(Security.generateNewInitVector()), StandardCharsets.UTF_8));
runtimeProperties.put(OpenmrsConstants.ENCRYPTION_KEY_RUNTIME_PROPERTY,
new String(base64.encode(Security.generateNewSecretKey()), StandardCharsets.UTF_8));
runtimeProperties.put(OpenmrsConstants.DEVELOPMENT_MODE_RUNTIME_PROPERTY,
OpenmrsConstants.DEVELOPMENT_MODE_DEFAULT);

Properties properties = Context.getRuntimeProperties();
properties.putAll(runtimeProperties);
Expand Down
Loading