From 0509e52c1773f47a0f9b73a747e7cd91a4cada8c Mon Sep 17 00:00:00 2001 From: Rajiv Date: Wed, 4 Apr 2018 16:43:13 +0530 Subject: [PATCH 1/8] Fix for NPE when updating to byteman 3.0.12/4.0.2 We were holding a weak reference to ModuleClassloader. If the MCL is collected, createLoader would return null. New version of byteman has some changes that triggered the situation where it would call createLoader after it was GC'ed, causing an NPE. Changed the code to use a softreference (so it won't be collected) so frequently. Also made a fix to create a new MCL if the existing MCL was collected. --- .../jinsight/ContextualModuleLoader.java | 38 ++++++++++++++++--- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/src/main/java/ai/apptuit/metrics/jinsight/ContextualModuleLoader.java b/src/main/java/ai/apptuit/metrics/jinsight/ContextualModuleLoader.java index d79735c..76ae7a6 100644 --- a/src/main/java/ai/apptuit/metrics/jinsight/ContextualModuleLoader.java +++ b/src/main/java/ai/apptuit/metrics/jinsight/ContextualModuleLoader.java @@ -17,8 +17,10 @@ package ai.apptuit.metrics.jinsight; import ai.apptuit.metrics.jinsight.ContextualModuleLoader.ModuleClassLoader; -import java.lang.ref.WeakReference; +import java.lang.ref.SoftReference; import java.net.URLClassLoader; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.Collections; import java.util.Map; import java.util.WeakHashMap; @@ -30,7 +32,7 @@ */ public class ContextualModuleLoader implements ModuleSystem { - private final Map> moduleLoaders = Collections + private final Map> moduleLoaders = Collections .synchronizedMap(new WeakHashMap<>()); public void initialize(String args) { @@ -44,9 +46,35 @@ public ModuleClassLoader createLoader(ClassLoader triggerClassLoader, String[] i throw new IllegalArgumentException("IMPORTs are not supported"); } - WeakReference reference = moduleLoaders - .computeIfAbsent(triggerClassLoader, cl -> new WeakReference<>(new ModuleClassLoader(cl))); - return reference.get(); + ModuleClassLoader moduleClassLoader = getModuleClassLoader(triggerClassLoader); + if (moduleClassLoader != null) { + return moduleClassLoader; + } + synchronized (moduleLoaders) { + //Double check idiom + moduleClassLoader = getModuleClassLoader(triggerClassLoader); + if (moduleClassLoader != null) { + return moduleClassLoader; + } + moduleClassLoader = AccessController.doPrivileged( + (PrivilegedAction) () -> new ModuleClassLoader(triggerClassLoader)); + //Since there are no strong references to moduleClassloader, it might be collected + //We should probably hold a PhantomReference to moduleClassloader + //that is collected only after the triggerClassloader is collected + moduleLoaders.put(triggerClassLoader, new SoftReference<>(moduleClassLoader)); + return moduleClassLoader; + } + } + + private ModuleClassLoader getModuleClassLoader(ClassLoader triggerClassLoader) { + SoftReference reference = moduleLoaders.get(triggerClassLoader); + if (reference != null) { + ModuleClassLoader moduleClassLoader = reference.get(); + if (moduleClassLoader != null) { + return moduleClassLoader; + } + } + return null; } public void destroyLoader(ModuleClassLoader helperLoader) { From 040984f43c1a3b899c1989a92587bbfdb12a3468 Mon Sep 17 00:00:00 2001 From: Rajiv Date: Thu, 5 Apr 2018 09:19:33 +0530 Subject: [PATCH 2/8] Update to latest codacy --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c85903c..22494dd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -44,7 +44,7 @@ cache: before_install: - sudo apt-get install jq - - wget -O ~/.codacy/reporter/codacy-reporter-latest.jar https://oss.sonatype.org/service/local/repositories/releases/content/com/codacy/codacy-coverage-reporter/2.0.2/codacy-coverage-reporter-2.0.2-assembly.jar + - wget -O ~/.codacy/reporter/codacy-reporter-latest.jar https://oss.sonatype.org/service/local/repositories/releases/content/com/codacy/codacy-coverage-reporter/4.0.0/codacy-coverage-reporter-4.0.0-assembly.jar - | wget -O ~/.rpmlint/rpmlint-1.9.tar.gz https://github.com/rpm-software-management/rpmlint/archive/rpmlint-1.9.tar.gz; tar xvfz ~/.rpmlint/rpmlint-1.9.tar.gz -C ~/.rpmlint; From 90f0627baa1fc398b4e02838ab2ca043c602bf04 Mon Sep 17 00:00:00 2001 From: Rajiv Date: Thu, 5 Apr 2018 14:02:12 +0530 Subject: [PATCH 3/8] Made the reporter frequency configurable Fixes #11 --- pkg/common/jinsight-config.properties | 1 + .../ai/apptuit/metrics/jinsight/Agent.java | 6 +- .../metrics/jinsight/ConfigService.java | 65 +++++++++++---- .../metrics/jinsight/RegistryService.java | 2 +- .../metrics/jinsight/ConfigServiceTest.java | 81 ++++++++++++++++++- .../metrics/jinsight/RegistryServiceTest.java | 13 ++- 6 files changed, 144 insertions(+), 24 deletions(-) diff --git a/pkg/common/jinsight-config.properties b/pkg/common/jinsight-config.properties index 5344442..c4440e6 100644 --- a/pkg/common/jinsight-config.properties +++ b/pkg/common/jinsight-config.properties @@ -3,3 +3,4 @@ apptuit.reporting_mode=XCOLLECTOR #apptuit.reporting_mode=API_PUT #apptuit.access_token=PASTE_ACCESS_TOKEN_HERE #global_tags=env:prod, data_center:us-east, micro_service:login +#reporting_frequency=15s \ No newline at end of file diff --git a/src/main/java/ai/apptuit/metrics/jinsight/Agent.java b/src/main/java/ai/apptuit/metrics/jinsight/Agent.java index 7677df6..8bdc90c 100644 --- a/src/main/java/ai/apptuit/metrics/jinsight/Agent.java +++ b/src/main/java/ai/apptuit/metrics/jinsight/Agent.java @@ -97,8 +97,10 @@ private static void main0(String agentArgs, Instrumentation instrumentation, instrumentation.appendToBootstrapClassLoaderSearch(bytemanJar); delegate.accept(agentArgs, instrumentation); - LOGGER.info("JInsight v["+ConfigService.getInstance().getAgentVersion() - + "] initialized. Reporting mode: "+ConfigService.getInstance().getReportingMode()); + ConfigService configService = ConfigService.getInstance(); + LOGGER.info("JInsight v["+ configService.getAgentVersion() + "] initialized. " + + "Reporting via: ["+ configService.getReportingMode() +"] " + + "every ["+ (configService.getReportingFrequency()/1000) + "] seconds"); } private static JarFile createBytemanJar() { diff --git a/src/main/java/ai/apptuit/metrics/jinsight/ConfigService.java b/src/main/java/ai/apptuit/metrics/jinsight/ConfigService.java index 530f19f..40423e8 100644 --- a/src/main/java/ai/apptuit/metrics/jinsight/ConfigService.java +++ b/src/main/java/ai/apptuit/metrics/jinsight/ConfigService.java @@ -27,6 +27,8 @@ import java.net.MalformedURLException; import java.net.URL; import java.net.UnknownHostException; +import java.time.Duration; +import java.time.format.DateTimeParseException; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; @@ -44,26 +46,27 @@ */ public class ConfigService { + static final String REPORTING_MODE_PROPERTY_NAME = "apptuit.reporting_mode"; + static final String REPORTING_FREQ_PROPERTY_NAME = "reporting_frequency"; private static final Logger LOGGER = Logger.getLogger(ConfigService.class.getName()); - private static final String CONFIG_SYSTEM_PROPERTY = "jinsight.config"; private static final String DEFAULT_CONFIG_FILE_NAME = "jinsight-config.properties"; - private static final String ACCESS_TOKEN_PROPERTY_NAME = "apptuit.access_token"; private static final String API_ENDPOINT_PROPERTY_NAME = "apptuit.api_url"; - private static final String REPORTING_MODE_PROPERTY_NAME = "apptuit.reporting_mode"; private static final String GLOBAL_TAGS_PROPERTY_NAME = "global_tags"; private static final String HOST_TAG_NAME = "host"; private static final File JINSIGHT_HOME = new File(System.getProperty("user.home"), ".jinsight"); private static final File UNIX_JINSIGHT_CONF_DIR = new File("/etc/jinsight/"); private static final ReportingMode DEFAULT_REPORTING_MODE = ReportingMode.API_PUT; + private static final String DEFAULT_REPORTING_FREQUENCY = "15s"; private static volatile ConfigService singleton = null; private final String apiToken; private final URL apiUrl; private final ReportingMode reportingMode; + private final long reportingFrequencyMillis; private final Map loadedGlobalTags = new HashMap<>(); private final String agentVersion; private Map globalTags = null; @@ -71,18 +74,8 @@ public class ConfigService { ConfigService(Properties config) throws ConfigurationException { this.apiToken = config.getProperty(ACCESS_TOKEN_PROPERTY_NAME); - String configMode = config.getProperty(REPORTING_MODE_PROPERTY_NAME); - ReportingMode mode = null; - if (configMode != null) { - try { - mode = ReportingMode.valueOf(configMode.trim().toUpperCase()); - } catch (IllegalArgumentException e) { - LOGGER.severe("Un-supported reporting mode [" + configMode + "]. " - + "Using default reporting mode: [" + DEFAULT_REPORTING_MODE + "]"); - LOGGER.log(Level.FINE, e.toString(), e); - } - } - reportingMode = (mode == null) ? DEFAULT_REPORTING_MODE : mode; + this.reportingMode = readReportingMode(config); + this.reportingFrequencyMillis = readReportingFrequency(config); if (apiToken == null && reportingMode == ReportingMode.API_PUT) { throw new ConfigurationException( @@ -101,7 +94,7 @@ public class ConfigService { } } this.apiUrl = url; - this.agentVersion=loadAgentVersion(); + this.agentVersion = loadAgentVersion(); loadGlobalTags(config); @@ -173,6 +166,42 @@ private static Properties loadProperties(File configFilePath) throws IOException return config; } + private ReportingMode readReportingMode(Properties config) { + String configMode = config.getProperty(REPORTING_MODE_PROPERTY_NAME); + if (configMode != null) { + try { + return ReportingMode.valueOf(configMode.trim().toUpperCase()); + } catch (IllegalArgumentException e) { + LOGGER.severe("Un-supported reporting mode [" + configMode + "]. " + + "Using default reporting mode: [" + DEFAULT_REPORTING_MODE + "]"); + LOGGER.log(Level.FINE, e.toString(), e); + } + } + return DEFAULT_REPORTING_MODE; + } + + private long readReportingFrequency(Properties config) { + String configFreq = config.getProperty(REPORTING_FREQ_PROPERTY_NAME); + if (configFreq != null) { + try { + return parseDuration(configFreq); + } catch (DateTimeParseException | IllegalArgumentException e) { + LOGGER.severe("Invalid reporting frequency [" + configFreq + "]. " + + "Using default reporting frequency: [" + DEFAULT_REPORTING_FREQUENCY + "]"); + LOGGER.log(Level.FINE, e.toString(), e); + } + } + return parseDuration(DEFAULT_REPORTING_FREQUENCY); + } + + private long parseDuration(String durationString) { + long millis = Duration.parse("PT" + durationString.trim()).toMillis(); + if (millis < 0) { + throw new IllegalArgumentException("Frequency cannot be negative"); + } + return millis; + } + private void loadGlobalTags(Properties config) throws ConfigurationException { String tagsString = config.getProperty(GLOBAL_TAGS_PROPERTY_NAME); if (tagsString != null) { @@ -233,6 +262,10 @@ ReportingMode getReportingMode() { return reportingMode; } + long getReportingFrequency() { + return reportingFrequencyMillis; + } + public String getAgentVersion() { return agentVersion; } diff --git a/src/main/java/ai/apptuit/metrics/jinsight/RegistryService.java b/src/main/java/ai/apptuit/metrics/jinsight/RegistryService.java index 9235c33..ddf6a88 100644 --- a/src/main/java/ai/apptuit/metrics/jinsight/RegistryService.java +++ b/src/main/java/ai/apptuit/metrics/jinsight/RegistryService.java @@ -48,7 +48,7 @@ private RegistryService() { ScheduledReporter reporter = createReporter(factory, configService.getGlobalTags(), configService.getApiToken(), configService.getApiUrl(), mode); - reporter.start(5, TimeUnit.SECONDS); + reporter.start(configService.getReportingFrequency(), TimeUnit.MILLISECONDS); registry.registerAll(new JvmMetricSet()); } diff --git a/src/test/java/ai/apptuit/metrics/jinsight/ConfigServiceTest.java b/src/test/java/ai/apptuit/metrics/jinsight/ConfigServiceTest.java index b81f705..b33659e 100644 --- a/src/test/java/ai/apptuit/metrics/jinsight/ConfigServiceTest.java +++ b/src/test/java/ai/apptuit/metrics/jinsight/ConfigServiceTest.java @@ -16,6 +16,8 @@ package ai.apptuit.metrics.jinsight; +import static ai.apptuit.metrics.jinsight.ConfigService.REPORTING_FREQ_PROPERTY_NAME; +import static ai.apptuit.metrics.jinsight.ConfigService.REPORTING_MODE_PROPERTY_NAME; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; @@ -58,7 +60,7 @@ public void testGetReportingModeDefault() throws Exception { @Test public void testGetReportingModeJunk() throws Exception { Properties p = getDefaultConfigProperties(); - p.setProperty("apptuit.reporting_mode", "junk"); + p.setProperty(REPORTING_MODE_PROPERTY_NAME, "junk"); ConfigService configService = new ConfigService(p); assertEquals(ReportingMode.API_PUT, configService.getReportingMode()); } @@ -66,7 +68,7 @@ public void testGetReportingModeJunk() throws Exception { @Test public void testGetReportingModeNoOp() throws Exception { Properties p = new Properties(); - p.setProperty("apptuit.reporting_mode", "NO_OP"); + p.setProperty(REPORTING_MODE_PROPERTY_NAME, "NO_OP"); ConfigService configService = new ConfigService(p); assertEquals(ReportingMode.NO_OP, configService.getReportingMode()); } @@ -74,11 +76,82 @@ public void testGetReportingModeNoOp() throws Exception { @Test public void testGetReportingModeNoOpCaseInsensitive() throws Exception { Properties p = new Properties(); - p.setProperty("apptuit.reporting_mode", "No_Op"); + p.setProperty(REPORTING_MODE_PROPERTY_NAME, "No_Op"); ConfigService configService = new ConfigService(p); assertEquals(ReportingMode.NO_OP, configService.getReportingMode()); } + @Test + public void testDefaultReportingFreq() throws Exception { + Properties p = getDefaultConfigProperties(); + ConfigService configService = new ConfigService(p); + assertEquals(15000L, configService.getReportingFrequency()); + } + + @Test + public void testDefaultReportingFreqOnError() throws Exception { + Properties p = getDefaultConfigProperties(); + p.setProperty(REPORTING_FREQ_PROPERTY_NAME, "BLEEP"); + ConfigService configService = new ConfigService(p); + assertEquals(15000L, configService.getReportingFrequency()); + } + + @Test + public void testDefaultReportingFreqSeconds() throws Exception { + Properties p = getDefaultConfigProperties(); + p.setProperty(REPORTING_FREQ_PROPERTY_NAME, "13S"); + ConfigService configService = new ConfigService(p); + assertEquals(13000L, configService.getReportingFrequency()); + } + + @Test + public void testReportingFreqSecondsLowercase() throws Exception { + Properties p = getDefaultConfigProperties(); + p.setProperty(REPORTING_FREQ_PROPERTY_NAME, "13s"); + ConfigService configService = new ConfigService(p); + assertEquals(13000L, configService.getReportingFrequency()); + } + + @Test + public void testReportingFreqPartialSeconds() throws Exception { + Properties p = getDefaultConfigProperties(); + p.setProperty(REPORTING_FREQ_PROPERTY_NAME, "13.7s"); + ConfigService configService = new ConfigService(p); + assertEquals(13700L, configService.getReportingFrequency()); + } + + @Test + public void testDefaultReportingFreqNegativeSeconds() throws Exception { + Properties p = getDefaultConfigProperties(); + p.setProperty(REPORTING_FREQ_PROPERTY_NAME, "-13.7s"); + ConfigService configService = new ConfigService(p); + assertEquals(15000L, configService.getReportingFrequency()); + } + + @Test + public void testReportingFreqMins() throws Exception { + Properties p = getDefaultConfigProperties(); + p.setProperty(REPORTING_FREQ_PROPERTY_NAME, "1M"); + ConfigService configService = new ConfigService(p); + assertEquals(60000L, configService.getReportingFrequency()); + } + + @Test + public void testReportingFreqPartialMins() throws Exception { + Properties p = getDefaultConfigProperties(); + p.setProperty(REPORTING_FREQ_PROPERTY_NAME, "1.5M"); + ConfigService configService = new ConfigService(p); + assertEquals(15000L, configService.getReportingFrequency()); + } + + @Test + public void testReportingFreqMinsAndSeconds() throws Exception { + Properties p = getDefaultConfigProperties(); + p.setProperty(REPORTING_FREQ_PROPERTY_NAME, "17M-13.7s"); + ConfigService configService = new ConfigService(p); + assertEquals((17*60*1000-13700), configService.getReportingFrequency()); + } + @Test public void testGetApiUrl() throws Exception { Properties p = getDefaultConfigProperties(); @@ -100,7 +173,7 @@ public void testBadApiUrl() throws Exception { @Test public void testGetTagsMissing() throws Exception { Properties p = new Properties(); - p.setProperty("apptuit.reporting_mode", "xcollector"); + p.setProperty(REPORTING_MODE_PROPERTY_NAME, "xcollector"); ConfigService configService = new ConfigService(p); Map globalTags = configService.getGlobalTags(); assertEquals(globalTags, Collections.emptyMap()); diff --git a/src/test/java/ai/apptuit/metrics/jinsight/RegistryServiceTest.java b/src/test/java/ai/apptuit/metrics/jinsight/RegistryServiceTest.java index 33bd1bb..c965c0f 100644 --- a/src/test/java/ai/apptuit/metrics/jinsight/RegistryServiceTest.java +++ b/src/test/java/ai/apptuit/metrics/jinsight/RegistryServiceTest.java @@ -33,6 +33,7 @@ import java.util.Map; import java.util.Properties; import java.util.UUID; +import java.util.concurrent.TimeUnit; import org.junit.Before; import org.junit.Test; @@ -44,11 +45,13 @@ public class RegistryServiceTest { private ApptuitReporterFactory mockFactory; private ConfigService mockConfigService; + private ScheduledReporter mockReporter; @Before public void setUp() throws Exception { mockFactory = mock(ApptuitReporterFactory.class); - when(mockFactory.build(any(MetricRegistry.class))).thenReturn(mock(ScheduledReporter.class)); + mockReporter = mock(ScheduledReporter.class); + when(mockFactory.build(any(MetricRegistry.class))).thenReturn(mockReporter); mockConfigService = mock(ConfigService.class); when(mockConfigService.getGlobalTags()).thenReturn(ConfigService.getInstance().getGlobalTags()); } @@ -127,4 +130,12 @@ public void testReportingModeNoOp() throws Exception { verify(mockFactory).setReportingMode(ReportingMode.NO_OP); } + + @Test + public void testReportingFrequency() throws Exception { + long freq = 99999L; + when(mockConfigService.getReportingFrequency()).thenReturn(freq); + new RegistryService(mockConfigService, mockFactory); + verify(mockReporter).start(freq, TimeUnit.MILLISECONDS); + } } From fe553fc1de44b1a7742b997001d5af3e8e4508dc Mon Sep 17 00:00:00 2001 From: Rajiv Date: Thu, 5 Apr 2018 14:03:29 +0530 Subject: [PATCH 4/8] Get latest metrics-apptuit --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 27becfe..5f61cbb 100644 --- a/pom.xml +++ b/pom.xml @@ -98,7 +98,7 @@ limitations under the License. 0.8.0 3.0.11 3.2.6 - 0.7.1 + 0.7.2 false From 5961b8250ae8a40afcfda0a59e904e684e07d8c8 Mon Sep 17 00:00:00 2001 From: Rajiv Date: Thu, 5 Apr 2018 14:44:55 +0530 Subject: [PATCH 5/8] Updated file paths to reflect the deb/rpm installation directories --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9897471..9df525e 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ of your choice: apptuit.ai, Prometheus, Graphite etc. Instrumenting a JVM with JInsight Java Agent is refreshingly simple: 1. Update your java command line to include the jinsight options: -`java -javaagent:/var/lib/jinsight/jinsight-latest.jar -Djinsight.config=/etc/jinsight/jinsight-config.properties -cp helloworld.jar HelloWorld` +`java -javaagent:/usr/share/java/jinsight.jar -Djinsight.config=/etc/jinsight/jinsight-config.properties -cp helloworld.jar HelloWorld` 2. Save API-TOKEN, global tags, frequency of reporting data etc in the `jinsight-config.properties` file 3. (Re)start your JVM From 03f5adbbe1e7a64e065ed53e934f52d118bc58a9 Mon Sep 17 00:00:00 2001 From: Rajiv Date: Mon, 9 Apr 2018 17:10:42 +0530 Subject: [PATCH 6/8] Reformatting - Make checkstyle happy --- src/main/java/ai/apptuit/metrics/jinsight/Agent.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/ai/apptuit/metrics/jinsight/Agent.java b/src/main/java/ai/apptuit/metrics/jinsight/Agent.java index 8bdc90c..2f8a652 100644 --- a/src/main/java/ai/apptuit/metrics/jinsight/Agent.java +++ b/src/main/java/ai/apptuit/metrics/jinsight/Agent.java @@ -98,9 +98,9 @@ private static void main0(String agentArgs, Instrumentation instrumentation, instrumentation.appendToBootstrapClassLoaderSearch(bytemanJar); delegate.accept(agentArgs, instrumentation); ConfigService configService = ConfigService.getInstance(); - LOGGER.info("JInsight v["+ configService.getAgentVersion() + "] initialized. " - + "Reporting via: ["+ configService.getReportingMode() +"] " - + "every ["+ (configService.getReportingFrequency()/1000) + "] seconds"); + LOGGER.info("JInsight v[" + configService.getAgentVersion() + "] initialized. " + + "Reporting via: [" + configService.getReportingMode() + "] " + + "every [" + (configService.getReportingFrequency() / 1000) + "] seconds"); } private static JarFile createBytemanJar() { From 49f7ed38735715c8e2e57cf439300108a489aa35 Mon Sep 17 00:00:00 2001 From: Rajiv Date: Mon, 9 Apr 2018 17:14:21 +0530 Subject: [PATCH 7/8] Update to latest dependencies --- pom.xml | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index 5f61cbb..0e7e3af 100644 --- a/pom.xml +++ b/pom.xml @@ -58,6 +58,15 @@ limitations under the License. jinsight-bintray https://dl.bintray.com/apptuitai/maven + @@ -95,7 +104,7 @@ limitations under the License. 4.1.15.Final 2.20.1 4.12 - 0.8.0 + 0.8.1 3.0.11 3.2.6 0.7.2 @@ -142,7 +151,7 @@ limitations under the License. com.h2database h2 - 1.4.196 + 1.4.197 test @@ -154,19 +163,19 @@ limitations under the License. org.eclipse.jetty jetty-servlet - 9.4.8.v20171121 + 9.4.9.v20180320 provided org.apache.tomcat.embed tomcat-embed-core - 8.5.27 + 8.5.28 provided org.apache.tomcat.embed tomcat-embed-jasper - 8.5.27 + 8.5.28 provided From 2d8c597a6c1c147568bd7756eb66b30084a99f89 Mon Sep 17 00:00:00 2001 From: Rajiv Date: Tue, 10 Apr 2018 11:41:49 +0530 Subject: [PATCH 8/8] Update to latest Byteman --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index 0e7e3af..5ceb300 100644 --- a/pom.xml +++ b/pom.xml @@ -105,6 +105,7 @@ limitations under the License. 2.20.1 4.12 0.8.1 + 4.0.2 3.0.11 3.2.6 0.7.2