GUACAMOLE-2181: Rely on automatic stack traces for debug-level logs.

This commit is contained in:
Michael Jumper committed 2025-12-08 20:24:10 -08:00
1 parent c92694c458
commit ea06e01ddd
44 files changed
+152 -243

No files matched your search

@@ -166,8 +166,7 @@ public class GuacamoleServletContextListener extends GuiceServletContextListener
logger.info("Read configuration parameters from \"{}\".", guacProperties);
}
catch (GuacamoleException e) {
logger.error("Unable to read guacamole.properties: {}", e.getMessage());
logger.debug("Error reading guacamole.properties.", e);
logger.error("Unable to read guacamole.properties: {}", e.getMessage(), e);
}
// For any values not defined in GUACAMOLE_HOME/guacamole.properties,
@@ -181,8 +180,7 @@ public class GuacamoleServletContextListener extends GuiceServletContextListener
}
}
catch (GuacamoleException e) {
logger.error("Unable to configure support for environment properties: {}", e.getMessage());
logger.debug("Error reading \"{}\" property from guacamole.properties.", ENABLE_ENVIRONMENT_PROPERTIES.getName(), e);
logger.error("Unable to configure support for environment properties: {}", e.getMessage(), e);
}
// For any values not defined in GUACAMOLE_HOME/guacamole.properties
@@ -198,8 +196,7 @@ public class GuacamoleServletContextListener extends GuiceServletContextListener
}
}
catch (GuacamoleException e) {
logger.error("Unable to configure support for file environment properties: {}", e.getMessage());
logger.debug("Error reading \"{}\" property from guacamole.properties.", ENABLE_FILE_ENVIRONMENT_PROPERTIES.getName(), e);
logger.error("Unable to configure support for file environment properties: {}", e.getMessage(), e);
}
// Now that at least the main guacamole.properties source of
@@ -225,8 +222,7 @@ public class GuacamoleServletContextListener extends GuiceServletContextListener
});
}
catch (GuacamoleException e) {
logger.error("An extension listening for application startup failed: {}", e.getMessage());
logger.debug("Extension failed internally while handling the application startup event.", e);
logger.error("An extension listening for application startup failed: {}", e.getMessage(), e);
}
}
@@ -307,8 +303,7 @@ public class GuacamoleServletContextListener extends GuiceServletContextListener
});
}
catch (GuacamoleException e) {
logger.error("An extension listening for application shutdown failed: {}", e.getMessage());
logger.debug("Extension failed internally while handling the application shutdown event.", e);
logger.error("An extension listening for application shutdown failed: {}", e.getMessage(), e);
}
}
@@ -320,8 +320,7 @@ public class GuacamoleSession {
});
}
catch (GuacamoleException e) {
logger.error("An extension listening for session invalidation failed: {}", e.getMessage());
logger.debug("Extension failed internally while handling the session invalidation event.", e);
logger.error("An extension listening for session invalidation failed: {}", e.getMessage(), e);
}
}
@@ -51,8 +51,8 @@ public class SystemFileEnvironmentGuacamoleProperties implements GuacamoleProper
return Files.asCharSource(new File(filename), StandardCharsets.UTF_8).read();
}
catch (IOException e) {
logger.error("Property \"{}\" could not be read from file \"{}\": {}", name, filename, e.getMessage());
logger.debug("Error reading property value from file.", e);
logger.error("Property \"{}\" could not be read from file \"{}\": {}", name,
filename, e.getMessage(), e);
}
}
@@ -106,13 +106,13 @@ public class FileAuthenticationProvider extends SimpleAuthenticationProvider {
parser = SAXParserFactory.newInstance().newSAXParser();
}
catch (ParserConfigurationException e) {
logger.error("Unable to create XML parser for reading \"{}\": {}", USER_MAPPING_FILENAME, e.getMessage());
logger.debug("An instance of SAXParser could not be created.", e);
logger.error("Unable to create XML parser for reading \"{}\": {}",
USER_MAPPING_FILENAME, e.getMessage(), e);
return null;
}
catch (SAXException e) {
logger.error("Unable to create XML parser for reading \"{}\": {}", USER_MAPPING_FILENAME, e.getMessage());
logger.debug("An instance of SAXParser could not be created.", e);
logger.error("Unable to create XML parser for reading \"{}\": {}",
USER_MAPPING_FILENAME, e.getMessage(), e);
return null;
}
@@ -138,15 +138,13 @@ public class FileAuthenticationProvider extends SimpleAuthenticationProvider {
// If the file is unreadable, return no mapping
catch (IOException e) {
logger.warn("Unable to read user mapping file \"{}\": {}", userMappingFile, e.getMessage());
logger.debug("Error reading user mapping file.", e);
logger.warn("Unable to read user mapping file \"{}\": {}", userMappingFile, e.getMessage(), e);
return null;
}
// If the file cannot be parsed, return no mapping
catch (SAXException e) {
logger.warn("User mapping file \"{}\" is not valid: {}", userMappingFile, e.getMessage());
logger.debug("Error parsing user mapping file.", e);
logger.warn("User mapping file \"{}\" is not valid: {}", userMappingFile, e.getMessage(), e);
return null;
}
@@ -182,15 +182,11 @@ public class AuthenticationProviderFacade implements AuthenticationProvider {
* authentication provider being skipped.
*/
private void warnAuthProviderSkipped(Throwable e) {
logger.warn("The \"{}\" authentication provider has been skipped due "
+ "to an internal error. If this is unexpected or you are the "
+ "developer of this authentication provider, you may wish to "
+ "enable debug-level logging: {}",
getIdentifier(), e.getMessage());
logger.debug("Authentication provider skipped due to an internal failure.", e);
getIdentifier(), e.getMessage(), e);
}
/**
@@ -434,8 +434,9 @@ public class ExtensionModule extends ServletModule {
// Use empty set by default if property cannot be parsed
catch (GuacamoleException e) {
logger.warn("The list of authentication providers specified via the \"{}\" property could not be parsed: {}", SKIP_IF_UNAVAILABLE.getName(), e.getMessage());
logger.debug("Unable to parse \"{}\" property.", SKIP_IF_UNAVAILABLE.getName(), e);
logger.warn("The list of authentication providers specified via "
+ "the \"{}\" property could not be parsed: {}",
SKIP_IF_UNAVAILABLE.getName(), e.getMessage(), e);
return Collections.<String>emptySet();
}
@@ -457,8 +458,9 @@ public class ExtensionModule extends ServletModule {
// Sort by filename if the desired order cannot be read
catch (GuacamoleException e) {
logger.warn("The list of extensions specified via the \"{}\" property could not be parsed: {}", EXTENSION_PRIORITY.getName(), e.getMessage());
logger.debug("Unable to parse \"{}\" property.", EXTENSION_PRIORITY.getName(), e);
logger.warn("The list of extensions specified via the \"{}\" "
+ "property could not be parsed: {}",
EXTENSION_PRIORITY.getName(), e.getMessage(), e);
return ExtensionOrderProperty.DEFAULT_COMPARATOR;
}
@@ -522,8 +524,8 @@ public class ExtensionModule extends ServletModule {
}
catch (GuacamoleException e) {
logger.error("Extension \"{}\" could not be loaded: {}", extensionFile.getName(), e.getMessage());
logger.debug("Unable to load extension.", e);
logger.error("Extension \"{}\" could not be loaded: {}",
extensionFile.getName(), e.getMessage(), e);
}
}
@@ -125,8 +125,7 @@ public class LanguageResourceService {
// Warn of failure to parse
catch (GuacamoleException e) {
parsedAllowedLanguages = null;
logger.error("Unable to parse list of allowed languages: {}", e.getMessage());
logger.debug("Error parsing list of allowed languages.", e);
logger.error("Unable to parse list of allowed languages: {}", e.getMessage(), e);
}
this.allowedLanguages = parsedAllowedLanguages;
@@ -308,8 +307,7 @@ public class LanguageResourceService {
}
catch (IOException e) {
logger.error("Unable to merge language resource \"{}\": {}", key, e.getMessage());
logger.debug("Error merging language resource.", e);
logger.error("Unable to merge language resource \"{}\": {}", key, e.getMessage(), e);
}
}
@@ -437,8 +435,7 @@ public class LanguageResourceService {
// Continue with next language if unable to read
catch (IOException e) {
logger.warn("Unable to read language resource \"{}\".", languageKey);
logger.debug("Error reading language resource.", e);
logger.warn("Unable to read language resource \"{}\".", languageKey, e);
}
}
@@ -61,35 +61,29 @@ class ProviderFactory {
catch (NoSuchMethodException e) {
logger.error("The {} extension in use is not properly defined. "
+ "Please contact the developers of the extension or, if you "
+ "are the developer, turn on debug-level logging.", typeName);
logger.debug("{} is missing a default constructor.",
providerClass.getName(), e);
+ "are the developer, turn on debug-level logging.",
typeName, e);
}
catch (SecurityException e) {
logger.error("The Java security manager is preventing extensions "
+ "from being loaded. Please check the configuration of Java or your "
+ "servlet container.");
logger.debug("Creation of {} disallowed by security manager.",
providerClass.getName(), e);
+ "servlet container.", e);
}
catch (InstantiationException e) {
logger.error("The {} extension in use is not properly defined. "
+ "Please contact the developers of the extension or, if you "
+ "are the developer, turn on debug-level logging.", typeName);
logger.debug("{} cannot be instantiated.", providerClass.getName(), e);
+ "are the developer, turn on debug-level logging.",
typeName, e);
}
catch (IllegalAccessException e) {
logger.error("The {} extension in use is not properly defined. "
+ "Please contact the developers of the extension or, if you "
+ "are the developer, turn on debug-level logging.");
logger.debug("Default constructor of {} is not public.", typeName, e);
+ "are the developer, turn on debug-level logging.", e);
}
catch (IllegalArgumentException e) {
logger.error("The {} extension in use is not properly defined. "
+ "Please contact the developers of the extension or, if you "
+ "are the developer, turn on debug-level logging.", typeName);
logger.debug("Default constructor of {} cannot accept zero arguments.",
providerClass.getName(), e);
+ "are the developer, turn on debug-level logging.", typeName, e);
}
catch (InvocationTargetException e) {
// Obtain causing error - create relatively-informative stub error if cause is unknown
@@ -97,8 +91,7 @@ class ProviderFactory {
if (cause == null)
cause = new GuacamoleException("Error encountered during initialization.");
logger.error("{} extension failed to start: {}", typeName, cause.getMessage());
logger.debug("{} instantiation failed.", providerClass.getName(), e);
logger.error("{} extension failed to start: {}", typeName, cause.getMessage(), cause);
}
return instance;
@@ -187,7 +187,7 @@ public class LogModule extends AbstractModule {
}
catch (FileNotFoundException e) {
logger.info("Logback configuration could not be read "
+ "from \"{}\": {}", logbackFile, e.getMessage());
+ "from \"{}\": {}", logbackFile, e.getMessage(), e);
}
}
@@ -200,7 +200,7 @@ public class LogModule extends AbstractModule {
}
catch (GuacamoleException e) {
level = LogLevel.INFO;
logger.error("Falling back to \"{}\" log level: {}", level.getCanonicalName(), e.getMessage());
logger.error("Falling back to \"{}\" log level: {}", level.getCanonicalName(), e.getMessage(), e);
}
return level.getLogbackConfiguration();
@@ -232,12 +232,10 @@ public class LogModule extends AbstractModule {
}
catch (JoranException e) {
logger.error("Initialization of logback failed: {}", e.getMessage());
logger.debug("Unable to load logback configuration.", e);
logger.error("Initialization of logback failed: {}", e.getMessage(), e);
}
catch (IOException e) {
logger.warn("Logback configuration file could not be cleanly closed: {}", e.getMessage());
logger.debug("Failed to close logback configuration file.", e);
logger.warn("Logback configuration file could not be cleanly closed: {}", e.getMessage(), e);
}
}
@@ -75,7 +75,7 @@ public class RESTExceptionMapper implements ExceptionMapper<Throwable> {
if (t instanceof GuacamoleUnauthorizedException) {
String token = authenticationService.getAuthenticationToken(request);
if (authenticationService.destroyGuacamoleSession(token))
logger.debug("Implicitly invalidated session for token \"{}\"", token);
logger.debug("Implicitly invalidated session for token \"{}\"", token, t);
}
// Translate GuacamoleException subclasses to HTTP error codes
@@ -84,11 +84,9 @@ public class RESTExceptionMapper implements ExceptionMapper<Throwable> {
// Always log the human-readable details of GuacacamoleExceptions
// for the benefit of the administrator
if (t instanceof GuacamoleClientException)
logger.debug("Client request rejected: {}", t.getMessage());
else {
logger.error("Request could not be processed: {}", t.getMessage());
logger.debug("Processing of request aborted by extension.", t);
}
logger.debug("Client request rejected: {}", t.getMessage(), t);
else
logger.error("Request could not be processed: {}", t.getMessage(), t);
return Response
.status(((GuacamoleException) t).getHttpStatusCode())
@@ -100,13 +98,11 @@ public class RESTExceptionMapper implements ExceptionMapper<Throwable> {
// Wrap unchecked exceptions
String message = t.getMessage();
if (message != null)
logger.error("Unexpected internal error: {}", message);
logger.error("Unexpected internal error: {}", message, t);
else
logger.error("An internal error occurred, but did not contain "
+ "an error message. Enable debug-level logging for "
+ "details.");
logger.debug("Unexpected error in REST endpoint.", t);
+ "details.", t);
return Response
.status(Response.Status.INTERNAL_SERVER_ERROR)
@@ -433,12 +433,12 @@ public class AuthenticationService {
// This line SHOULD be unreachable unless a bug causes
// rethrowCause() to not actually rethrow the underlying failure
Throwable cause = e.getCause();
if (cause != null) {
logger.warn("An underlying internal error was not correctly rethrown by rethrowCause(): {}", cause.getMessage());
logger.debug("Internal error not rethrown by rethrowCause().", cause);
}
if (cause != null)
logger.warn("An underlying internal error was not correctly "
+ "rethrown by rethrowCause(): {}", cause.getMessage(), cause);
else
logger.warn("An underlying internal error was not correctly rethrown by rethrowCause().");
logger.warn("An underlying internal error was not correctly "
+ "rethrown by rethrowCause().");
throw e.getCauseAsGuacamoleException();
@@ -81,8 +81,7 @@ public class HashTokenSessionMap implements TokenSessionMap {
sessionTimeoutValue = environment.getProperty(API_SESSION_TIMEOUT, 60);
}
catch (GuacamoleException e) {
logger.error("Unable to read guacamole.properties: {}", e.getMessage());
logger.debug("Error while reading session timeout value.", e);
logger.error("Unable to read guacamole.properties: {}", e.getMessage(), e);
sessionTimeoutValue = 60;
}
@@ -69,8 +69,7 @@ public class InterceptedStreamMap<T extends Closeable> {
stream.close();
}
catch (IOException e) {
logger.warn("Unable to close intercepted stream: {}", e.getMessage());
logger.debug("I/O error prevented closure of intercepted stream.", e);
logger.warn("Unable to close intercepted stream: {}", e.getMessage(), e);
}
// Notify waiting threads that the stream has ended
@@ -130,8 +130,7 @@ public class OutputStreamInterceptingFilter
blob = BaseEncoding.base64().decode(data);
}
catch (IllegalArgumentException e) {
logger.warn("Received base64 data for intercepted stream was invalid.");
logger.debug("Decoding base64 data for intercepted stream failed.", e);
logger.warn("Received base64 data for intercepted stream was invalid.", e);
return null;
}
@@ -240,8 +240,7 @@ public abstract class GuacamoleWebSocketTunnelServlet extends WebSocketServlet {
tunnel = doConnect(tunnelRequest);
}
catch (GuacamoleException e) {
logger.error("Creation of WebSocket tunnel to guacd failed: {}", e.getMessage());
logger.debug("Error connecting WebSocket tunnel.", e);
logger.error("Creation of WebSocket tunnel to guacd failed: {}", e.getMessage(), e);
closeConnection(connection, e.getStatus().getGuacamoleStatusCode(),
e.getWebSocketCode());
return;
@@ -295,8 +294,7 @@ public abstract class GuacamoleWebSocketTunnelServlet extends WebSocketServlet {
// to pass within the WebSocket connection, logging
// each error appropriately.
catch (GuacamoleClientException e) {
logger.info("WebSocket connection terminated: {}", e.getMessage());
logger.debug("WebSocket connection terminated due to client error.", e);
logger.info("WebSocket connection terminated: {}", e.getMessage(), e);
closeConnection(connection, e.getStatus().getGuacamoleStatusCode(),
e.getWebSocketCode());
}
@@ -305,8 +303,7 @@ public abstract class GuacamoleWebSocketTunnelServlet extends WebSocketServlet {
closeConnection(connection, GuacamoleStatus.SUCCESS);
}
catch (GuacamoleException e) {
logger.error("Connection to guacd terminated abnormally: {}", e.getMessage());
logger.debug("Internal error during connection to guacd.", e);
logger.error("Connection to guacd terminated abnormally: {}", e.getMessage(), e);
closeConnection(connection, e.getStatus().getGuacamoleStatusCode(),
e.getWebSocketCode());
}
@@ -196,8 +196,7 @@ public abstract class GuacamoleWebSocketTunnelListener implements WebSocketListe
}
catch (GuacamoleException e) {
logger.error("Creation of WebSocket tunnel to guacd failed: {}", e.getMessage());
logger.debug("Error connecting WebSocket tunnel.", e);
logger.error("Creation of WebSocket tunnel to guacd failed: {}", e.getMessage(), e);
closeConnection(session, e.getStatus().getGuacamoleStatusCode(), e.getWebSocketCode());
return;
}
@@ -245,8 +244,7 @@ public abstract class GuacamoleWebSocketTunnelListener implements WebSocketListe
// to pass within the WebSocket connection, logging
// each error appropriately.
catch (GuacamoleClientException e) {
logger.info("WebSocket connection terminated: {}", e.getMessage());
logger.debug("WebSocket connection terminated due to client error.", e);
logger.info("WebSocket connection terminated: {}", e.getMessage(), e);
closeConnection(session, e.getStatus().getGuacamoleStatusCode(),
e.getWebSocketCode());
}
@@ -255,8 +253,7 @@ public abstract class GuacamoleWebSocketTunnelListener implements WebSocketListe
closeConnection(session, GuacamoleStatus.SUCCESS);
}
catch (GuacamoleException e) {
logger.error("Connection to guacd terminated abnormally: {}", e.getMessage());
logger.debug("Internal error during connection to guacd.", e);
logger.error("Connection to guacd terminated abnormally: {}", e.getMessage(), e);
closeConnection(session, e.getStatus().getGuacamoleStatusCode(),
e.getWebSocketCode());
}
@@ -268,8 +268,7 @@ public abstract class GuacamoleWebSocketTunnelServlet extends WebSocketServlet {
tunnel = doConnect(tunnelRequest);
}
catch (GuacamoleException e) {
logger.error("Creation of WebSocket tunnel to guacd failed: {}", e.getMessage());
logger.debug("Error connecting WebSocket tunnel.", e);
logger.error("Creation of WebSocket tunnel to guacd failed: {}", e.getMessage(), e);
closeConnection(outbound, e.getStatus().getGuacamoleStatusCode(),
e.getWebSocketCode());
return;
@@ -323,8 +322,7 @@ public abstract class GuacamoleWebSocketTunnelServlet extends WebSocketServlet {
// to pass within the WebSocket connection, logging
// each error appropriately.
catch (GuacamoleClientException e) {
logger.info("WebSocket connection terminated: {}", e.getMessage());
logger.debug("WebSocket connection terminated due to client error.", e);
logger.info("WebSocket connection terminated: {}", e.getMessage(), e);
closeConnection(outbound, e.getStatus().getGuacamoleStatusCode(),
e.getWebSocketCode());
}
@@ -333,8 +331,7 @@ public abstract class GuacamoleWebSocketTunnelServlet extends WebSocketServlet {
closeConnection(outbound, GuacamoleStatus.SUCCESS);
}
catch (GuacamoleException e) {
logger.error("Connection to guacd terminated abnormally: {}", e.getMessage());
logger.debug("Internal error during connection to guacd.", e);
logger.error("Connection to guacd terminated abnormally: {}", e.getMessage(), e);
closeConnection(outbound, e.getStatus().getGuacamoleStatusCode(),
e.getWebSocketCode());
}