From d842b96425bf1c42ef7d8b259c4e86949cd58b06 Mon Sep 17 00:00:00 2001 From: Cristian Ciutea Date: Mon, 1 Aug 2022 11:26:10 +0200 Subject: [PATCH] improve error handling (#126) --- .../org/newrelic/nrjmx/v2/InternalStats.java | 34 +++++++++-------- .../org/newrelic/nrjmx/v2/JMXFetcher.java | 37 +++++++++++++------ 2 files changed, 44 insertions(+), 27 deletions(-) diff --git a/src/main/java/org/newrelic/nrjmx/v2/InternalStats.java b/src/main/java/org/newrelic/nrjmx/v2/InternalStats.java index 56455d1..4f3a832 100644 --- a/src/main/java/org/newrelic/nrjmx/v2/InternalStats.java +++ b/src/main/java/org/newrelic/nrjmx/v2/InternalStats.java @@ -39,37 +39,41 @@ public InternalStats(long maxSize) { * Records a new InternalStat and returns it for attaching more data if required. * * @param statType String name of the stat. - * * @return InternalStat new registered stat to add data to it. */ public InternalStat record(String statType) { - if (stats.size() >= maxSize) { - stats.remove(0); - } + synchronized (stats) { + if (stats.size() >= maxSize) { + stats.remove(0); + } - InternalStat stat = new InternalStat() - .setStartTimestamp(System.currentTimeMillis()) - .setMilliseconds((double)System.nanoTime() / 1000000.0) - .setStatType(statType); - stats.add(stat); - return stat; + InternalStat stat = new InternalStat() + .setStartTimestamp(System.currentTimeMillis()) + .setMilliseconds((double) System.nanoTime() / 1000000.0) + .setStatType(statType); + stats.add(stat); + return stat; + } } /** * Returns all the collected stats and clear them. - ** + * + * * @return List returns all collected internal stats. */ public List getStats() { - List stats = this.stats; - this.stats = new ArrayList<>(); - return stats; + synchronized (this.stats) { + List stats = new ArrayList<>(this.stats); + this.stats = new ArrayList<>(); + return stats; + } } /** * Calculate the elapsed ms with .3f precision since the stat was recorded and attach it to the stat. */ public static void setElapsedMs(InternalStat internalStat) { - internalStat.setMilliseconds((double)System.nanoTime() / 1000000.0 - internalStat.milliseconds); + internalStat.setMilliseconds((double) System.nanoTime() / 1000000.0 - internalStat.milliseconds); } } diff --git a/src/main/java/org/newrelic/nrjmx/v2/JMXFetcher.java b/src/main/java/org/newrelic/nrjmx/v2/JMXFetcher.java index a57c118..2241068 100644 --- a/src/main/java/org/newrelic/nrjmx/v2/JMXFetcher.java +++ b/src/main/java/org/newrelic/nrjmx/v2/JMXFetcher.java @@ -19,7 +19,6 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.math.BigDecimal; -import java.rmi.ConnectException; import java.text.DateFormat; import java.util.*; import java.util.concurrent.*; @@ -134,6 +133,10 @@ public void disconnect(long timeoutMs) throws JMXError, JMXConnectionError { * @throws JMXConnectionError JMX connection related exception */ public void disconnect() throws JMXConnectionError { + if (Thread.interrupted()) { + return; + } + if (this.connector == null) { throw new JMXConnectionError() .setMessage("cannot disconnect, connection to JMX endpoint is not established"); @@ -226,16 +229,18 @@ private Set queryMBeans(ObjectName objectName) throws JMXConnect } return result; - } catch (ConnectException ce) { + } catch (JMXConnectionError je) { + throw je; + } catch (IOException io) { disconnect(); - String message = String.format("can't connect to JMX server, error: '%s'", ce.getMessage()); + String message = String.format("problem occurred when talking to the JMX server while querying mBeans, error: '%s'", io.getMessage()); throw new JMXConnectionError(message); - } catch (IOException ioe) { + } catch (Exception e) { throw new JMXError() .setMessage("can't get beans for query: " + objectName) - .setCauseMessage(ioe.getMessage()) - .setStacktrace(getStackTrace(ioe)); + .setCauseMessage(e.getMessage()) + .setStacktrace(getStackTrace(e)); } finally { if (internalStat != null) { InternalStats.setElapsedMs(internalStat); @@ -291,12 +296,14 @@ private List getMBeanAttributeNames(ObjectName objectName) throws JMXCon if (internalStat != null) { internalStat.setSuccessful(true); } - } catch (ConnectException ce) { + } catch (JMXConnectionError je) { + throw je; + } catch (IOException io) { disconnect(); - String message = String.format("can't connect to JMX server, error: '%s'", ce.getMessage()); + String message = String.format("problem occurred when talking to the JMX server while requesting mBean info, error: '%s'", io.getMessage()); throw new JMXConnectionError(message); - } catch (InstanceNotFoundException | IntrospectionException | ReflectionException | IOException e) { + } catch (InstanceNotFoundException | IntrospectionException | ReflectionException e) { throw new JMXError() .setMessage("can't find mBean: " + objectName) .setCauseMessage(e.getMessage()) @@ -386,10 +393,12 @@ private void getMBeanAttributes(ObjectName objectName, List attributes, if (internalStat != null) { internalStat.setSuccessful(true); } - } catch (ConnectException ce) { + } catch (JMXConnectionError je) { + throw je; + } catch (IOException io) { disconnect(); - String message = String.format("can't connect to JMX server, error: '%s'", ce.getMessage()); + String message = String.format("problem occurred when talking to the JMX server while requesting attributes, error: '%s'", io.getMessage()); throw new JMXConnectionError(message); } catch (Exception e) { throw new JMXError() @@ -525,6 +534,7 @@ private ObjectName getObjectName(String mBeanName) throws JMXError { * @throws JMXConnectionError JMX connection related exception */ private T withTimeout(Future future, long timeoutMs) throws JMXError, JMXConnectionError { + try { if (timeoutMs <= 0) { return future.get(); @@ -551,6 +561,8 @@ private T withTimeout(Future future, long timeoutMs) throws JMXError, JMX throw new JMXError() .setMessage("failed to execute operation, error: " + e.getMessage()) .setStacktrace(getStackTrace(e)); + } finally { + future.cancel(true); } } @@ -637,7 +649,7 @@ public List getInternalStats() throws JMXError { * @return MBeanServerConnection the connection to the JMX endpoint * @throws JMXConnectionError JMX connection related Exception */ - private MBeanServerConnection getConnection() throws JMXConnectionError, JMXError { + private MBeanServerConnection getConnection() throws JMXConnectionError { if (jmxConfig == null) { throw new JMXConnectionError("failed to get connection to JMX server: configuration not provided"); } @@ -712,6 +724,7 @@ private static Map buildConnectionEnvConfig(JMXConfig jmxConfig) p.put("javax.net.ssl.trustStorePassword", jmxConfig.trustStorePassword); connectionEnv.put("com.sun.jndi.rmi.factory.socket", new SslRMIClientSocketFactory()); } + return connectionEnv; }