Skip to content

Commit 6ebf7aa

Browse files
authored
Merge pull request #7 from intergral/fr_support
Support use within FusionReactor
2 parents c6e01ad + 717af3e commit 6ebf7aa

File tree

24 files changed

+564
-82
lines changed

24 files changed

+564
-82
lines changed

agent-api/src/main/java/com/intergral/deep/agent/api/IDeep.java

+45
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,52 @@
1717

1818
package com.intergral.deep.agent.api;
1919

20+
import com.intergral.deep.agent.api.plugin.IPlugin;
21+
import com.intergral.deep.agent.api.plugin.IPlugin.IPluginRegistration;
22+
import com.intergral.deep.agent.api.tracepoint.ITracepoint.ITracepointRegistration;
23+
import java.util.Collection;
24+
import java.util.Map;
25+
26+
/**
27+
* This type describes the main API for Deep.
28+
* <p>
29+
* This API can only be used after the agent has been loaded.
30+
*/
2031
public interface IDeep {
2132

33+
/**
34+
* Get the version of deep being used.
35+
*
36+
* @return the sematic version of deep as a string e.g. 1.2.3
37+
*/
2238
String getVersion();
39+
40+
/**
41+
* This allows the registration of custom plugins.
42+
*
43+
* @param plugin the plugin that can be used to decorate snapshots
44+
* @return a {@link IPluginRegistration} that can be used to unregister the plugin
45+
*/
46+
IPluginRegistration registerPlugin(final IPlugin plugin);
47+
48+
/**
49+
* Create a tracepoint that will only exist on this instance.
50+
*
51+
* @param path the path to the file
52+
* @param line the line number
53+
* @return a {@link ITracepointRegistration} that can be used to remove the tracepoint
54+
*/
55+
ITracepointRegistration registerTracepoint(final String path, final int line);
56+
57+
/**
58+
* Create a tracepoint that will only exist on this instance.
59+
*
60+
* @param path the path to the file
61+
* @param line the line number
62+
* @param args the key value pairs that further define the tracepoint
63+
* @param watches the list of watch expressions
64+
* @return a {@link ITracepointRegistration} that can be used to remove the tracepoint
65+
*/
66+
ITracepointRegistration registerTracepoint(final String path, final int line, final Map<String, String> args,
67+
final Collection<String> watches);
2368
}

agent-api/src/main/java/com/intergral/deep/agent/api/plugin/IEventContext.java renamed to agent-api/src/main/java/com/intergral/deep/agent/api/IRegistration.java

+9-3
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,15 @@
1515
* along with this program. If not, see <https://www.gnu.org/licenses/>.
1616
*/
1717

18-
package com.intergral.deep.agent.api.plugin;
18+
package com.intergral.deep.agent.api;
1919

20-
public interface IEventContext {
20+
/**
21+
* This is a generic interface from the result of a registration.
22+
*/
23+
public interface IRegistration {
2124

22-
String evaluateExpression(String expression) throws Throwable;
25+
/**
26+
* Unregister the item registered.
27+
*/
28+
void unregister();
2329
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
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.agent.api.plugin;
19+
20+
/**
21+
* This exception is thrown when a plugin tried to evaluate an expression that fails.
22+
*/
23+
public class EvaluationException extends Exception {
24+
25+
/**
26+
* The expression that was evaluated.
27+
*/
28+
private final String expression;
29+
30+
/**
31+
* Create a new exception
32+
*
33+
* @param expression the expression that failed
34+
* @param cause the failure
35+
*/
36+
public EvaluationException(final String expression, final Throwable cause) {
37+
super("Could not evaluate expression: " + expression, cause);
38+
this.expression = expression;
39+
}
40+
41+
/**
42+
* Get the expression
43+
*
44+
* @return {@link #expression}
45+
*/
46+
public String getExpression() {
47+
return expression;
48+
}
49+
}

agent-api/src/main/java/com/intergral/deep/agent/api/plugin/IPlugin.java

+42-2
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,60 @@
1717

1818
package com.intergral.deep.agent.api.plugin;
1919

20+
import com.intergral.deep.agent.api.IRegistration;
2021
import com.intergral.deep.agent.api.resource.Resource;
2122
import com.intergral.deep.agent.api.settings.ISettings;
2223

24+
/**
25+
* This type is used to define a Deep Plugin.
26+
* <p>
27+
* Plugins can decorate the snapshot when they are captured allowing for additional metadata to be attached. e.g. OTEL span data.
28+
*/
2329
public interface IPlugin {
2430

25-
Resource decorate(final ISettings settings, final IEventContext snapshot);
31+
/**
32+
* This method is called by Deep after a snapshot is created.
33+
* <p>
34+
* This method is executed inline with the tracepoint code.
35+
*
36+
* @param settings the current settings of Deep
37+
* @param snapshot the {@link ISnapshotContext} describing the snapshot
38+
* @return a new {@link Resource} to be added to the snapshot, or {@code null} to do nothing
39+
*/
40+
Resource decorate(final ISettings settings, final ISnapshotContext snapshot);
41+
42+
/**
43+
* The name of the plugin. This should be unique.
44+
*
45+
* @return the plugin name, defaults to the full class name
46+
*/
47+
default String name() {
48+
return this.getClass().getName();
49+
}
2650

51+
/**
52+
* Is this plugin active.
53+
* <p>
54+
* By default, this will check the Deep settings for the plugin name. e.g. the setting com.intergral.deep.plugin.JavaPlugin.active=false
55+
* will disable the JavaPlugin. The normal settings rules apply, e.g. deep. or DEEP_ as a prefix when using system properties or environment variables.
56+
*
57+
* @param settings the current deep settings.
58+
* @return {@code false} if setting is 'false', otherwise {@code true}
59+
*/
2760
default boolean isActive(final ISettings settings) {
28-
final String simpleName = this.getClass().getSimpleName();
61+
final String simpleName = this.name();
2962
final Boolean settingAs = settings.getSettingAs(String.format("%s.active", simpleName),
3063
Boolean.class);
3164
if (settingAs == null) {
3265
return true;
3366
}
3467
return settingAs;
3568
}
69+
70+
/**
71+
* This type describes a registered plugin.
72+
*/
73+
interface IPluginRegistration extends IRegistration {
74+
75+
}
3676
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
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.agent.api.plugin;
19+
20+
/**
21+
* This is the context passed to plugins. This allows for the data of a context to be exposed to the plugin in a controlled manor.
22+
*/
23+
public interface ISnapshotContext {
24+
25+
/**
26+
* Evaluate an expression in the frame of the tracepoint that triggered this snapshot
27+
*
28+
* @param expression the express to evaluate
29+
* @return the result of the expression as a string
30+
* @throws EvaluationException if there were any issues evaluating the expression
31+
*/
32+
String evaluateExpression(String expression) throws EvaluationException;
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
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.agent.api.tracepoint;
19+
20+
import com.intergral.deep.agent.api.IRegistration;
21+
import java.util.Collection;
22+
import java.util.Collections;
23+
import java.util.Map;
24+
import java.util.UUID;
25+
26+
public interface ITracepoint {
27+
28+
String path();
29+
30+
int line();
31+
32+
default Map<String, String> args() {
33+
return Collections.emptyMap();
34+
}
35+
36+
default Collection<String> watches() {
37+
return Collections.emptyList();
38+
}
39+
40+
default String id() {
41+
return UUID.randomUUID().toString();
42+
}
43+
44+
interface ITracepointRegistration extends IRegistration {
45+
46+
}
47+
}

agent/src/main/java/com/intergral/deep/agent/AgentImpl.java

+18-9
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717

1818
package com.intergral.deep.agent;
1919

20-
import com.intergral.deep.agent.api.DeepVersion;
2120
import com.intergral.deep.agent.api.IDeep;
2221
import com.intergral.deep.agent.api.hook.IDeepHook;
2322
import com.intergral.deep.agent.api.reflection.IReflection;
@@ -26,32 +25,42 @@
2625
import com.intergral.deep.agent.tracepoint.inst.TracepointInstrumentationService;
2726
import java.lang.instrument.Instrumentation;
2827
import java.util.Map;
28+
import java.util.concurrent.CountDownLatch;
2929

3030
public class AgentImpl {
3131

32+
private static final CountDownLatch LATCH = new CountDownLatch(1);
33+
private static DeepAgent deepAgent;
34+
3235
public static void startup(final Instrumentation inst, final Map<String, String> args) {
3336
final Settings settings = Settings.build(args);
3437
Logger.configureLogging(settings);
3538

3639
final TracepointInstrumentationService tracepointInstrumentationService =
3740
TracepointInstrumentationService.init(inst, settings);
3841

39-
final DeepAgent deepAgent = new DeepAgent(settings, tracepointInstrumentationService);
42+
final DeepAgent deep = new DeepAgent(settings, tracepointInstrumentationService);
43+
44+
deep.start();
45+
46+
deepAgent = deep;
47+
LATCH.countDown();
48+
}
4049

41-
deepAgent.start();
50+
public static Object awaitLoadAPI() throws InterruptedException {
51+
LATCH.await();
52+
return loadDeepAPI();
4253
}
4354

4455
public static Object loadDeepAPI() {
56+
if (deepAgent == null) {
57+
throw new IllegalStateException("Must start DEEP first");
58+
}
4559
return new IDeepHook() {
4660

4761
@Override
4862
public IDeep deepService() {
49-
return new IDeep() {
50-
@Override
51-
public String getVersion() {
52-
return DeepVersion.VERSION;
53-
}
54-
};
63+
return deepAgent;
5564
}
5665

5766
@Override

agent/src/main/java/com/intergral/deep/agent/DeepAgent.java

+31-1
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,12 @@
1717

1818
package com.intergral.deep.agent;
1919

20+
import com.intergral.deep.agent.api.DeepVersion;
21+
import com.intergral.deep.agent.api.IDeep;
2022
import com.intergral.deep.agent.api.plugin.IPlugin;
23+
import com.intergral.deep.agent.api.plugin.IPlugin.IPluginRegistration;
2124
import com.intergral.deep.agent.api.resource.Resource;
25+
import com.intergral.deep.agent.api.tracepoint.ITracepoint.ITracepointRegistration;
2226
import com.intergral.deep.agent.grpc.GrpcService;
2327
import com.intergral.deep.agent.plugins.PluginLoader;
2428
import com.intergral.deep.agent.poll.LongPollService;
@@ -28,9 +32,13 @@
2832
import com.intergral.deep.agent.tracepoint.TracepointConfigService;
2933
import com.intergral.deep.agent.tracepoint.handler.Callback;
3034
import com.intergral.deep.agent.tracepoint.inst.TracepointInstrumentationService;
35+
import com.intergral.deep.agent.types.TracePointConfig;
36+
import java.util.Collection;
37+
import java.util.Collections;
3138
import java.util.List;
39+
import java.util.Map;
3240

33-
public class DeepAgent {
41+
public class DeepAgent implements IDeep {
3442

3543
private final Settings settings;
3644
private final GrpcService grpcService;
@@ -58,4 +66,26 @@ public void start() {
5866
this.grpcService.start();
5967
this.pollService.start(tracepointConfig);
6068
}
69+
70+
@Override
71+
public String getVersion() {
72+
return DeepVersion.VERSION;
73+
}
74+
75+
public IPluginRegistration registerPlugin(final IPlugin plugin) {
76+
this.settings.addPlugin(plugin);
77+
return () -> this.settings.removePlugin(plugin);
78+
}
79+
80+
@Override
81+
public ITracepointRegistration registerTracepoint(final String path, final int line) {
82+
return registerTracepoint(path, line, Collections.emptyMap(), Collections.emptyList());
83+
}
84+
85+
@Override
86+
public ITracepointRegistration registerTracepoint(final String path, final int line, final Map<String, String> args,
87+
final Collection<String> watches) {
88+
final TracePointConfig tracePointConfig = this.tracepointConfig.addCustom(path, line, args, watches);
89+
return () -> this.tracepointConfig.removeCustom(tracePointConfig);
90+
}
6191
}

0 commit comments

Comments
 (0)