Skip to content

Commit 0250d30

Browse files
committed
fix(spi): handle errors during SPI loading to ensure we do not break startup
- add agent only example
1 parent ef74535 commit 0250d30

File tree

15 files changed

+479
-2
lines changed

15 files changed

+479
-2
lines changed

.idea/runConfigurations/Agent_ONLY_Load_with_JavaAgent.xml

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

agent/src/main/java/com/intergral/deep/agent/resource/SpiUtil.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,19 @@
88
import com.intergral.deep.agent.api.spi.Ordered;
99
import java.util.ArrayList;
1010
import java.util.Comparator;
11+
import java.util.Iterator;
1112
import java.util.List;
1213
import java.util.ServiceLoader;
14+
import org.slf4j.Logger;
15+
import org.slf4j.LoggerFactory;
1316

1417
/**
1518
* Utilities to load SPI services.
1619
*/
1720
public final class SpiUtil {
1821

22+
private static final Logger LOGGER = LoggerFactory.getLogger(SpiUtil.class);
23+
1924
private SpiUtil() {
2025
}
2126

@@ -28,8 +33,15 @@ public static <T extends Ordered> List<T> loadOrdered(Class<T> spiClass,
2833
static <T extends Ordered> List<T> loadOrdered(
2934
Class<T> spiClass, ClassLoader serviceClassLoader, ServiceLoaderFinder serviceLoaderFinder) {
3035
List<T> result = new ArrayList<>();
31-
for (T service : serviceLoaderFinder.load(spiClass, serviceClassLoader)) {
32-
result.add(service);
36+
final Iterator<T> iterator = serviceLoaderFinder.load(spiClass, serviceClassLoader).iterator();
37+
while (iterator.hasNext()) {
38+
try {
39+
result.add(iterator.next());
40+
} catch (Throwable t) {
41+
// WARNING - exception from this will have the wrong stack trace
42+
// the error will come from 'hasNext' not 'next'
43+
LOGGER.error("Cannot load provider.", t);
44+
}
3345
}
3446
result.sort(Comparator.comparing(Ordered::order));
3547
return result;
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Copyright (C) 2024 Intergral GmbH
3+
*
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU Affero General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU Affero General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU Affero General Public License
15+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
16+
*/
17+
18+
package com.intergral.deep.agent.resource;
19+
20+
import com.intergral.deep.agent.api.spi.Ordered;
21+
22+
public interface ITestProvider extends Ordered {
23+
24+
}

agent/src/test/java/com/intergral/deep/agent/resource/SpiUtilTest.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,10 @@ void loadsOrderedSpi() {
4646

4747
assertEquals(3, loadedSpi.size());
4848
}
49+
50+
@Test
51+
void canHandleConfigErrors() {
52+
final List<ITestProvider> ts = SpiUtil.loadOrdered(ITestProvider.class, getClass().getClassLoader());
53+
assertEquals(1, ts.size());
54+
}
4955
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Copyright (C) 2024 Intergral GmbH
3+
*
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU Affero General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU Affero General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU Affero General Public License
15+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
16+
*/
17+
18+
package com.intergral.deep.agent.resource;
19+
20+
21+
public class TestProvider implements ITestProvider {
22+
23+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#
2+
# Copyright (C) 2024 Intergral GmbH
3+
#
4+
# This program is free software: you can redistribute it and/or modify
5+
# it under the terms of the GNU Affero General Public License as published by
6+
# the Free Software Foundation, either version 3 of the License, or
7+
# (at your option) any later version.
8+
#
9+
# This program is distributed in the hope that it will be useful,
10+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
# GNU Affero General Public License for more details.
13+
#
14+
# You should have received a copy of the GNU Affero General Public License
15+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
16+
#
17+
18+
com.intergral.deep.agent.resource.TestProvider
19+
com.intergral.deep.agent.test.NotExists

examples/agent-only-load/.gitignore

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
target/
2+
!.mvn/wrapper/maven-wrapper.jar
3+
!**/src/main/**/target/
4+
!**/src/test/**/target/
5+
6+
### IntelliJ IDEA ###
7+
.idea/modules.xml
8+
.idea/jarRepositories.xml
9+
.idea/compiler.xml
10+
.idea/libraries/
11+
*.iws
12+
*.iml
13+
*.ipr
14+
15+
### Eclipse ###
16+
.apt_generated
17+
.classpath
18+
.factorypath
19+
.project
20+
.settings
21+
.springBeans
22+
.sts4-cache
23+
24+
### NetBeans ###
25+
/nbproject/private/
26+
/nbbuild/
27+
/dist/
28+
/nbdist/
29+
/.nb-gradle/
30+
build/
31+
!**/src/main/**/build/
32+
!**/src/test/**/build/
33+
34+
### VS Code ###
35+
.vscode/
36+
37+
### Mac OS ###
38+
.DS_Store

examples/agent-only-load/pom.xml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
~ Copyright (C) 2023 Intergral GmbH
4+
~
5+
~ This program is free software: you can redistribute it and/or modify
6+
~ it under the terms of the GNU Affero General Public License as published by
7+
~ the Free Software Foundation, either version 3 of the License, or
8+
~ (at your option) any later version.
9+
~
10+
~ This program is distributed in the hope that it will be useful,
11+
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
~ GNU Affero General Public License for more details.
14+
~
15+
~ You should have received a copy of the GNU Affero General Public License
16+
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
-->
18+
19+
<project xmlns="http://maven.apache.org/POM/4.0.0"
20+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
21+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
22+
<modelVersion>4.0.0</modelVersion>
23+
<parent>
24+
<groupId>com.intergral.deep.examples</groupId>
25+
<artifactId>examples</artifactId>
26+
<version>1.0-SNAPSHOT</version>
27+
<relativePath>../pom.xml</relativePath>
28+
</parent>
29+
30+
<artifactId>agent-only-load</artifactId>
31+
<name>Agent Load</name>
32+
<description>This example uses the agent load (-javaagent) to load the deep agent. It therefore
33+
has no dependencies of code related to deep.
34+
</description>
35+
36+
<properties>
37+
<maven.compiler.source>8</maven.compiler.source>
38+
<maven.compiler.target>8</maven.compiler.target>
39+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
40+
</properties>
41+
42+
<dependencies>
43+
</dependencies>
44+
</project>
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* Copyright (C) 2023 Intergral GmbH
3+
*
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU Affero General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU Affero General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU Affero General Public License
15+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
16+
*/
17+
18+
package com.intergral.deep.examples;
19+
20+
import java.util.HashMap;
21+
import java.util.Map;
22+
import java.util.Properties;
23+
import java.util.UUID;
24+
25+
public class BaseTest {
26+
27+
protected final Properties systemProps = System.getProperties();
28+
29+
30+
public String newId() {
31+
return UUID.randomUUID().toString();
32+
}
33+
34+
35+
public Map<Character, Integer> makeCharCountMap(final String str) {
36+
final HashMap<Character, Integer> res = new HashMap<Character, Integer>();
37+
38+
for (int i = 0; i < str.length(); i++) {
39+
final char c = str.charAt(i);
40+
final Integer cnt = res.get(c);
41+
if (cnt == null) {
42+
res.put(c, 0);
43+
} else {
44+
res.put(c, cnt + 1);
45+
}
46+
}
47+
48+
return res;
49+
}
50+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Copyright (C) 2023 Intergral GmbH
3+
*
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU Affero General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU Affero General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU Affero General Public License
15+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
16+
*/
17+
18+
package com.intergral.deep.examples;
19+
20+
21+
22+
/**
23+
* This example expects the deep agent to be loaded via the javaagent vm option.
24+
* <p>
25+
* See RunConfigurations for IDEA:
26+
* <ul>
27+
* <li>Agent ONLY Load with JavaAgent</li>
28+
* </ul>
29+
*/
30+
public class Main {
31+
32+
/**
33+
* Main entry for example.
34+
*
35+
* @param args the startup arguments
36+
* @throws Throwable if we error
37+
*/
38+
public static void main(String[] args) throws Throwable {
39+
40+
final SimpleTest ts = new SimpleTest("This is a test", 2);
41+
//noinspection InfiniteLoopStatement
42+
for (; ; ) {
43+
try {
44+
ts.message(ts.newId());
45+
} catch (Exception e) {
46+
//noinspection CallToPrintStackTrace
47+
e.printStackTrace();
48+
}
49+
50+
//noinspection BusyWait
51+
Thread.sleep(1000);
52+
}
53+
}
54+
}

0 commit comments

Comments
 (0)