diff --git a/.idea/misc.xml b/.idea/misc.xml index 612ec51..56b4fdf 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,3 +1,4 @@ + @@ -10,6 +11,7 @@ + diff --git a/CHANGELOG.md b/CHANGELOG.md index d9bd868..4a9e58a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ -# 1.1.1 (xx/xx/2023) +# 1.2.0 (xx/xx/2023) +- **[CHANGE]**: plugin: Change the plugins to use SPI to load [#77](https://github.com/intergral/deep/pull/77) [@Umaaz](https://github.com/Umaaz) +# 1.1.2 (29/09/2023) +- **[CHANGE]**: version: Override grpc-netty dependencies to remove CVE [#44](https://github.com/intergral/deep/pull/44) [@LMarkie](https://github.com/LMarkie) +- **[BUGFIX]**: build: change mvn dep graph to run only on master [#45](https://github.com/intergral/deep/pull/45) [@Umaaz](https://github.com/Umaaz) +- **[BUGFIX]**: build: update build to ensure agent is built for cf-tests [#55](https://github.com/intergral/deep/pull/55) [@Umaaz](https://github.com/Umaaz) +- **[Snyk]**: Upgrade: net.bytebuddy:byte-buddy-agent from 1.14.4 to 1.14.7 [#43](https://github.com/intergral/deep/pull/43) [@Umaaz](https://github.com/Umaaz) + +# 1.1.1 (25/09/2023) +- **[CHANGE]**: reflection: reduce duplicate reflection code and proxy style [#34](https://github.com/intergral/deep/pull/34) [@Umaaz](https://github.com/Umaaz) +- **[Snyk]**: vulnerability: Fix for 1 vulnerability [#35](https://github.com/intergral/deep/pull/35) [@Umaaz](https://github.com/Umaaz) +- **[Snyk]**: Upgrade: org.junit.jupiter:junit-jupiter from 5.9.3 to 5.10.0 [#38](https://github.com/intergral/deep/pull/38) [@Umaaz](https://github.com/Umaaz) # 1.1.0 (06/09/2023) diff --git a/agent-api/src/main/java/com/intergral/deep/agent/api/IDeep.java b/agent-api/src/main/java/com/intergral/deep/agent/api/IDeep.java index 2148787..d368a98 100644 --- a/agent-api/src/main/java/com/intergral/deep/agent/api/IDeep.java +++ b/agent-api/src/main/java/com/intergral/deep/agent/api/IDeep.java @@ -17,8 +17,6 @@ package com.intergral.deep.agent.api; -import com.intergral.deep.agent.api.plugin.IPlugin; -import com.intergral.deep.agent.api.plugin.IPlugin.IPluginRegistration; import com.intergral.deep.agent.api.tracepoint.ITracepoint.ITracepointRegistration; import java.util.Collection; import java.util.Map; @@ -56,14 +54,6 @@ public interface IDeep { */ String getVersion(); - /** - * This allows the registration of custom plugins. - * - * @param plugin the plugin that can be used to decorate snapshots - * @return a {@link IPluginRegistration} that can be used to unregister the plugin - */ - IPluginRegistration registerPlugin(final IPlugin plugin); - /** * Create a tracepoint that will only exist on this instance. * diff --git a/agent-api/src/main/java/com/intergral/deep/agent/api/auth/AuthProvider.java b/agent-api/src/main/java/com/intergral/deep/agent/api/auth/AuthProvider.java deleted file mode 100644 index 720f1c3..0000000 --- a/agent-api/src/main/java/com/intergral/deep/agent/api/auth/AuthProvider.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * 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.api.auth; - -import com.intergral.deep.agent.api.DeepRuntimeException; -import com.intergral.deep.agent.api.plugin.IPlugin; -import com.intergral.deep.agent.api.reflection.IReflection; -import com.intergral.deep.agent.api.reflection.ReflectionUtils; -import com.intergral.deep.agent.api.settings.ISettings; -import java.lang.reflect.Constructor; -import java.util.Collections; -import java.util.Map; - -/** - * A utility class to load the configured {@link IAuthProvider}. - */ -public final class AuthProvider { - - private AuthProvider() { - } - - private static final NoopProvider NOOP_PROVIDER = new NoopProvider(); - - /** - * Load the configured {@link IAuthProvider}. - *

- * This will always return a {@link IAuthProvider}. - * - * @param settings the current settings - * @param reflection the reflection service that is available - * @return the loaded {@link IAuthProvider} - */ - public static IAuthProvider provider(final ISettings settings, final IReflection reflection) { - final String serviceAuthProvider = settings.getSettingAs("service.auth.provider", String.class); - if (serviceAuthProvider == null || serviceAuthProvider.trim().isEmpty()) { - return NOOP_PROVIDER; - } - - // check if we have a plugin of this name that we can use - final IPlugin plugin = settings.getPlugin(serviceAuthProvider); - if (plugin != null) { - if (plugin instanceof IAuthProvider) { - return (IAuthProvider) plugin; - } else { - throw new DeepRuntimeException( - String.format("Cannot use plugin %s as auth provider, must implement IAuthProvider interface.", plugin.name())); - } - } - - try { - final Class aClass = Class.forName(serviceAuthProvider); - final Constructor constructor = ReflectionUtils.findConstructor(aClass, reflection); - return ReflectionUtils.callConstructor(constructor, settings, reflection); - } catch (ClassNotFoundException e) { - throw new RuntimeException(String.format("Cannot load auth provider %s", serviceAuthProvider), e); - } - } - - static class NoopProvider implements IAuthProvider { - - @Override - public Map provide() { - return Collections.emptyMap(); - } - } -} diff --git a/agent-api/src/main/java/com/intergral/deep/agent/api/auth/BasicAuthProvider.java b/agent-api/src/main/java/com/intergral/deep/agent/api/auth/BasicAuthProvider.java index 819a141..9e47ee0 100644 --- a/agent-api/src/main/java/com/intergral/deep/agent/api/auth/BasicAuthProvider.java +++ b/agent-api/src/main/java/com/intergral/deep/agent/api/auth/BasicAuthProvider.java @@ -17,7 +17,9 @@ package com.intergral.deep.agent.api.auth; +import com.intergral.deep.agent.api.reflection.IReflection; import com.intergral.deep.agent.api.settings.ISettings; +import com.intergral.deep.agent.api.spi.IDeepPlugin; import java.util.Base64; import java.util.Collections; import java.util.Map; @@ -34,12 +36,14 @@ *

* These values are then base64 encoded and attached to the outbound requests as the {@code authorization} header. */ -public class BasicAuthProvider implements IAuthProvider { +public class BasicAuthProvider implements IDeepPlugin, IAuthProvider { - private final ISettings settings; + private ISettings settings; - public BasicAuthProvider(final ISettings settings) { + @Override + public IDeepPlugin configure(final ISettings settings, final IReflection reflection) { this.settings = settings; + return this; } @Override diff --git a/agent-api/src/main/java/com/intergral/deep/agent/api/plugin/IPlugin.java b/agent-api/src/main/java/com/intergral/deep/agent/api/plugin/IPlugin.java deleted file mode 100644 index 9bd09d8..0000000 --- a/agent-api/src/main/java/com/intergral/deep/agent/api/plugin/IPlugin.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * 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.api.plugin; - -import com.intergral.deep.agent.api.IRegistration; -import com.intergral.deep.agent.api.resource.Resource; -import com.intergral.deep.agent.api.settings.ISettings; - -/** - * This type is used to define a Deep Plugin. - *

- * Plugins can decorate the snapshot when they are captured allowing for additional metadata to be attached. e.g. OTEL span data. - */ -public interface IPlugin { - - /** - * This method is called by Deep after a snapshot is created. - *

- * This method is executed inline with the tracepoint code. - * - * @param settings the current settings of Deep - * @param snapshot the {@link ISnapshotContext} describing the snapshot - * @return a new {@link Resource} to be added to the snapshot, or {@code null} to do nothing - */ - Resource decorate(final ISettings settings, final ISnapshotContext snapshot); - - /** - * The name of the plugin. This should be unique. - * - * @return the plugin name, defaults to the full class name - */ - default String name() { - return this.getClass().getName(); - } - - /** - * Is this plugin active. - *

- * By default, this will check the Deep settings for the plugin name. e.g. the setting com.intergral.deep.plugin.JavaPlugin.active=false - * will disable the JavaPlugin. The normal settings rules apply, e.g. deep. or DEEP_ as a prefix when using system properties - * or environment variables. - * - * @param settings the current deep settings. - * @return {@code false} if setting is 'false', otherwise {@code true} - */ - default boolean isActive(final ISettings settings) { - final String simpleName = this.name(); - final Boolean settingAs = settings.getSettingAs(String.format("%s.active", simpleName), - Boolean.class); - if (settingAs == null) { - return true; - } - return settingAs; - } - - /** - * This type describes a registered plugin. - */ - interface IPluginRegistration extends IRegistration { - - /** - * Indicates if this plugin is currently set to be the auth provider. - * - * @return {@code true} if the registered plugin is an {@link com.intergral.deep.agent.api.auth.IAuthProvider} and deep is configured - * to use this provider, else {@code false} - */ - boolean isAuthProvider(); - - /** - * Indicates if this plugin is being used to decorate the resource data. - * - * @return {@code true} if this plugin was used to decorate the resource data, else {@code false}. - */ - boolean isResourceProvider(); - - /** - * Indicates if this plugin is being used to log tracepoints. - * - * @return {@code true} if this plugin is being used to log the tracepoint logs, else {@code false}. - */ - boolean isTracepointLogger(); - } -} diff --git a/agent-api/src/main/java/com/intergral/deep/agent/api/plugin/ISnapshotDecorator.java b/agent-api/src/main/java/com/intergral/deep/agent/api/plugin/ISnapshotDecorator.java new file mode 100644 index 0000000..5cf818d --- /dev/null +++ b/agent-api/src/main/java/com/intergral/deep/agent/api/plugin/ISnapshotDecorator.java @@ -0,0 +1,38 @@ +/* + * 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.api.plugin; + +import com.intergral.deep.agent.api.resource.Resource; +import com.intergral.deep.agent.api.settings.ISettings; + +/** + * This type allows a plugin to provide additional attributes to captured snapshots. + */ +public interface ISnapshotDecorator { + + /** + * This method is called by Deep after a snapshot is created. + *

+ * This method is executed inline with the tracepoint code. + * + * @param settings the current settings of Deep + * @param snapshot the {@link ISnapshotContext} describing the snapshot + * @return a new {@link Resource} to be added to the snapshot, or {@code null} to do nothing + */ + Resource decorate(final ISettings settings, final ISnapshotContext snapshot); +} diff --git a/agent-api/src/main/java/com/intergral/deep/agent/api/reflection/ReflectionUtils.java b/agent-api/src/main/java/com/intergral/deep/agent/api/reflection/ReflectionUtils.java deleted file mode 100644 index 0353c92..0000000 --- a/agent-api/src/main/java/com/intergral/deep/agent/api/reflection/ReflectionUtils.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * 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.api.reflection; - -import com.intergral.deep.agent.api.DeepRuntimeException; -import com.intergral.deep.agent.api.settings.ISettings; -import java.lang.reflect.Constructor; - -/** - * A simple util to get create plugins. A plugin can have a default constructor or one that accepts the {@link ISettings} class. So this - * type helps us find and call the appropriate constructor. - */ -public final class ReflectionUtils { - - private ReflectionUtils() { - } - - /** - * Call the constructor. - * - * @param constructor the constructor - * @param settings the settings object - * @param reflection the reflection service to use - * @param the type of the new object - * @return the new object - */ - public static T callConstructor(final Constructor constructor, final ISettings settings, final IReflection reflection) { - if (constructor.getParameterTypes().length == 0) { - return reflection.callConstructor(constructor); - } - return reflection.callConstructor(constructor, settings); - } - - /** - * Find the constructor to use. - *

- * Will look for the constructor that we can use in the order: - *

    - *
  • constructor(ISettings.class)
  • - *
  • constructor()
  • - *
- * - * @param clazz the class to look on - * @param reflection the reflection service to use - * @return the constructor that was found - * @throws DeepRuntimeException if we could not find a constructor - */ - public static Constructor findConstructor(final Class clazz, final IReflection reflection) { - - final Constructor constructor = reflection.findConstructor(clazz, ISettings.class); - if (constructor != null) { - return constructor; - } - - final Constructor defaultConstructor = reflection.findConstructor(clazz); - if (defaultConstructor != null) { - return defaultConstructor; - } - final String simpleName = clazz.getSimpleName(); - throw new DeepRuntimeException( - String.format("Cannot create auth provider of type: %s. Class is missing constructor %s(%s) or %s().", clazz.getName(), - simpleName, ISettings.class.getName(), simpleName)); - - } - -} diff --git a/agent-api/src/main/java/com/intergral/deep/agent/api/settings/ISettings.java b/agent-api/src/main/java/com/intergral/deep/agent/api/settings/ISettings.java index 3f94803..73e4dfe 100644 --- a/agent-api/src/main/java/com/intergral/deep/agent/api/settings/ISettings.java +++ b/agent-api/src/main/java/com/intergral/deep/agent/api/settings/ISettings.java @@ -17,7 +17,6 @@ package com.intergral.deep.agent.api.settings; -import com.intergral.deep.agent.api.plugin.IPlugin; import com.intergral.deep.agent.api.resource.Resource; import java.util.List; import java.util.Map; @@ -47,11 +46,6 @@ public interface ISettings { */ String KEY_SERVICE_SECURE = "service.secure"; - /** - * This is the setting key for the plugin list. - */ - String PLUGINS = "plugins"; - /** * To let us calculate the class and file names for JSP classes we need to know the JSP suffix that is being used by monitored service. *

@@ -127,12 +121,4 @@ public interface ISettings { * @return the {@link Resource} */ Resource getResource(); - - /** - * Look for a plugin with the given name or class name. - * - * @param name the plugin name or the plugin class name - * @return the {@link IPlugin} or {@code null} - */ - IPlugin getPlugin(final String name); } diff --git a/agent-api/src/main/java/com/intergral/deep/agent/api/spi/IConditional.java b/agent-api/src/main/java/com/intergral/deep/agent/api/spi/IConditional.java new file mode 100644 index 0000000..677ae2c --- /dev/null +++ b/agent-api/src/main/java/com/intergral/deep/agent/api/spi/IConditional.java @@ -0,0 +1,31 @@ +/* + * 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.api.spi; + +/** + * This interface allows an instance of {@link IDeepPlugin} to only be loaded based on a condition. + */ +public interface IConditional { + + /** + * Should determine if the plugin is active. + * + * @return {@code true} if and only if the plugins is active, else {@code false} + */ + boolean isActive(); +} diff --git a/agent-api/src/main/java/com/intergral/deep/agent/api/spi/IDeepPlugin.java b/agent-api/src/main/java/com/intergral/deep/agent/api/spi/IDeepPlugin.java new file mode 100644 index 0000000..ff92dc9 --- /dev/null +++ b/agent-api/src/main/java/com/intergral/deep/agent/api/spi/IDeepPlugin.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.agent.api.spi; + +import com.intergral.deep.agent.api.reflection.IReflection; +import com.intergral.deep.agent.api.settings.ISettings; + +/** + * This type defines a plugin for Deep. These plugins will be loaded via SPI and can provide any functionality from the extension points in + * Deep. + * + *

    + *
  • {@link IConditional} - allow plugin to be conditional
  • + *
  • {@link com.intergral.deep.agent.api.plugin.ISnapshotDecorator} - + * allow plugins to provide additional attributes to captured snapshots
  • + *
  • {@link com.intergral.deep.agent.api.auth.IAuthProvider} - allow plugin to provide additional ways to authenticate
  • + *
  • {@link ResourceProvider} - allow plugins to provide additional information for the resource definition
  • + *
+ *

+ * Plugins will be instantiated via the default constructor and then the {@link #configure(ISettings, IReflection)} + * function will be invoked. + */ +public interface IDeepPlugin extends Ordered { + + /** + * This allows for the plugin to retain a reference to the settings for Deep and allows access to the {@link IReflection} service to + * perform reflection operations. + * + * @param settings the settings for Deep + * @param reflection a service to allow easier access to reflection + * @return {@code this}, or a new instance of a plugin + * + * @see IReflection + * @see ISettings + */ + default IDeepPlugin configure(ISettings settings, IReflection reflection) { + return this; + } +} diff --git a/agent-api/src/test/java/com/intergral/deep/agent/api/auth/AuthProviderTest.java b/agent-api/src/test/java/com/intergral/deep/agent/api/auth/AuthProviderTest.java deleted file mode 100644 index 8658a53..0000000 --- a/agent-api/src/test/java/com/intergral/deep/agent/api/auth/AuthProviderTest.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * 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.api.auth; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import com.intergral.deep.agent.api.auth.AuthProvider.NoopProvider; -import com.intergral.deep.agent.api.plugin.IPlugin; -import com.intergral.deep.agent.api.plugin.ISnapshotContext; -import com.intergral.deep.agent.api.reflection.IReflection; -import com.intergral.deep.agent.api.resource.Resource; -import com.intergral.deep.agent.api.settings.ISettings; -import java.util.Collections; -import java.util.Map; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; - -class AuthProviderTest { - - @Test - void canProvide() { - final ISettings settings = Mockito.mock(ISettings.class); - final IReflection reflection = Mockito.mock(IReflection.class); - final IAuthProvider provider = AuthProvider.provider(settings, reflection); - - assertEquals(provider.getClass(), NoopProvider.class); - } - - @Test - void canLoadProviderByName() { - final ISettings settings = Mockito.mock(ISettings.class); - Mockito.doReturn(MockAuthProviderPlugin.class.getName()).when(settings).getSettingAs("service.auth.provider", String.class); - final IReflection reflection = Mockito.mock(IReflection.class); - Mockito.when(reflection.findConstructor(Mockito.any(), Mockito.any())) - .thenAnswer(invocationOnMock -> MockAuthProviderPlugin.class.getConstructor()); - Mockito.when(reflection.callConstructor(Mockito.any())).thenReturn(new MockAuthProviderPlugin()); - final IAuthProvider provider = AuthProvider.provider(settings, reflection); - - assertEquals(MockAuthProviderPlugin.class, provider.getClass()); - } - - @Test - void willUseNoopProvider() { - final ISettings settings = Mockito.mock(ISettings.class); - final IReflection reflection = Mockito.mock(IReflection.class); - final IAuthProvider provider = AuthProvider.provider(settings, reflection); - assertEquals(NoopProvider.class, provider.getClass()); - assertEquals(Collections.emptyMap(), provider.provide()); - } - - public static class MockAuthProviderPlugin implements IPlugin, IAuthProvider { - - @Override - public Resource decorate(final ISettings settings, final ISnapshotContext snapshot) { - return Resource.create(Collections.singletonMap("test", "provider")); - } - - @Override - public Map provide() { - return Collections.singletonMap("test", "provider"); - } - } -} \ No newline at end of file diff --git a/agent-api/src/test/java/com/intergral/deep/agent/api/auth/BasicAuthProviderTest.java b/agent-api/src/test/java/com/intergral/deep/agent/api/auth/BasicAuthProviderTest.java index 5acedc1..f979e74 100644 --- a/agent-api/src/test/java/com/intergral/deep/agent/api/auth/BasicAuthProviderTest.java +++ b/agent-api/src/test/java/com/intergral/deep/agent/api/auth/BasicAuthProviderTest.java @@ -29,7 +29,8 @@ class BasicAuthProviderTest { @Test void canProvide() { final ISettings settings = Mockito.mock(ISettings.class); - final BasicAuthProvider basicAuthProvider = new BasicAuthProvider(settings); + final BasicAuthProvider basicAuthProvider = new BasicAuthProvider(); + basicAuthProvider.configure(settings, null); assertEquals(0, basicAuthProvider.provide().size()); } @@ -38,7 +39,8 @@ void canProvide() { void canProvide_settings() { final ISettings settings = Mockito.mock(ISettings.class); Mockito.doReturn("username").doReturn("password").when(settings).getSettingAs(Mockito.anyString(), Mockito.any()); - final BasicAuthProvider basicAuthProvider = new BasicAuthProvider(settings); + final BasicAuthProvider basicAuthProvider = new BasicAuthProvider(); + basicAuthProvider.configure(settings, null); final Map provide = basicAuthProvider.provide(); assertEquals(1, provide.size()); @@ -49,7 +51,8 @@ void canProvide_settings() { void canProvide_missingUsername() { final ISettings settings = Mockito.mock(ISettings.class); Mockito.doReturn(null).doReturn("password").when(settings).getSettingAs(Mockito.anyString(), Mockito.any()); - final BasicAuthProvider basicAuthProvider = new BasicAuthProvider(settings); + final BasicAuthProvider basicAuthProvider = new BasicAuthProvider(); + basicAuthProvider.configure(settings, null); final Map provide = basicAuthProvider.provide(); assertEquals(0, provide.size()); @@ -59,7 +62,8 @@ void canProvide_missingUsername() { void canProvide_missingPassword() { final ISettings settings = Mockito.mock(ISettings.class); Mockito.doReturn("username").doReturn(null).when(settings).getSettingAs(Mockito.anyString(), Mockito.any()); - final BasicAuthProvider basicAuthProvider = new BasicAuthProvider(settings); + final BasicAuthProvider basicAuthProvider = new BasicAuthProvider(); + basicAuthProvider.configure(settings, null); final Map provide = basicAuthProvider.provide(); assertEquals(0, provide.size()); diff --git a/agent-api/src/test/java/com/intergral/deep/agent/api/plugin/IPluginTest.java b/agent-api/src/test/java/com/intergral/deep/agent/api/plugin/IPluginTest.java deleted file mode 100644 index 06de505..0000000 --- a/agent-api/src/test/java/com/intergral/deep/agent/api/plugin/IPluginTest.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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.api.plugin; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import com.intergral.deep.agent.api.resource.Resource; -import com.intergral.deep.agent.api.settings.ISettings; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; - -class IPluginTest { - - @Test - void name() { - assertEquals("com.intergral.deep.agent.api.plugin.IPluginTest$MockPlugin", new MockPlugin().name()); - } - - @Test - void isActive() { - final ISettings settings = Mockito.mock(ISettings.class); - Mockito.when(settings.getSettingAs("com.intergral.deep.agent.api.plugin.IPluginTest$MockPlugin.active", Boolean.class)).thenReturn(null) - .thenReturn(true).thenReturn(false); - assertTrue(new MockPlugin().isActive(settings)); - assertTrue(new MockPlugin().isActive(settings)); - assertFalse(new MockPlugin().isActive(settings)); - } - - static class MockPlugin implements IPlugin { - - @Override - public Resource decorate(final ISettings settings, final ISnapshotContext snapshot) { - return null; - } - } -} \ No newline at end of file diff --git a/agent-api/src/test/java/com/intergral/deep/agent/api/spi/IDeepPluginTest.java b/agent-api/src/test/java/com/intergral/deep/agent/api/spi/IDeepPluginTest.java new file mode 100644 index 0000000..f8d4f44 --- /dev/null +++ b/agent-api/src/test/java/com/intergral/deep/agent/api/spi/IDeepPluginTest.java @@ -0,0 +1,34 @@ +/* + * 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.api.spi; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertSame; + +import org.junit.jupiter.api.Test; + +class IDeepPluginTest { + + @Test + void configure() { + final IDeepPlugin iDeepPlugin = new IDeepPlugin() { + }; + assertNotNull(iDeepPlugin.configure(null, null)); + assertSame(iDeepPlugin, iDeepPlugin.configure(null, null)); + } +} \ No newline at end of file diff --git a/agent/src/main/java/com/intergral/deep/agent/DeepAgent.java b/agent/src/main/java/com/intergral/deep/agent/DeepAgent.java index b04f400..3cbbc37 100644 --- a/agent/src/main/java/com/intergral/deep/agent/DeepAgent.java +++ b/agent/src/main/java/com/intergral/deep/agent/DeepAgent.java @@ -19,17 +19,12 @@ import com.intergral.deep.agent.api.DeepVersion; import com.intergral.deep.agent.api.IDeep; -import com.intergral.deep.agent.api.auth.IAuthProvider; -import com.intergral.deep.agent.api.logger.ITracepointLogger; -import com.intergral.deep.agent.api.plugin.IPlugin; -import com.intergral.deep.agent.api.plugin.IPlugin.IPluginRegistration; import com.intergral.deep.agent.api.resource.Resource; -import com.intergral.deep.agent.api.settings.ISettings; -import com.intergral.deep.agent.api.spi.ResourceProvider; +import com.intergral.deep.agent.api.spi.IDeepPlugin; import com.intergral.deep.agent.api.tracepoint.ITracepoint; import com.intergral.deep.agent.api.tracepoint.ITracepoint.ITracepointRegistration; import com.intergral.deep.agent.grpc.GrpcService; -import com.intergral.deep.agent.plugins.PluginLoader; +import com.intergral.deep.agent.plugins.PluginSpiLoader; import com.intergral.deep.agent.poll.LongPollService; import com.intergral.deep.agent.push.PushService; import com.intergral.deep.agent.resource.ResourceDetector; @@ -42,15 +37,12 @@ import java.util.Collections; import java.util.List; import java.util.Map; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * This is the agent that is provided via the API, and is what holds all deep together. */ public class DeepAgent implements IDeep { - private static final Logger LOGGER = LoggerFactory.getLogger(DeepAgent.class); private final Settings settings; private final GrpcService grpcService; private final LongPollService pollService; @@ -77,8 +69,9 @@ public DeepAgent(final Settings settings, * Start deep. */ public void start() { - final List iLoadedPlugins = PluginLoader.loadPlugins(settings, Reflection.getInstance()); - final Resource resource = ResourceDetector.configureResource(settings, DeepAgent.class.getClassLoader()); + final List iLoadedPlugins = PluginSpiLoader + .loadPlugins(settings, Reflection.getInstance(), DeepAgent.class.getClassLoader()); + final Resource resource = ResourceDetector.configureResource(this.settings, iLoadedPlugins); this.settings.setPlugins(iLoadedPlugins); this.settings.setResource(Resource.DEFAULT.merge(resource)); this.grpcService.start(); @@ -90,70 +83,6 @@ public String getVersion() { return DeepVersion.VERSION; } - @Override - public IPluginRegistration registerPlugin(final IPlugin plugin) { - this.settings.addPlugin(plugin); - - boolean isResourceProvider = false; - // if plugin provides resource definitions then merge them into the resource - if (plugin instanceof ResourceProvider) { - try { - final Resource resource = ((ResourceProvider) plugin).createResource(this.settings); - this.settings.setResource(this.settings.getResource().merge(resource)); - isResourceProvider = true; - } catch (Throwable t) { - LOGGER.error("Cannot create resource from plugin: {}", plugin.name(), t); - } - } - - final boolean isAuthProvider; - if (plugin instanceof IAuthProvider) { - final String settingAs = this.settings.getSettingAs(ISettings.KEY_AUTH_PROVIDER, String.class); - isAuthProvider = settingAs != null && settingAs.equals(plugin.getClass().getName()); - } else { - isAuthProvider = false; - } - - if (plugin instanceof ITracepointLogger) { - this.settings.setTracepointLogger((ITracepointLogger) plugin); - } - - final boolean finalIsResourceProvider = isResourceProvider; - return new IPluginRegistration() { - - @Override - public boolean isResourceProvider() { - return finalIsResourceProvider; - } - - @Override - public boolean isTracepointLogger() { - //noinspection ObjectEquality,EqualsBetweenInconvertibleTypes - return DeepAgent.this.settings.getTracepointLogger() == plugin; - } - - @Override - public boolean isAuthProvider() { - return isAuthProvider; - } - - @Override - public void unregister() { - settings.removePlugin(plugin); - // if plugin provides resource definitions then we need to recalculate the resource - if (plugin instanceof ResourceProvider) { - final Resource resource = ResourceDetector.configureResource(settings, DeepAgent.class.getClassLoader()); - DeepAgent.this.settings.setResource(Resource.DEFAULT.merge(resource)); - } - } - - @Override - public IPlugin get() { - return plugin; - } - }; - } - @Override public ITracepointRegistration registerTracepoint(final String path, final int line) { return registerTracepoint(path, line, Collections.emptyMap(), Collections.emptyList()); diff --git a/agent/src/main/java/com/intergral/deep/agent/grpc/GrpcService.java b/agent/src/main/java/com/intergral/deep/agent/grpc/GrpcService.java index f225b7a..abc5539 100644 --- a/agent/src/main/java/com/intergral/deep/agent/grpc/GrpcService.java +++ b/agent/src/main/java/com/intergral/deep/agent/grpc/GrpcService.java @@ -17,10 +17,10 @@ package com.intergral.deep.agent.grpc; -import com.intergral.deep.agent.Reflection; -import com.intergral.deep.agent.api.auth.AuthProvider; +import com.intergral.deep.agent.api.DeepRuntimeException; import com.intergral.deep.agent.api.auth.IAuthProvider; import com.intergral.deep.agent.api.settings.ISettings; +import com.intergral.deep.agent.api.spi.IDeepPlugin; import com.intergral.deep.agent.settings.Settings; import com.intergral.deep.proto.poll.v1.PollConfigGrpc; import com.intergral.deep.proto.tracepoint.v1.SnapshotServiceGrpc; @@ -37,6 +37,8 @@ import io.netty.buffer.UnpooledByteBufAllocator; import io.netty.channel.ChannelOption; import io.netty.channel.PreferHeapByteBufAllocator; +import java.util.Collection; +import java.util.Collections; import java.util.Map; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; @@ -166,7 +168,7 @@ public SnapshotServiceGrpc.SnapshotServiceStub snapshotService() { } private Metadata buildMetaData() { - final IAuthProvider provider = AuthProvider.provider(this.settings, Reflection.getInstance()); + final IAuthProvider provider = loadAuth(); final Map headers = provider.provide(); final Metadata metadata = new Metadata(); @@ -176,4 +178,32 @@ private Metadata buildMetaData() { } return metadata; } + + private IAuthProvider loadAuth() { + final String settingAs = this.settings.getSettingAs("service.auth.provider", String.class); + if (settingAs == null || settingAs.isEmpty()) { + return new NoopProvider(); + } + + final Collection plugins = this.settings.getPlugins(); + for (IDeepPlugin plugin : plugins) { + if (plugin.getClass().getName().equals(settingAs)) { + if (plugin instanceof IAuthProvider) { + return (IAuthProvider) plugin; + } else { + throw new DeepRuntimeException( + String.format("Cannot use plugin %s as auth provider, must implement IAuthProvider interface.", plugin.getClass().getName())); + } + } + } + throw new DeepRuntimeException(String.format("Cannot load auth provider %s", settingAs)); + } + + static class NoopProvider implements IAuthProvider { + + @Override + public Map provide() { + return Collections.emptyMap(); + } + } } diff --git a/agent/src/main/java/com/intergral/deep/agent/plugins/PluginLoader.java b/agent/src/main/java/com/intergral/deep/agent/plugins/PluginLoader.java deleted file mode 100644 index de51ac3..0000000 --- a/agent/src/main/java/com/intergral/deep/agent/plugins/PluginLoader.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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.plugins; - -import com.intergral.deep.agent.api.plugin.IPlugin; -import com.intergral.deep.agent.api.reflection.IReflection; -import com.intergral.deep.agent.api.reflection.ReflectionUtils; -import com.intergral.deep.agent.settings.Settings; -import java.lang.reflect.Constructor; -import java.util.ArrayList; -import java.util.List; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * this type deals with loading the plugins. - */ -public final class PluginLoader { - - private PluginLoader() { - } - - private static final Logger LOGGER = LoggerFactory.getLogger(PluginLoader.class); - - /** - * Using the current config load as many plugins as we can. - * - * @param settings the settings for deep - * @param reflection the reflection service to use - * @return the list of active and loaded plugins - */ - public static List loadPlugins(final Settings settings, final IReflection reflection) { - final List plugins = settings.getAsList("plugins"); - final List loadedPlugins = new ArrayList<>(); - for (String plugin : plugins) { - try { - final Class aClass = Class.forName(plugin); - final Constructor constructor = ReflectionUtils.findConstructor(aClass, reflection); - final IPlugin asPlugin = ReflectionUtils.callConstructor(constructor, settings, reflection); - if (asPlugin.isActive(settings)) { - loadedPlugins.add(asPlugin); - } - } catch (Exception e) { - LOGGER.error("Cannot load plugin {}", plugin, e); - } - } - return loadedPlugins; - } - -} diff --git a/agent/src/main/java/com/intergral/deep/agent/plugins/PluginSpiLoader.java b/agent/src/main/java/com/intergral/deep/agent/plugins/PluginSpiLoader.java new file mode 100644 index 0000000..8ec9492 --- /dev/null +++ b/agent/src/main/java/com/intergral/deep/agent/plugins/PluginSpiLoader.java @@ -0,0 +1,69 @@ +/* + * 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.plugins; + +import com.intergral.deep.agent.api.reflection.IReflection; +import com.intergral.deep.agent.api.settings.ISettings; +import com.intergral.deep.agent.api.spi.IConditional; +import com.intergral.deep.agent.api.spi.IDeepPlugin; +import com.intergral.deep.agent.resource.ResourceDetector; +import com.intergral.deep.agent.resource.SpiUtil; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * This acts as the main loader for plugins using the SPI loader system. + */ +public final class PluginSpiLoader { + + private PluginSpiLoader() { + } + + // Visible for testing + static final String ENABLED_PLUGIN_KEY = "deep.java.enabled.plugin"; + static final String DISABLED_PLUGIN_KEY = "deep.java.disabled.plugin"; + + /** + * Load all available plugins. + * + * @param settings the current settings + * @param reflection the reflection service + * @param loader the classloader to use + * @return the list of loaded plugins in order + * @see IDeepPlugin + */ + public static List loadPlugins(final ISettings settings, final IReflection reflection, final ClassLoader loader) { + Set enabledProviders = + new HashSet<>(settings.getAsList(ENABLED_PLUGIN_KEY)); + Set disabledProviders = + new HashSet<>(settings.getAsList(DISABLED_PLUGIN_KEY)); + final List iDeepPlugins = SpiUtil.loadOrdered(IDeepPlugin.class, loader); + return iDeepPlugins.stream() + .filter(plugin -> !ResourceDetector.isDisabled(plugin.getClass(), enabledProviders, disabledProviders)) + .filter(plugin -> { + if (plugin instanceof IConditional) { + return ((IConditional) plugin).isActive(); + } + return true; + }) + .map(plugin -> plugin.configure(settings, reflection)) + .collect(Collectors.toList()); + } +} diff --git a/agent/src/main/java/com/intergral/deep/agent/push/PushService.java b/agent/src/main/java/com/intergral/deep/agent/push/PushService.java index 6a39348..a075c6d 100644 --- a/agent/src/main/java/com/intergral/deep/agent/push/PushService.java +++ b/agent/src/main/java/com/intergral/deep/agent/push/PushService.java @@ -17,9 +17,10 @@ package com.intergral.deep.agent.push; -import com.intergral.deep.agent.api.plugin.IPlugin; import com.intergral.deep.agent.api.plugin.ISnapshotContext; +import com.intergral.deep.agent.api.plugin.ISnapshotDecorator; import com.intergral.deep.agent.api.resource.Resource; +import com.intergral.deep.agent.api.spi.IDeepPlugin; import com.intergral.deep.agent.grpc.GrpcService; import com.intergral.deep.agent.settings.Settings; import com.intergral.deep.agent.types.snapshot.EventSnapshot; @@ -58,15 +59,17 @@ public void pushSnapshot(final EventSnapshot snapshot, final ISnapshotContext co } private void decorate(final EventSnapshot snapshot, final ISnapshotContext context) { - final Collection plugins = this.settings.getPlugins(); - for (IPlugin plugin : plugins) { - try { - final Resource decorate = plugin.decorate(this.settings, context); - if (decorate != null) { - snapshot.mergeAttributes(decorate); + final Collection plugins = this.settings.getPlugins(); + for (IDeepPlugin plugin : plugins) { + if (plugin instanceof ISnapshotDecorator) { + try { + final Resource decorate = ((ISnapshotDecorator) plugin).decorate(this.settings, context); + if (decorate != null) { + snapshot.mergeAttributes(decorate); + } + } catch (Throwable t) { + LOGGER.error("Error processing plugin {}", plugin.getClass().getName()); } - } catch (Throwable t) { - LOGGER.error("Error processing plugin {}", plugin.getClass().getName()); } } snapshot.close(); diff --git a/agent/src/main/java/com/intergral/deep/agent/resource/EnvironmentResourceProvider.java b/agent/src/main/java/com/intergral/deep/agent/resource/EnvironmentResourceProvider.java index be3bee4..2002fa2 100644 --- a/agent/src/main/java/com/intergral/deep/agent/resource/EnvironmentResourceProvider.java +++ b/agent/src/main/java/com/intergral/deep/agent/resource/EnvironmentResourceProvider.java @@ -21,6 +21,7 @@ import com.intergral.deep.agent.api.resource.Resource; import com.intergral.deep.agent.api.resource.ResourceAttributes; import com.intergral.deep.agent.api.settings.ISettings; +import com.intergral.deep.agent.api.spi.IDeepPlugin; import com.intergral.deep.agent.api.spi.ResourceProvider; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; @@ -42,7 +43,7 @@ * * @see ISettings#getSettingAs(String, Class) */ -public class EnvironmentResourceProvider implements ResourceProvider { +public class EnvironmentResourceProvider implements IDeepPlugin, ResourceProvider { static final String SERVICE_NAME_PROPERTY = "service.name"; static final String ATTRIBUTE_PROPERTY = "resource.attributes"; diff --git a/agent/src/main/java/com/intergral/deep/agent/resource/JavaResourceDetector.java b/agent/src/main/java/com/intergral/deep/agent/resource/JavaResourceDetector.java index ff250cf..99413f1 100644 --- a/agent/src/main/java/com/intergral/deep/agent/resource/JavaResourceDetector.java +++ b/agent/src/main/java/com/intergral/deep/agent/resource/JavaResourceDetector.java @@ -19,13 +19,14 @@ import com.intergral.deep.agent.api.resource.Resource; import com.intergral.deep.agent.api.settings.ISettings; +import com.intergral.deep.agent.api.spi.IDeepPlugin; import com.intergral.deep.agent.api.spi.ResourceProvider; import java.util.Collections; /** * A resource provider that detects the hava version to add to the resource. */ -public class JavaResourceDetector implements ResourceProvider { +public class JavaResourceDetector implements IDeepPlugin, ResourceProvider { @Override public Resource createResource(final ISettings settings) { diff --git a/agent/src/main/java/com/intergral/deep/agent/resource/ResourceDetector.java b/agent/src/main/java/com/intergral/deep/agent/resource/ResourceDetector.java index cee695a..0dcb868 100644 --- a/agent/src/main/java/com/intergral/deep/agent/resource/ResourceDetector.java +++ b/agent/src/main/java/com/intergral/deep/agent/resource/ResourceDetector.java @@ -5,13 +5,14 @@ package com.intergral.deep.agent.resource; -import com.intergral.deep.agent.api.plugin.IPlugin; import com.intergral.deep.agent.api.resource.Resource; import com.intergral.deep.agent.api.spi.ConditionalResourceProvider; +import com.intergral.deep.agent.api.spi.IDeepPlugin; import com.intergral.deep.agent.api.spi.ResourceProvider; import com.intergral.deep.agent.settings.Settings; import java.util.Collections; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; @@ -24,18 +25,18 @@ private ResourceDetector() { } // Visible for testing - static final String DISABLED_ATTRIBUTE_KEYS = "deep.resource.disabled.keys"; - static final String ENABLED_PROVIDERS_KEY = "deep.java.enabled.resource.providers"; - static final String DISABLED_PROVIDERS_KEY = "deep.java.disabled.resource.providers"; + static final String DISABLED_ATTRIBUTE_KEYS = "resource.disabled.keys"; + static final String ENABLED_PROVIDERS_KEY = "java.enabled.resource.providers"; + static final String DISABLED_PROVIDERS_KEY = "java.disabled.resource.providers"; /** * Create and configure a resource for this agent. * - * @param settings the settings for the agent - * @param serviceClassLoader the class loader to use to load the SPI services + * @param settings the settings for the agent + * @param plugins the list of discovered plugins * @return the loaded resource */ - public static Resource configureResource(Settings settings, ClassLoader serviceClassLoader) { + public static Resource configureResource(final Settings settings, final List plugins) { Resource result = Resource.create(Collections.emptyMap()); Set enabledProviders = @@ -43,19 +44,11 @@ public static Resource configureResource(Settings settings, ClassLoader serviceC Set disabledProviders = new HashSet<>(settings.getAsList(DISABLED_PROVIDERS_KEY)); - for (ResourceProvider resourceProvider : - SpiUtil.loadOrdered(ResourceProvider.class, serviceClassLoader)) { - final Resource resource = getResource(settings, resourceProvider, enabledProviders, disabledProviders, result); - if (resource != null) { - result = resource; - } - } - - // let plugins also act as resource providers - for (IPlugin plugin : settings.getPlugins()) { + for (IDeepPlugin plugin : plugins) { if (!(plugin instanceof ResourceProvider)) { continue; } + final Resource resource = getResource(settings, (ResourceProvider) plugin, enabledProviders, disabledProviders, result); if (resource != null) { result = resource; @@ -69,13 +62,10 @@ public static Resource configureResource(Settings settings, ClassLoader serviceC private static Resource getResource(final Settings settings, final ResourceProvider resourceProvider, final Set enabledProviders, final Set disabledProviders, final Resource result) { - if (!enabledProviders.isEmpty() - && !enabledProviders.contains(resourceProvider.getClass().getName())) { - return null; - } - if (disabledProviders.contains(resourceProvider.getClass().getName())) { + if (isDisabled(resourceProvider.getClass(), enabledProviders, disabledProviders)) { return null; } + if (resourceProvider instanceof ConditionalResourceProvider && !((ConditionalResourceProvider) resourceProvider).shouldApply(settings, result)) { return null; @@ -83,6 +73,22 @@ private static Resource getResource(final Settings settings, final ResourceProvi return result.merge(resourceProvider.createResource(settings)); } + /** + * Check if a class is disabled based on the list of enabled and disabled classes. + * + * @param providerClass the class to check + * @param enabledClasses the enabled classes + * @param disabledClasses the disabled classes + * @return {@code true} if the class should be disabled, else {@code false} + */ + public static boolean isDisabled(final Class providerClass, final Set enabledClasses, final Set disabledClasses) { + if (!enabledClasses.isEmpty() + && !enabledClasses.contains(providerClass.getName())) { + return true; + } + return disabledClasses.contains(providerClass.getName()); + } + // visible for testing static Resource filterAttributes(Resource resource, Settings settings) { Set disabledKeys = new HashSet<>(settings.getAsList( 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 fe2bee7..36fff82 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 @@ -19,7 +19,7 @@ public final class SpiUtil { private SpiUtil() { } - static List loadOrdered(Class spiClass, + public static List loadOrdered(Class spiClass, ClassLoader serviceClassLoader) { return loadOrdered(spiClass, serviceClassLoader, ServiceLoader::load); } diff --git a/agent/src/main/java/com/intergral/deep/agent/settings/Settings.java b/agent/src/main/java/com/intergral/deep/agent/settings/Settings.java index 67043e2..21ec3db 100644 --- a/agent/src/main/java/com/intergral/deep/agent/settings/Settings.java +++ b/agent/src/main/java/com/intergral/deep/agent/settings/Settings.java @@ -19,9 +19,9 @@ import com.intergral.deep.agent.api.logger.ITracepointLogger; import com.intergral.deep.agent.api.logger.TracepointLogger; -import com.intergral.deep.agent.api.plugin.IPlugin; import com.intergral.deep.agent.api.resource.Resource; import com.intergral.deep.agent.api.settings.ISettings; +import com.intergral.deep.agent.api.spi.IDeepPlugin; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; @@ -35,7 +35,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.Properties; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; @@ -47,9 +46,8 @@ public class Settings implements ISettings { private static final AtomicBoolean IS_ACTIVE = new AtomicBoolean(true); private final Properties properties; - private final Collection customPlugins = new ArrayList<>(); private Resource resource; - private Collection plugins = Collections.emptyList(); + private Collection plugins = Collections.emptyList(); private ITracepointLogger tracepointLogger = new TracepointLogger(); private Settings(Properties properties) { @@ -229,6 +227,7 @@ public T getSettingAs(String key, Class clazz) { return coerc(systemProperty, clazz); } + @SuppressWarnings({"rawtypes", "unchecked"}) @Override public Map getMap(String key) { final Map settingAs = getSettingAs(key, Map.class); @@ -300,6 +299,7 @@ public void setResource(Resource resource) { * @param key the key for the setting * @return the value as a list */ + @SuppressWarnings({"rawtypes", "unchecked"}) public List getAsList(final String key) { final List settingAs = getSettingAs(key, List.class); if (settingAs == null) { @@ -313,10 +313,8 @@ public List getAsList(final String key) { * * @return the full list on plugins */ - public Collection getPlugins() { - final ArrayList actualPlugins = new ArrayList<>(this.plugins); - actualPlugins.addAll(this.customPlugins); - return actualPlugins; + public Collection getPlugins() { + return new ArrayList<>(this.plugins); } /** @@ -324,45 +322,10 @@ public Collection getPlugins() { * * @param plugins the plugins to use */ - public void setPlugins(Collection plugins) { + public void setPlugins(Collection plugins) { this.plugins = plugins; } - /** - * Add a custom plugin. - * - * @param plugin the plugin to add - * @see com.intergral.deep.agent.api.IDeep#registerPlugin(IPlugin) - */ - public void addPlugin(final IPlugin plugin) { - final Optional first = this.customPlugins.stream().filter(current -> current.name().equals(plugin.name())).findFirst(); - if (first.isPresent()) { - throw new IllegalStateException(String.format("Cannot add duplicate named (%s) plugin", plugin.name())); - } - this.customPlugins.add(plugin); - } - - /** - * Remove a plugin that was added via {@link #addPlugin(IPlugin)}. - * - * @param plugin the plugin to remove - */ - public void removePlugin(final IPlugin plugin) { - this.customPlugins.removeIf(current -> current.name().equals(plugin.name())); - } - - - @Override - public IPlugin getPlugin(final String name) { - final Collection allPlugins = this.getPlugins(); - for (IPlugin plugin : allPlugins) { - if (plugin.name().equals(name) || plugin.getClass().getName().equals(name)) { - return plugin; - } - } - return null; - } - /** * Is deep currently active. * diff --git a/agent/src/main/resources/META-INF/services/com.intergral.deep.agent.api.spi.IDeepPlugin b/agent/src/main/resources/META-INF/services/com.intergral.deep.agent.api.spi.IDeepPlugin new file mode 100644 index 0000000..5f72396 --- /dev/null +++ b/agent/src/main/resources/META-INF/services/com.intergral.deep.agent.api.spi.IDeepPlugin @@ -0,0 +1,22 @@ +# +# 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 . +# + +com.intergral.deep.agent.resource.JavaResourceDetector +com.intergral.deep.agent.resource.EnvironmentResourceProvider +com.intergral.deep.plugin.cf.CFPlugin +com.intergral.deep.plugin.JavaPlugin +com.intergral.deep.agent.api.auth.BasicAuthProvider diff --git a/agent/src/main/resources/deep_settings.properties b/agent/src/main/resources/deep_settings.properties index 6721434..e286372 100644 --- a/agent/src/main/resources/deep_settings.properties +++ b/agent/src/main/resources/deep_settings.properties @@ -32,7 +32,6 @@ in.app.exclude= # Use this to tell GRPC to use PreferHeapByteBufAllocator grpc.heap.allocator=false grpc.allocator=pooled -plugins=com.intergral.deep.plugin.JavaPlugin,com.intergral.deep.plugin.cf.CFPlugin # Define what the jsp compilation convention is # Default tomcat take index.jsp and make it into index_jsp.class diff --git a/agent/src/test/java/com/intergral/deep/agent/DeepAgentTest.java b/agent/src/test/java/com/intergral/deep/agent/DeepAgentTest.java index 184d791..f49406c 100644 --- a/agent/src/test/java/com/intergral/deep/agent/DeepAgentTest.java +++ b/agent/src/test/java/com/intergral/deep/agent/DeepAgentTest.java @@ -24,7 +24,6 @@ import static org.mockito.Mockito.times; import com.intergral.deep.agent.api.DeepVersion; -import com.intergral.deep.agent.api.plugin.IPlugin.IPluginRegistration; import com.intergral.deep.agent.api.tracepoint.ITracepoint; import com.intergral.deep.agent.api.tracepoint.ITracepoint.ITracepointRegistration; import com.intergral.deep.agent.settings.Settings; @@ -83,22 +82,6 @@ void start_shouldSetPluginsAndResource() throws IOException { } - @Test - void registerPlugin() { - final IPluginRegistration iPluginRegistration = deepAgent.registerPlugin((settings, snapshot) -> null); - - assertNotNull(iPluginRegistration.get()); - assertFalse(iPluginRegistration.isAuthProvider()); - assertFalse(iPluginRegistration.isTracepointLogger()); - assertFalse(iPluginRegistration.isResourceProvider()); - - Mockito.verify(settings, times(1)).addPlugin(Mockito.any()); - - iPluginRegistration.unregister(); - - Mockito.verify(settings, times(1)).removePlugin(Mockito.any()); - } - @Test void registerTracepoint() { final ITracepointRegistration iTracepointRegistration = deepAgent.registerTracepoint("some/path", 123); diff --git a/agent/src/test/java/com/intergral/deep/agent/grpc/GrpcServiceTest.java b/agent/src/test/java/com/intergral/deep/agent/grpc/GrpcServiceTest.java index 6468d4f..8c6de56 100644 --- a/agent/src/test/java/com/intergral/deep/agent/grpc/GrpcServiceTest.java +++ b/agent/src/test/java/com/intergral/deep/agent/grpc/GrpcServiceTest.java @@ -23,6 +23,7 @@ import com.intergral.deep.agent.api.auth.IAuthProvider; import com.intergral.deep.agent.api.settings.ISettings; +import com.intergral.deep.agent.api.spi.IDeepPlugin; import com.intergral.deep.agent.logging.Logger; import com.intergral.deep.agent.settings.Settings; import com.intergral.deep.proto.poll.v1.PollRequest; @@ -55,7 +56,6 @@ class GrpcServiceTest { private CountDownLatch pollLatch; private final AtomicReference pollRequest = new AtomicReference<>(); private CountDownLatch snapshotLatch; - private final AtomicReference snapshotRequest = new AtomicReference<>(); private final AtomicReference header = new AtomicReference<>(); private int port; @@ -76,7 +76,6 @@ void setUp() throws Exception { final TestSnapshotService testSnapshotService = new TestSnapshotService((snapshot, responseObserver) -> { final String headerVal = testInterceptor.contextKey().get(); header.set(headerVal); - snapshotRequest.set(snapshot); snapshotLatch.countDown(); responseObserver.onNext(SnapshotResponse.newBuilder().build()); responseObserver.onCompleted(); @@ -119,10 +118,13 @@ void serverCanConnect_poll() throws InterruptedException { map.put(ISettings.KEY_SERVICE_SECURE, "false"); map.put(ISettings.KEY_AUTH_PROVIDER, MockAuthProvider.class.getName()); - grpcService = new GrpcService(Settings.build(map)); + final Settings build = Settings.build(map); + build.setPlugins(Collections.singleton(new MockAuthProvider())); + grpcService = new GrpcService(build); final PollResponse pollResponse = grpcService.pollService().poll(PollRequest.newBuilder().setTsNanos(101010L).build()); assertEquals(202020L, pollResponse.getTsNanos()); + //noinspection ResultOfMethodCallIgnored pollLatch.await(5, TimeUnit.SECONDS); final PollRequest pollRequest = this.pollRequest.get(); @@ -139,7 +141,9 @@ void serverCanConnect_snapshot() throws InterruptedException { map.put(ISettings.KEY_SERVICE_SECURE, "false"); map.put(ISettings.KEY_AUTH_PROVIDER, MockAuthProvider.class.getName()); - grpcService = new GrpcService(Settings.build(map)); + final Settings build = Settings.build(map); + build.setPlugins(Collections.singleton(new MockAuthProvider())); + grpcService = new GrpcService(build); final CountDownLatch responseLatch = new CountDownLatch(1); final AtomicReference responseAtomicReference = new AtomicReference<>(); @@ -162,6 +166,7 @@ public void onCompleted() { } }); + //noinspection ResultOfMethodCallIgnored responseLatch.await(5, TimeUnit.SECONDS); final SnapshotResponse snapshotResponse = responseAtomicReference.get(); assertNotNull(snapshotResponse); @@ -169,7 +174,7 @@ public void onCompleted() { } - public static class MockAuthProvider implements IAuthProvider { + public static class MockAuthProvider implements IAuthProvider, IDeepPlugin { @Override public Map provide() { diff --git a/agent/src/test/java/com/intergral/deep/agent/plugins/PluginLoaderTest.java b/agent/src/test/java/com/intergral/deep/agent/plugins/PluginLoaderTest.java deleted file mode 100644 index 9a66886..0000000 --- a/agent/src/test/java/com/intergral/deep/agent/plugins/PluginLoaderTest.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * 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.plugins; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import com.intergral.deep.agent.Reflection; -import com.intergral.deep.agent.api.plugin.IPlugin; -import com.intergral.deep.agent.api.plugin.ISnapshotContext; -import com.intergral.deep.agent.api.resource.Resource; -import com.intergral.deep.agent.api.settings.ISettings; -import com.intergral.deep.agent.settings.Settings; -import com.intergral.deep.plugin.JavaPlugin; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import org.junit.jupiter.api.Test; - -class PluginLoaderTest { - - @Test - void canLoadNoPlugins() { - final List iPlugins = PluginLoader.loadPlugins(Settings.build(Collections.emptyMap()), Reflection.getInstance()); - assertEquals(1, iPlugins.size()); - assertEquals(iPlugins.get(0).name(), JavaPlugin.class.getName()); - } - - @Test - void canLoadBadPlugin() { - final HashMap agentArgs = new HashMap<>(); - agentArgs.put(ISettings.PLUGINS, BadPlugin.class.getName()); - final List iPlugins = PluginLoader.loadPlugins(Settings.build(agentArgs), Reflection.getInstance()); - assertEquals(0, iPlugins.size()); - } - - @Test - void canLoadGoodPlugin() { - final HashMap agentArgs = new HashMap<>(); - agentArgs.put(ISettings.PLUGINS, GoodPlugin.class.getName()); - final List iPlugins = PluginLoader.loadPlugins(Settings.build(agentArgs), Reflection.getInstance()); - assertEquals(1, iPlugins.size()); - assertEquals(iPlugins.get(0).name(), GoodPlugin.class.getName()); - } - - public static class BadPlugin { - - } - - public static class GoodPlugin implements IPlugin { - - @Override - public Resource decorate(final ISettings settings, final ISnapshotContext snapshot) { - return null; - } - } -} \ No newline at end of file diff --git a/agent/src/test/java/com/intergral/deep/agent/poll/LongPollServiceTest.java b/agent/src/test/java/com/intergral/deep/agent/poll/LongPollServiceTest.java index 1b0a5bf..fbfd7e3 100644 --- a/agent/src/test/java/com/intergral/deep/agent/poll/LongPollServiceTest.java +++ b/agent/src/test/java/com/intergral/deep/agent/poll/LongPollServiceTest.java @@ -59,29 +59,25 @@ class LongPollServiceTest { - private Server server; private LongPollService longPollService; private final AtomicReference request = new AtomicReference<>(null); private PollResponse response; - private Throwable responseError; - private int port; private GrpcService grpcService; @BeforeEach void setUp() throws IOException { final TestPollService testPollService = new TestPollService((req, responseObserver) -> { request.set(req); - if (responseError != null) { - responseObserver.onError(responseError); - } else { - responseObserver.onNext(response); - } + + responseObserver.onNext(response); + responseObserver.onCompleted(); }); // find a free port + int port; try (ServerSocket socket = new ServerSocket(0)) { port = socket.getLocalPort(); } @@ -183,6 +179,7 @@ void canHandleTracepointResponse() { longPollService.run(100); + //noinspection unchecked final ArgumentCaptor> captor = ArgumentCaptor.forClass(Collection.class); verify(instrumentationService).processBreakpoints(captor.capture()); diff --git a/agent/src/test/java/com/intergral/deep/agent/push/PushServiceTest.java b/agent/src/test/java/com/intergral/deep/agent/push/PushServiceTest.java index 010a8a6..83f0a25 100644 --- a/agent/src/test/java/com/intergral/deep/agent/push/PushServiceTest.java +++ b/agent/src/test/java/com/intergral/deep/agent/push/PushServiceTest.java @@ -24,10 +24,11 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import com.intergral.deep.agent.api.plugin.IPlugin; import com.intergral.deep.agent.api.plugin.ISnapshotContext; +import com.intergral.deep.agent.api.plugin.ISnapshotDecorator; import com.intergral.deep.agent.api.resource.Resource; import com.intergral.deep.agent.api.settings.ISettings; +import com.intergral.deep.agent.api.spi.IDeepPlugin; import com.intergral.deep.agent.grpc.GrpcService; import com.intergral.deep.agent.push.PushService.LoggingObserver; import com.intergral.deep.agent.settings.Settings; @@ -77,7 +78,8 @@ void canPushSnapshot() { @Test void doesDecorate() { - settings.addPlugin(new TestDecorator()); + + settings.setPlugins(Collections.singleton(new TestDecorator())); final ISnapshotContext context = Mockito.mock(ISnapshotContext.class); pushService.pushSnapshot(new MockEventSnapshot(), context); @@ -94,7 +96,7 @@ void doesDecorate() { assertEquals("value", attributes.getValue().getStringValue()); } - public static class TestDecorator implements IPlugin { + public static class TestDecorator implements IDeepPlugin, ISnapshotDecorator { @Override public Resource decorate(final ISettings settings, final ISnapshotContext snapshot) { diff --git a/agent/src/test/java/com/intergral/deep/agent/resource/ResourceDetectorTest.java b/agent/src/test/java/com/intergral/deep/agent/resource/ResourceDetectorTest.java index 0920be3..c142625 100644 --- a/agent/src/test/java/com/intergral/deep/agent/resource/ResourceDetectorTest.java +++ b/agent/src/test/java/com/intergral/deep/agent/resource/ResourceDetectorTest.java @@ -22,6 +22,7 @@ import com.intergral.deep.agent.api.resource.Resource; import com.intergral.deep.agent.settings.Settings; +import java.util.Collections; import java.util.HashMap; import org.junit.jupiter.api.Test; @@ -33,7 +34,7 @@ void loadsResource() { agentArgs.put(ResourceDetector.ENABLED_PROVIDERS_KEY, ""); agentArgs.put(ResourceDetector.DISABLED_PROVIDERS_KEY, JavaResourceDetector.class.getName()); final Settings settings = Settings.build(agentArgs); - final Resource resource = ResourceDetector.configureResource(settings, getClass().getClassLoader()); + final Resource resource = ResourceDetector.configureResource(settings, Collections.singletonList(new JavaResourceDetector())); assertNotNull(resource); assertEquals(0, resource.getAttributes().size()); @@ -42,7 +43,7 @@ void loadsResource() { @Test void loadResourceFromSettings() { final Settings settings = Settings.build(new HashMap<>()); - final Resource resource = ResourceDetector.configureResource(settings, getClass().getClassLoader()); + final Resource resource = ResourceDetector.configureResource(settings, Collections.singletonList(new JavaResourceDetector())); assertEquals(System.getProperty("java.version"), resource.getAttributes().get("java_version")); } @@ -51,7 +52,7 @@ void loadResourceFromConfig() { final HashMap agentArgs = new HashMap<>(); agentArgs.put(EnvironmentResourceProvider.ATTRIBUTE_PROPERTY, "key=value,other=thing"); final Settings settings = Settings.build(agentArgs); - final Resource resource = ResourceDetector.configureResource(settings, getClass().getClassLoader()); + final Resource resource = ResourceDetector.configureResource(settings, Collections.singletonList(new EnvironmentResourceProvider())); assertEquals("value", resource.getAttributes().get("key")); assertEquals("thing", resource.getAttributes().get("other")); diff --git a/agent/src/test/java/com/intergral/deep/agent/settings/SettingsTest.java b/agent/src/test/java/com/intergral/deep/agent/settings/SettingsTest.java index db5da1e..a5a0282 100644 --- a/agent/src/test/java/com/intergral/deep/agent/settings/SettingsTest.java +++ b/agent/src/test/java/com/intergral/deep/agent/settings/SettingsTest.java @@ -24,10 +24,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import com.intergral.deep.agent.api.logger.ITracepointLogger; -import com.intergral.deep.agent.api.plugin.IPlugin; -import com.intergral.deep.agent.api.plugin.ISnapshotContext; -import com.intergral.deep.agent.api.resource.Resource; -import com.intergral.deep.agent.api.settings.ISettings; import com.intergral.deep.agent.settings.Settings.InvalidConfigException; import java.net.MalformedURLException; import java.net.URL; @@ -38,7 +34,6 @@ import java.util.logging.Level; import java.util.regex.Pattern; import org.junit.jupiter.api.Test; -import org.mockito.Mock; import org.mockito.Mockito; class SettingsTest { @@ -118,28 +113,6 @@ void canHandleURLs() { } } - @Test - void plugins() { - - final Settings settings = Settings.build(new HashMap<>()); - - final IPlugin plugin = new IPlugin() { - @Override - public Resource decorate(final ISettings settings, final ISnapshotContext snapshot) { - return null; - } - }; - settings.addPlugin(plugin); - final IllegalStateException illegalStateException = assertThrows(IllegalStateException.class, () -> settings.addPlugin(plugin)); - assertEquals("Cannot add duplicate named (com.intergral.deep.agent.settings.SettingsTest$1) plugin", - illegalStateException.getMessage()); - - assertEquals(1, settings.getPlugins().size()); - settings.removePlugin(plugin); - - assertEquals(0, settings.getPlugins().size()); - } - @Test void setActive() { diff --git a/examples/agent-load/src/main/java/com/intergral/deep/examples/Main.java b/examples/agent-load/src/main/java/com/intergral/deep/examples/Main.java index a64caf1..21e7e36 100644 --- a/examples/agent-load/src/main/java/com/intergral/deep/examples/Main.java +++ b/examples/agent-load/src/main/java/com/intergral/deep/examples/Main.java @@ -18,7 +18,6 @@ package com.intergral.deep.examples; -import com.intergral.deep.agent.api.resource.Resource; import com.intergral.deep.api.DeepAPI; import java.util.Collections; @@ -46,27 +45,22 @@ public static void main(String[] args) throws Throwable { // java.lang.IllegalStateException: Must start Deep first! System.out.println(DeepAPI.api().getVersion()); - // Use the API to register a plugin - // This plugin will attach the attribute 'example' to the created snapshot - // you should also see the log line 'custom plugin' when you run this example - DeepAPI.api().registerPlugin((settings, snapshot) -> { - System.out.println("custom plugin"); - return Resource.create(Collections.singletonMap("example", "agent_load")); - }); - // USe the API to create a tracepoint that will fire forever DeepAPI.api() .registerTracepoint("com/intergral/deep/examples/SimpleTest", 46, Collections.singletonMap("fire_count", "-1"), Collections.emptyList()); 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-load/src/main/java/com/intergral/deep/examples/MyPlugin.java b/examples/agent-load/src/main/java/com/intergral/deep/examples/MyPlugin.java new file mode 100644 index 0000000..dc62379 --- /dev/null +++ b/examples/agent-load/src/main/java/com/intergral/deep/examples/MyPlugin.java @@ -0,0 +1,36 @@ +/* + * 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 com.intergral.deep.agent.api.plugin.ISnapshotContext; +import com.intergral.deep.agent.api.plugin.ISnapshotDecorator; +import com.intergral.deep.agent.api.resource.Resource; +import com.intergral.deep.agent.api.settings.ISettings; +import com.intergral.deep.agent.api.spi.IDeepPlugin; + +/** + * This is an example plugin. + */ +public class MyPlugin implements IDeepPlugin, ISnapshotDecorator { + + @Override + public Resource decorate(final ISettings settings, final ISnapshotContext snapshot) { + System.out.println("custom plugin"); + return null; + } +} diff --git a/agent/src/main/resources/META-INF/services/com.intergral.deep.agent.api.spi.ResourceProvider b/examples/agent-load/src/main/resources/META-INF/services/com.intergral.deep.agent.api.spi.IDeepPlugin similarity index 86% rename from agent/src/main/resources/META-INF/services/com.intergral.deep.agent.api.spi.ResourceProvider rename to examples/agent-load/src/main/resources/META-INF/services/com.intergral.deep.agent.api.spi.IDeepPlugin index cdf58a7..67cbd67 100644 --- a/agent/src/main/resources/META-INF/services/com.intergral.deep.agent.api.spi.ResourceProvider +++ b/examples/agent-load/src/main/resources/META-INF/services/com.intergral.deep.agent.api.spi.IDeepPlugin @@ -15,5 +15,4 @@ # along with this program. If not, see . # -com.intergral.deep.agent.resource.JavaResourceDetector -com.intergral.deep.agent.resource.EnvironmentResourceProvider \ No newline at end of file +com.intergral.deep.examples.MyPlugin \ No newline at end of file diff --git a/examples/dynamic-load/src/main/java/com/intergral/deep/examples/Main.java b/examples/dynamic-load/src/main/java/com/intergral/deep/examples/Main.java index 241a101..ce74ddf 100644 --- a/examples/dynamic-load/src/main/java/com/intergral/deep/examples/Main.java +++ b/examples/dynamic-load/src/main/java/com/intergral/deep/examples/Main.java @@ -21,7 +21,6 @@ import com.intergral.deep.Deep; import com.intergral.deep.agent.api.IDeep; import com.intergral.deep.agent.api.reflection.IReflection; -import com.intergral.deep.agent.api.resource.Resource; import com.intergral.deep.agent.api.settings.ISettings; import com.intergral.deep.api.DeepAPI; import java.nio.file.Path; @@ -48,12 +47,13 @@ public class Main { public static void main(String[] args) throws Throwable { // this is only needed in this example as we are using a local built module // if using the dependency from maven you do not need to set the path + //noinspection DataFlowIssue Path jarPath = Paths.get(Main.class.getResource("/").toURI()) .getParent() .getParent() .getParent() .getParent() - .resolve("agent/target/deep-1.0-SNAPSHOT.jar"); + .resolve("agent/target/agent-1.0-SNAPSHOT.jar"); // Dynamically configure and attach the deep agent Deep.config() @@ -70,27 +70,22 @@ public static void main(String[] args) throws Throwable { System.out.println(DeepAPI.api().getVersion()); System.out.println(DeepAPI.reflection()); - // Use the API to register a plugin - // This plugin will attach the attribute 'example' to the created snapshot - // you should also see the log line 'custom plugin' when you run this example - DeepAPI.api().registerPlugin((settings, snapshot) -> { - System.out.println("custom plugin"); - return Resource.create(Collections.singletonMap("example", "dynamic_load")); - }); - // USe the API to create a tracepoint that will fire forever DeepAPI.api() .registerTracepoint("com/intergral/deep/examples/SimpleTest", 46, Collections.singletonMap("fire_count", "-1"), Collections.emptyList()); 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/dynamic-load/src/main/java/com/intergral/deep/examples/MyPlugin.java b/examples/dynamic-load/src/main/java/com/intergral/deep/examples/MyPlugin.java new file mode 100644 index 0000000..dc62379 --- /dev/null +++ b/examples/dynamic-load/src/main/java/com/intergral/deep/examples/MyPlugin.java @@ -0,0 +1,36 @@ +/* + * 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 com.intergral.deep.agent.api.plugin.ISnapshotContext; +import com.intergral.deep.agent.api.plugin.ISnapshotDecorator; +import com.intergral.deep.agent.api.resource.Resource; +import com.intergral.deep.agent.api.settings.ISettings; +import com.intergral.deep.agent.api.spi.IDeepPlugin; + +/** + * This is an example plugin. + */ +public class MyPlugin implements IDeepPlugin, ISnapshotDecorator { + + @Override + public Resource decorate(final ISettings settings, final ISnapshotContext snapshot) { + System.out.println("custom plugin"); + return null; + } +} diff --git a/examples/dynamic-load/src/main/resources/META-INF/services/com.intergral.deep.agent.api.spi.IDeepPlugin b/examples/dynamic-load/src/main/resources/META-INF/services/com.intergral.deep.agent.api.spi.IDeepPlugin new file mode 100644 index 0000000..67cbd67 --- /dev/null +++ b/examples/dynamic-load/src/main/resources/META-INF/services/com.intergral.deep.agent.api.spi.IDeepPlugin @@ -0,0 +1,18 @@ +# +# 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 . +# + +com.intergral.deep.examples.MyPlugin \ No newline at end of file diff --git a/it-tests/cf-tests/src/test/cfml/testFile.cfm b/it-tests/cf-tests/src/test/cfml/testFile.cfm index a4a683d..1a216e0 100644 --- a/it-tests/cf-tests/src/test/cfml/testFile.cfm +++ b/it-tests/cf-tests/src/test/cfml/testFile.cfm @@ -1,3 +1,3 @@ - + #i# diff --git a/it-tests/cf-tests/src/test/java/com/intergral/deep/tests/it/cf/ACFTest.java b/it-tests/cf-tests/src/test/java/com/intergral/deep/tests/it/cf/ACFTest.java index 6b9b492..0bc8fb0 100644 --- a/it-tests/cf-tests/src/test/java/com/intergral/deep/tests/it/cf/ACFTest.java +++ b/it-tests/cf-tests/src/test/java/com/intergral/deep/tests/it/cf/ACFTest.java @@ -22,6 +22,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; +import com.intergral.deep.proto.common.v1.KeyValue; import com.intergral.deep.proto.poll.v1.PollResponse; import com.intergral.deep.proto.poll.v1.ResponseType; import com.intergral.deep.proto.tracepoint.v1.Snapshot; @@ -36,6 +37,7 @@ import java.net.URISyntaxException; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; @@ -53,21 +55,21 @@ public abstract class ACFTest { private static final AtomicReference snapshot = new AtomicReference<>(); - private static CountDownLatch loglatch; + private static CountDownLatch logLatch; private static Server server; - private static CountDownLatch snapshotlatch; + private static CountDownLatch snapshotLatch; private final GenericContainer container; - private TestPollService pollService; public ACFTest(final String dockerImageName) { - loglatch = new CountDownLatch(1); - snapshotlatch = new CountDownLatch(1); + logLatch = new CountDownLatch(1); + snapshotLatch = new CountDownLatch(1); Path agentTarget = null; Path testFilePath = null; Path jvmConfigPath = null; try { + //noinspection DataFlowIssue final Path targetPath = Paths.get(ACFTest.class.getResource("/").toURI()).getParent(); agentTarget = targetPath.getParent() .getParent() @@ -83,6 +85,7 @@ public ACFTest(final String dockerImageName) { final String testHost = System.getProperty("nv.test.host", "172.17.0.1"); + //noinspection resource container = new GenericContainer<>(new ImageFromDockerfile("cftest", true) // add the nv jar into the context of the docker file .withFileFromPath("deep.jar", new File(property).toPath()) @@ -102,7 +105,7 @@ public ACFTest(final String dockerImageName) { .withLogConsumer(outputFrame -> { System.out.println(outputFrame.getUtf8String()); if (outputFrame.getUtf8String().contains("ColdFusion started")) { - loglatch.countDown(); + logLatch.countDown(); } }) .withExposedPorts(8500) @@ -124,7 +127,7 @@ public ACFTest(final String dockerImageName) { void setUp() throws Exception { final CountDownLatch grpcConnectLatch = new CountDownLatch(1); - pollService = new TestPollService((request, responseObserver) -> { + TestPollService pollService = new TestPollService((request, responseObserver) -> { responseObserver.onNext(PollResponse.newBuilder() .setResponseType(ResponseType.UPDATE) .setCurrentHash("1") @@ -140,7 +143,7 @@ void setUp() throws Exception { final TestSnapshotService testSnapshotService = new TestSnapshotService( (request, responseObserver) -> { snapshot.set(request); - snapshotlatch.countDown(); + snapshotLatch.countDown(); }); server = ServerBuilder.forPort(9999) @@ -155,7 +158,7 @@ void setUp() throws Exception { System.out.println("GRPC Connected"); // await cf start up - assertTrue(loglatch.await(600, TimeUnit.SECONDS)); + assertTrue(logLatch.await(600, TimeUnit.SECONDS)); System.out.println("CF Started."); } @@ -169,8 +172,9 @@ void afterAll() { @Test void checkCfTracepoint() throws Exception { + //noinspection HttpUrlsUsage final String uri = - "http://" + container.getContainerIpAddress() + ":" + container.getMappedPort(8500) + "http://" + container.getHost() + ":" + container.getMappedPort(8500) + "/CTA/tests/testFile.cfm"; final Request build = new Request.Builder().url(uri).build(); @@ -182,16 +186,18 @@ void checkCfTracepoint() throws Exception { final Call call = client.newCall(build); try (final Response execute = call.execute()) { final ResponseBody body = execute.body(); + //noinspection DataFlowIssue final String s = new String(body.bytes()); System.out.println(s); break; } catch (Exception e) { e.printStackTrace(); } + //noinspection BusyWait Thread.sleep(1000); } - assertTrue(snapshotlatch.await(5, TimeUnit.MINUTES)); + assertTrue(snapshotLatch.await(5, TimeUnit.MINUTES)); final Snapshot snapshot = ACFTest.snapshot.get(); @@ -216,6 +222,20 @@ void checkCfTracepoint() throws Exception { assertEquals("I", iResult.variableId().getName()); assertEquals("java.lang.Integer", iResult.variable().getType()); assertEquals("100", iResult.variable().getValue()); + + checkPluignData(snapshot); + } + + protected abstract void checkPluignData(final Snapshot snapshot); + + protected KeyValue findAttribute(final Snapshot snapshot, final String key) { + final List attributesList = snapshot.getAttributesList(); + for (KeyValue keyValue : attributesList) { + if (keyValue.getKey().equals(key)) { + return keyValue; + } + } + return null; } } diff --git a/it-tests/cf-tests/src/test/java/com/intergral/deep/tests/it/cf/Cf2018Test.java b/it-tests/cf-tests/src/test/java/com/intergral/deep/tests/it/cf/Cf2018Test.java index 3148c94..ef34730 100644 --- a/it-tests/cf-tests/src/test/java/com/intergral/deep/tests/it/cf/Cf2018Test.java +++ b/it-tests/cf-tests/src/test/java/com/intergral/deep/tests/it/cf/Cf2018Test.java @@ -17,9 +17,23 @@ package com.intergral.deep.tests.it.cf; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import com.intergral.deep.proto.common.v1.KeyValue; +import com.intergral.deep.proto.tracepoint.v1.Snapshot; + public class Cf2018Test extends ACFTest { public Cf2018Test() { super("adobecoldfusion/coldfusion:latest-2018"); } + + @Override + protected void checkPluignData(final Snapshot snapshot) { + final KeyValue cfVersion = findAttribute(snapshot, "cf_version"); + assertEquals("2018", cfVersion.getValue().getStringValue()); + final KeyValue appName = findAttribute(snapshot, "app_name"); + assertEquals("cf-test-app", appName.getValue().getStringValue()); + } + } diff --git a/it-tests/cf-tests/src/test/java/com/intergral/deep/tests/it/cf/Cf2021Test.java b/it-tests/cf-tests/src/test/java/com/intergral/deep/tests/it/cf/Cf2021Test.java new file mode 100644 index 0000000..053e87f --- /dev/null +++ b/it-tests/cf-tests/src/test/java/com/intergral/deep/tests/it/cf/Cf2021Test.java @@ -0,0 +1,39 @@ +/* + * 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.tests.it.cf; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import com.intergral.deep.proto.common.v1.KeyValue; +import com.intergral.deep.proto.tracepoint.v1.Snapshot; + +public class Cf2021Test extends ACFTest { + + public Cf2021Test() { + super("adobecoldfusion/coldfusion:latest-2021"); + } + + @Override + protected void checkPluignData(final Snapshot snapshot) { + final KeyValue cfVersion = findAttribute(snapshot, "cf_version"); + assertEquals("2021", cfVersion.getValue().getStringValue()); + final KeyValue appName = findAttribute(snapshot, "app_name"); + assertEquals("cf-test-app", appName.getValue().getStringValue()); + } + +} diff --git a/it-tests/cf-tests/src/test/java/com/intergral/deep/tests/it/cf/Cf2023Test.java b/it-tests/cf-tests/src/test/java/com/intergral/deep/tests/it/cf/Cf2023Test.java new file mode 100644 index 0000000..1dd015e --- /dev/null +++ b/it-tests/cf-tests/src/test/java/com/intergral/deep/tests/it/cf/Cf2023Test.java @@ -0,0 +1,39 @@ +/* + * 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.tests.it.cf; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import com.intergral.deep.proto.common.v1.KeyValue; +import com.intergral.deep.proto.tracepoint.v1.Snapshot; + +public class Cf2023Test extends ACFTest { + + public Cf2023Test() { + super("adobecoldfusion/coldfusion:latest-2023"); + } + + @Override + protected void checkPluignData(final Snapshot snapshot) { + final KeyValue cfVersion = findAttribute(snapshot, "cf_version"); + assertEquals("2023", cfVersion.getValue().getStringValue()); + final KeyValue appName = findAttribute(snapshot, "app_name"); + assertEquals("cf-test-app", appName.getValue().getStringValue()); + } + +} diff --git a/it-tests/java-tests/src/test/java/com/intergral/deep/tests/it/java/ADeepITTest.java b/it-tests/java-tests/src/test/java/com/intergral/deep/tests/it/java/ADeepITTest.java index 1de6666..49b2a99 100644 --- a/it-tests/java-tests/src/test/java/com/intergral/deep/tests/it/java/ADeepITTest.java +++ b/it-tests/java-tests/src/test/java/com/intergral/deep/tests/it/java/ADeepITTest.java @@ -35,14 +35,13 @@ import com.intergral.deep.tests.grpc.TestSnapshotService; import io.grpc.Server; import io.grpc.ServerBuilder; -import io.grpc.stub.StreamObserver; import java.io.File; import java.lang.management.ManagementFactory; import java.lang.reflect.Method; -import java.util.Collections; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.HashMap; import java.util.Map; -import java.util.Set; import java.util.concurrent.atomic.AtomicReference; import net.bytebuddy.agent.ByteBuddyAgent; import org.junit.jupiter.api.BeforeAll; @@ -52,18 +51,16 @@ public abstract class ADeepITTest { protected static ResettableCountDownLatch grpcConnectLatch; protected static Server server; - protected static ResettableCountDownLatch snapshotlatch; + protected static ResettableCountDownLatch snapshotLatch; protected static PollResponse nextResponse; protected static Object nerdVision; protected static AtomicReference snapshotAtomicReference = new AtomicReference<>(); - private static TestPollService pollService; - private static TestSnapshotService snapshotService; @BeforeAll static void beforeAll() throws Exception { - snapshotlatch = new ResettableCountDownLatch(1); + snapshotLatch = new ResettableCountDownLatch(1); grpcConnectLatch = new ResettableCountDownLatch(1); if (nerdVision != null) { @@ -71,43 +68,41 @@ static void beforeAll() throws Exception { } // we have to be careful with the class loading when testing the agent in our own tests // we build all the message objects here to ensure we load into the correct classloader + //noinspection unused final PollResponse build = PollResponse.newBuilder() .setCurrentHash("") .setResponseType(ResponseType.UPDATE) .addResponse(TracePointConfig.newBuilder().setPath("").setLineNumber(1).build()) .build(); + //noinspection unused final PollRequest pollRequest = PollRequest.newBuilder() .setResource(Resource.newBuilder().addAttributes(KeyValue.newBuilder() .setKey("").setValue(AnyValue.newBuilder().build()).build()).build()) .build(); SnapshotResponse.newBuilder().build(); WatchResult.newBuilder().build(); + //noinspection unused final WatchResult.ResultCase goodResult = WatchResult.ResultCase.GOOD_RESULT; - Snapshot.newBuilder() + //noinspection unused + final Snapshot snapshot = Snapshot.newBuilder() .addFrames(StackFrame.newBuilder().addVariables(VariableID.newBuilder().build()).build()) .putVarLookup("", Variable.newBuilder().build()) .build(); + // See comment above - pollService = new TestPollService(new TestPollService.ICallback() { - @Override - public void poll(final PollRequest request, final StreamObserver observer) { - if (nextResponse != null) { - observer.onNext(nextResponse); - } - observer.onCompleted(); - grpcConnectLatch.countDown(); + TestPollService pollService = new TestPollService((request, observer) -> { + if (nextResponse != null) { + observer.onNext(nextResponse); } + observer.onCompleted(); + grpcConnectLatch.countDown(); }); - snapshotService = new TestSnapshotService(new TestSnapshotService.ICallback() { - @Override - public void send(final Snapshot request, - final StreamObserver responseObserver) { - System.out.println("send"); - snapshotAtomicReference.set(request); - responseObserver.onCompleted(); - snapshotlatch.countDown(); - } + TestSnapshotService snapshotService = new TestSnapshotService((request, responseObserver) -> { + System.out.println("send"); + snapshotAtomicReference.set(request); + responseObserver.onCompleted(); + snapshotLatch.countDown(); }); server = ServerBuilder.forPort(9898) @@ -116,24 +111,30 @@ public void send(final Snapshot request, .build(); server.start(); - final String nvPath = System.getProperty("mvn.agentPath", - "/home/bdonnell/repo/github/intergral/deep-java-client/deep-java-client/agent/target/agent-1.0-SNAPSHOT.jar"); + //noinspection DataFlowIssue + final Path rootPath = Paths.get(ADeepITTest.class.getResource("/").toURI()) + .getParent() // test + .getParent() // src + .getParent() // java-tests + .getParent(); // it-tests + final Path jarPath = rootPath // root + .resolve("agent/target/agent-1.0-SNAPSHOT.jar"); + + final String nvPath = System.getProperty("mvn.agentPath", jarPath.toAbsolutePath().toString()); final Map config = new HashMap<>(); config.put("service.url", "localhost:9898"); config.put("service.secure", "false"); config.put("logging.level", "FINE"); config.put("deep.path", nvPath); - config.put("transform.path", - "/home/bdonnell/repo/github/intergral/deep-java-client/deep-java-client/dispath"); + config.put("transform.path", rootPath.resolve("dispath").toAbsolutePath().toString()); ByteBuddyAgent.attach(new File(nvPath), getPid(), configAsArgs(config)); final Class aClass = Class.forName("com.intergral.deep.agent.AgentImpl"); final Method registerBreakpointService = aClass.getDeclaredMethod("loadDeepAPI"); - final Object invoke = registerBreakpointService.invoke(null); - nerdVision = invoke; + nerdVision = registerBreakpointService.invoke(null); } static String getPid() { @@ -152,13 +153,9 @@ static String configAsArgs(final Map config) { return stringBuilder.toString(); } - public static Set setOf(final T frame) { - return Collections.singleton(frame); - } - @BeforeEach void setUp() { - snapshotlatch = new ResettableCountDownLatch(1); + snapshotLatch = new ResettableCountDownLatch(1); grpcConnectLatch = new ResettableCountDownLatch(1); } diff --git a/it-tests/java-tests/src/test/java/com/intergral/deep/tests/it/java/DeepITTest.java b/it-tests/java-tests/src/test/java/com/intergral/deep/tests/it/java/DeepITTest.java index d9e7e31..59b43a4 100644 --- a/it-tests/java-tests/src/test/java/com/intergral/deep/tests/it/java/DeepITTest.java +++ b/it-tests/java-tests/src/test/java/com/intergral/deep/tests/it/java/DeepITTest.java @@ -61,7 +61,7 @@ void checkBPFires() throws Exception { } }).start(); - snapshotlatch.await(5, TimeUnit.MINUTES); + snapshotLatch.await(5, TimeUnit.MINUTES); final Snapshot snapshot = snapshotAtomicReference.get(); assertEquals(snapshot.getVarLookupMap().get("1").getChildren(0).getName(), "name"); diff --git a/plugins/cf-plugin/src/main/java/com/intergral/deep/plugin/cf/CFPlugin.java b/plugins/cf-plugin/src/main/java/com/intergral/deep/plugin/cf/CFPlugin.java index 4fdb05f..dc74473 100644 --- a/plugins/cf-plugin/src/main/java/com/intergral/deep/plugin/cf/CFPlugin.java +++ b/plugins/cf-plugin/src/main/java/com/intergral/deep/plugin/cf/CFPlugin.java @@ -17,10 +17,12 @@ package com.intergral.deep.plugin.cf; -import com.intergral.deep.agent.api.plugin.IPlugin; import com.intergral.deep.agent.api.plugin.ISnapshotContext; +import com.intergral.deep.agent.api.plugin.ISnapshotDecorator; import com.intergral.deep.agent.api.resource.Resource; import com.intergral.deep.agent.api.settings.ISettings; +import com.intergral.deep.agent.api.spi.IConditional; +import com.intergral.deep.agent.api.spi.IDeepPlugin; import java.util.HashMap; /** @@ -28,7 +30,7 @@ *

* This plugin will attach the cf version and the cf app name to the captured snapshots. */ -public class CFPlugin implements IPlugin { +public class CFPlugin implements IDeepPlugin, IConditional, ISnapshotDecorator { @Override public Resource decorate(final ISettings settings, final ISnapshotContext context) { @@ -48,10 +50,7 @@ public Resource decorate(final ISettings settings, final ISnapshotContext contex } @Override - public boolean isActive(final ISettings settings) { - if (!Utils.isCFServer()) { - return false; - } - return IPlugin.super.isActive(settings); + public boolean isActive() { + return Utils.isCFServer(); } } diff --git a/plugins/java-plugin/src/main/java/com/intergral/deep/plugin/JavaPlugin.java b/plugins/java-plugin/src/main/java/com/intergral/deep/plugin/JavaPlugin.java index 8f8c049..6bb00b8 100644 --- a/plugins/java-plugin/src/main/java/com/intergral/deep/plugin/JavaPlugin.java +++ b/plugins/java-plugin/src/main/java/com/intergral/deep/plugin/JavaPlugin.java @@ -17,17 +17,18 @@ package com.intergral.deep.plugin; -import com.intergral.deep.agent.api.plugin.IPlugin; import com.intergral.deep.agent.api.plugin.ISnapshotContext; +import com.intergral.deep.agent.api.plugin.ISnapshotDecorator; import com.intergral.deep.agent.api.resource.Resource; import com.intergral.deep.agent.api.settings.ISettings; +import com.intergral.deep.agent.api.spi.IDeepPlugin; import java.util.HashMap; import java.util.Map; /** * This plugin captures the thread name of the thread the snapshot was cpatured on. */ -public class JavaPlugin implements IPlugin { +public class JavaPlugin implements IDeepPlugin, ISnapshotDecorator { private final Map basic = new HashMap<>();