diff --git a/.idea/runConfigurations/Agent_ONLY_Load_with_JavaAgent.xml b/.idea/runConfigurations/Agent_ONLY_Load_with_JavaAgent.xml new file mode 100644 index 0000000..f1a0cd5 --- /dev/null +++ b/.idea/runConfigurations/Agent_ONLY_Load_with_JavaAgent.xml @@ -0,0 +1,16 @@ + + + + \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ad69fc..453adb5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ # main - Unreleased - **[FEATURE]**: plugin: Add plugin for Otel [#87](https://github.com/intergral/deep/pull/87) [@Umaaz](https://github.com/Umaaz) - **[FEATURE]**: traces: Add apis for creating traces from tracepoints [#87](https://github.com/intergral/deep/pull/87) [@Umaaz](https://github.com/Umaaz) + - **[BUGFIX]**: fix issue with SPI loading failing [#92](https://github.com/intergral/deep/pull/92) [@Umaaz](https://github.com/Umaaz) + - **[BUGFIX]**: fix issue with method entry tracepoings [#91](https://github.com/intergral/deep/pull/91) [@Umaaz](https://github.com/Umaaz) # 1.1.4 (15/12/2023) - **[CHANGE]**: plugin: Add new API for registering plugins [#84](https://github.com/intergral/deep/pull/84) [@Umaaz](https://github.com/Umaaz) diff --git a/agent/src/main/java/com/intergral/deep/agent/resource/SpiUtil.java b/agent/src/main/java/com/intergral/deep/agent/resource/SpiUtil.java index 36fff82..0498c73 100644 --- a/agent/src/main/java/com/intergral/deep/agent/resource/SpiUtil.java +++ b/agent/src/main/java/com/intergral/deep/agent/resource/SpiUtil.java @@ -8,14 +8,19 @@ import com.intergral.deep.agent.api.spi.Ordered; import java.util.ArrayList; import java.util.Comparator; +import java.util.Iterator; import java.util.List; import java.util.ServiceLoader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Utilities to load SPI services. */ public final class SpiUtil { + private static final Logger LOGGER = LoggerFactory.getLogger(SpiUtil.class); + private SpiUtil() { } @@ -28,8 +33,15 @@ public static List loadOrdered(Class spiClass, static List loadOrdered( Class spiClass, ClassLoader serviceClassLoader, ServiceLoaderFinder serviceLoaderFinder) { List result = new ArrayList<>(); - for (T service : serviceLoaderFinder.load(spiClass, serviceClassLoader)) { - result.add(service); + final Iterator iterator = serviceLoaderFinder.load(spiClass, serviceClassLoader).iterator(); + while (iterator.hasNext()) { + try { + result.add(iterator.next()); + } catch (Throwable t) { + // WARNING - exception from this will have the wrong stack trace + // the error will come from 'hasNext' not 'next' + LOGGER.error("Cannot load provider.", t); + } } result.sort(Comparator.comparing(Ordered::order)); return result; diff --git a/agent/src/test/java/com/intergral/deep/agent/resource/ITestProvider.java b/agent/src/test/java/com/intergral/deep/agent/resource/ITestProvider.java new file mode 100644 index 0000000..90a64f2 --- /dev/null +++ b/agent/src/test/java/com/intergral/deep/agent/resource/ITestProvider.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2023 Intergral GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.intergral.deep.agent.resource; + +import com.intergral.deep.agent.api.spi.Ordered; + +/** + * This type is used to test SPI loading. + */ +public interface ITestProvider extends Ordered { + +} diff --git a/agent/src/test/java/com/intergral/deep/agent/resource/SpiUtilTest.java b/agent/src/test/java/com/intergral/deep/agent/resource/SpiUtilTest.java index 8d5062c..8d8a552 100644 --- a/agent/src/test/java/com/intergral/deep/agent/resource/SpiUtilTest.java +++ b/agent/src/test/java/com/intergral/deep/agent/resource/SpiUtilTest.java @@ -46,4 +46,10 @@ void loadsOrderedSpi() { assertEquals(3, loadedSpi.size()); } + + @Test + void canHandleConfigErrors() { + final List ts = SpiUtil.loadOrdered(ITestProvider.class, getClass().getClassLoader()); + assertEquals(1, ts.size()); + } } \ No newline at end of file diff --git a/agent/src/test/java/com/intergral/deep/agent/resource/TestProvider.java b/agent/src/test/java/com/intergral/deep/agent/resource/TestProvider.java new file mode 100644 index 0000000..1579137 --- /dev/null +++ b/agent/src/test/java/com/intergral/deep/agent/resource/TestProvider.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2023 Intergral GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.intergral.deep.agent.resource; + + +/** + * This type is used to test SPI loading. + */ +public class TestProvider implements ITestProvider { + +} diff --git a/agent/src/test/resources/META-INF/services/com.intergral.deep.agent.resource.ITestProvider b/agent/src/test/resources/META-INF/services/com.intergral.deep.agent.resource.ITestProvider new file mode 100644 index 0000000..514ec52 --- /dev/null +++ b/agent/src/test/resources/META-INF/services/com.intergral.deep.agent.resource.ITestProvider @@ -0,0 +1,19 @@ +# +# Copyright (C) 2024 Intergral GmbH +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# + +com.intergral.deep.agent.resource.TestProvider +com.intergral.deep.agent.test.NotExists \ No newline at end of file diff --git a/examples/agent-only-load/.gitignore b/examples/agent-only-load/.gitignore new file mode 100644 index 0000000..5ff6309 --- /dev/null +++ b/examples/agent-only-load/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/examples/agent-only-load/pom.xml b/examples/agent-only-load/pom.xml new file mode 100644 index 0000000..4dfc3c4 --- /dev/null +++ b/examples/agent-only-load/pom.xml @@ -0,0 +1,44 @@ + + + + + 4.0.0 + + com.intergral.deep.examples + examples + 1.0-SNAPSHOT + ../pom.xml + + + agent-only-load + Agent Load + This example uses the agent load (-javaagent) to load the deep agent. It therefore + has no dependencies of code related to deep. + + + + 8 + 8 + UTF-8 + + + + + \ No newline at end of file diff --git a/examples/agent-only-load/src/main/java/com/intergral/deep/examples/BaseTest.java b/examples/agent-only-load/src/main/java/com/intergral/deep/examples/BaseTest.java new file mode 100644 index 0000000..1a3ba44 --- /dev/null +++ b/examples/agent-only-load/src/main/java/com/intergral/deep/examples/BaseTest.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2023 Intergral GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.intergral.deep.examples; + +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; +import java.util.UUID; + +public class BaseTest { + + protected final Properties systemProps = System.getProperties(); + + + public String newId() { + return UUID.randomUUID().toString(); + } + + + public Map makeCharCountMap(final String str) { + final HashMap res = new HashMap(); + + for (int i = 0; i < str.length(); i++) { + final char c = str.charAt(i); + final Integer cnt = res.get(c); + if (cnt == null) { + res.put(c, 0); + } else { + res.put(c, cnt + 1); + } + } + + return res; + } +} diff --git a/examples/agent-only-load/src/main/java/com/intergral/deep/examples/Main.java b/examples/agent-only-load/src/main/java/com/intergral/deep/examples/Main.java new file mode 100644 index 0000000..7dd8bfc --- /dev/null +++ b/examples/agent-only-load/src/main/java/com/intergral/deep/examples/Main.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2023 Intergral GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.intergral.deep.examples; + + + +/** + * This example expects the deep agent to be loaded via the javaagent vm option. + *

+ * See RunConfigurations for IDEA: + *

    + *
  • Agent ONLY Load with JavaAgent
  • + *
+ */ +public class Main { + + /** + * Main entry for example. + * + * @param args the startup arguments + * @throws Throwable if we error + */ + public static void main(String[] args) throws Throwable { + + final SimpleTest ts = new SimpleTest("This is a test", 2); + //noinspection InfiniteLoopStatement + for (; ; ) { + try { + ts.message(ts.newId()); + } catch (Exception e) { + //noinspection CallToPrintStackTrace + e.printStackTrace(); + } + + //noinspection BusyWait + Thread.sleep(1000); + } + } +} diff --git a/examples/agent-only-load/src/main/java/com/intergral/deep/examples/SimpleTest.java b/examples/agent-only-load/src/main/java/com/intergral/deep/examples/SimpleTest.java new file mode 100644 index 0000000..3a42b27 --- /dev/null +++ b/examples/agent-only-load/src/main/java/com/intergral/deep/examples/SimpleTest.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2023 Intergral GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.intergral.deep.examples; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.TreeMap; + +public class SimpleTest extends BaseTest { + + public static Date NICE_START_DATE = new Date(); + + private final long startedAt = System.currentTimeMillis(); + private final String testName; + private final int maxExecutions; + private int cnt = 0; + private Map charCounter = new TreeMap(); + + + public SimpleTest(final String testName, final int maxExecutions) { + this.testName = testName; + this.maxExecutions = maxExecutions; + } + + + void message(final String uuid) throws Exception { + System.out.println(cnt + ":" + uuid); + cnt += 1; + + checkEnd(cnt, maxExecutions); + + final Map info = makeCharCountMap(uuid); + merge(charCounter, info); + if ((cnt % 30) == 0) { + dump(); + } + } + + + void merge(final Map charCounter, final Map newInfo) { + for (final Character c : newInfo.keySet()) { + final Integer i = newInfo.get(c); + + Integer curr = charCounter.get(c); + if (curr == null) { + charCounter.put(c, i); + } else { + charCounter.put(c, curr + i); + } + } + } + + + void dump() { + System.out.println(charCounter); + charCounter = new HashMap(); + } + + + static void checkEnd(final int val, final int max) throws Exception { + if (val > max) { + throw new Exception("Hit max executions " + val + " " + max); + } + } + + + @Override + public String toString() { + return getClass().getName() + ":" + testName + ":" + startedAt + "#" + System.identityHashCode( + this); + } +} diff --git a/examples/agent-only-load/src/site/site.xml b/examples/agent-only-load/src/site/site.xml new file mode 100644 index 0000000..06276d0 --- /dev/null +++ b/examples/agent-only-load/src/site/site.xml @@ -0,0 +1,48 @@ + + + + + + + org.apache.maven.skins + maven-fluido-skin + 1.11.2 + + + + + + + + + + + + false + true + + intergral/deep-java-client + right + gray + + + + \ No newline at end of file diff --git a/examples/pom.xml b/examples/pom.xml index cecf403..3d51fee 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -36,6 +36,7 @@ pom agent-load + agent-only-load dynamic-load prometheus-metrics-example otel-example