From b7d33b3cb6a1f8f3c0eafd95550056c261c39433 Mon Sep 17 00:00:00 2001 From: Frank Chen Date: Sat, 2 Nov 2024 14:25:34 +0800 Subject: [PATCH 1/4] Split inteceptor class loader and plugin class loader --- .../controller/AgentControllerService.java | 4 +- .../aop/interceptor/InterceptorSupplier.java | 4 +- .../interceptor/plugin/PluginResolver.java | 8 +- .../loader/InterceptorClassLoader.java | 101 ++++++++++++++++++ ...ava => InterceptorClassLoaderManager.java} | 21 +--- .../loader/PluginClassLoader.java | 84 ++------------- .../MetricRegistryFactory$Create.java | 4 +- 7 files changed, 126 insertions(+), 100 deletions(-) create mode 100644 agent/agent-instrumentation/src/main/java/org/bithon/agent/instrumentation/loader/InterceptorClassLoader.java rename agent/agent-instrumentation/src/main/java/org/bithon/agent/instrumentation/loader/{PluginClassLoaderManager.java => InterceptorClassLoaderManager.java} (67%) diff --git a/agent/agent-controller/src/main/java/org/bithon/agent/controller/AgentControllerService.java b/agent/agent-controller/src/main/java/org/bithon/agent/controller/AgentControllerService.java index ef037bda26..5634897db2 100644 --- a/agent/agent-controller/src/main/java/org/bithon/agent/controller/AgentControllerService.java +++ b/agent/agent-controller/src/main/java/org/bithon/agent/controller/AgentControllerService.java @@ -24,7 +24,7 @@ import org.bithon.agent.controller.config.AgentSettingFetchTask; import org.bithon.agent.controller.config.ConfigurationCommandImpl; import org.bithon.agent.instrumentation.loader.AgentClassLoader; -import org.bithon.agent.instrumentation.loader.PluginClassLoaderManager; +import org.bithon.agent.instrumentation.loader.PluginClassLoader; import org.bithon.agent.starter.IAgentService; import org.bithon.component.commons.logging.ILogAdaptor; import org.bithon.component.commons.logging.LoggerFactory; @@ -73,7 +73,7 @@ public void start() throws Exception { attachCommand(controller, new InstrumentationCommand()); attachCommand(controller, new ConfigurationCommandImpl()); loadAgentCommands(controller, AgentClassLoader.getClassLoader()); - loadAgentCommands(controller, PluginClassLoaderManager.getDefaultLoader()); + loadAgentCommands(controller, PluginClassLoader.getClassLoader()); // diff --git a/agent/agent-instrumentation/src/main/java/org/bithon/agent/instrumentation/aop/interceptor/InterceptorSupplier.java b/agent/agent-instrumentation/src/main/java/org/bithon/agent/instrumentation/aop/interceptor/InterceptorSupplier.java index 385fcfc9dd..07d7d9f972 100644 --- a/agent/agent-instrumentation/src/main/java/org/bithon/agent/instrumentation/aop/interceptor/InterceptorSupplier.java +++ b/agent/agent-instrumentation/src/main/java/org/bithon/agent/instrumentation/aop/interceptor/InterceptorSupplier.java @@ -17,7 +17,7 @@ package org.bithon.agent.instrumentation.aop.interceptor; import org.bithon.agent.instrumentation.aop.interceptor.declaration.AbstractInterceptor; -import org.bithon.agent.instrumentation.loader.PluginClassLoaderManager; +import org.bithon.agent.instrumentation.loader.InterceptorClassLoaderManager; import org.bithon.agent.instrumentation.logging.LoggerFactory; import java.io.PrintWriter; @@ -85,7 +85,7 @@ public AbstractInterceptor get() { private AbstractInterceptor createInterceptor(String interceptorClassName, ClassLoader userClassLoader) { try { // Load class out of lock in case of deadlock - ClassLoader interceptorClassLoader = PluginClassLoaderManager.getClassLoader(userClassLoader); + ClassLoader interceptorClassLoader = InterceptorClassLoaderManager.getClassLoader(userClassLoader); Class interceptorClass = Class.forName(interceptorClassName, true, interceptorClassLoader); return (AbstractInterceptor) interceptorClass.getConstructor().newInstance(); diff --git a/agent/agent-instrumentation/src/main/java/org/bithon/agent/instrumentation/aop/interceptor/plugin/PluginResolver.java b/agent/agent-instrumentation/src/main/java/org/bithon/agent/instrumentation/aop/interceptor/plugin/PluginResolver.java index af4fd9cb5e..bb8e461800 100644 --- a/agent/agent-instrumentation/src/main/java/org/bithon/agent/instrumentation/aop/interceptor/plugin/PluginResolver.java +++ b/agent/agent-instrumentation/src/main/java/org/bithon/agent/instrumentation/aop/interceptor/plugin/PluginResolver.java @@ -22,7 +22,7 @@ import org.bithon.agent.instrumentation.aop.interceptor.descriptor.MethodPointCutDescriptor; import org.bithon.agent.instrumentation.expt.AgentException; import org.bithon.agent.instrumentation.loader.JarClassLoader; -import org.bithon.agent.instrumentation.loader.PluginClassLoaderManager; +import org.bithon.agent.instrumentation.loader.PluginClassLoader; import org.bithon.agent.instrumentation.logging.ILogger; import org.bithon.agent.instrumentation.logging.LoggerFactory; @@ -45,7 +45,7 @@ public abstract class PluginResolver { public PluginResolver() { // create plugin class loader first - PluginClassLoaderManager.createDefault(); + PluginClassLoader.createClassLoader(); } public Descriptors resolveInterceptors() { @@ -72,7 +72,7 @@ public Descriptors resolveInterceptors() { */ private void resolveInterceptorType(Collection descriptors) { LOG.info("Resolving interceptor type from all enabled plugins..."); - InterceptorTypeResolver resolver = new InterceptorTypeResolver(PluginClassLoaderManager.getDefaultLoader()); + InterceptorTypeResolver resolver = new InterceptorTypeResolver(PluginClassLoader.getClassLoader()); for (Descriptors.Descriptor descriptor : descriptors) { for (Descriptors.MethodPointCuts pointcut : descriptor.getMethodPointCuts()) { @@ -92,7 +92,7 @@ private void resolveInterceptorType(Collection descripto } private List loadPlugins() { - JarClassLoader pluginClassLoader = PluginClassLoaderManager.getDefaultLoader(); + JarClassLoader pluginClassLoader = PluginClassLoader.getClassLoader(); return pluginClassLoader.getJars() .stream() .flatMap(JarFile::stream) diff --git a/agent/agent-instrumentation/src/main/java/org/bithon/agent/instrumentation/loader/InterceptorClassLoader.java b/agent/agent-instrumentation/src/main/java/org/bithon/agent/instrumentation/loader/InterceptorClassLoader.java new file mode 100644 index 0000000000..71d56b0e64 --- /dev/null +++ b/agent/agent-instrumentation/src/main/java/org/bithon/agent/instrumentation/loader/InterceptorClassLoader.java @@ -0,0 +1,101 @@ +/* + * Copyright 2020 bithon.org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.bithon.agent.instrumentation.loader; + +import java.io.IOException; +import java.net.URL; +import java.util.Enumeration; +import java.util.Locale; + +/** + * @author frank.chen021@outlook.com + * @date 28/12/21 10:31 AM + */ +public class InterceptorClassLoader extends ClassLoader { + private final JarClassLoader pluginClassLoader; + + private final ClassLoader appClassLoader; + + public InterceptorClassLoader(JarClassLoader pluginClassLoader, ClassLoader appClassLoader) { + // NOTE: parent is assigned to parent class loader + // This is the key to implement agent lib isolation from app libs + super(null); + + this.pluginClassLoader = pluginClassLoader; + this.appClassLoader = appClassLoader; + } + + /** + * For classes under org.bithon.agent.plugin, we need to make sure the classes are loaded in this class loader, + * instead of the parent class loader. + *

+ * This makes sure that this class loader can find those classes referenced in the plugin. + * + */ + @Override + protected Class findClass(String name) throws ClassNotFoundException { + if (name.startsWith("org.bithon.agent.plugin.")) { + try { + byte[] classBytes = pluginClassLoader.getClassByteCode(name); + if (classBytes != null) { + // define the package object for customer-loaded classes, + // so that getPackage could work + int lastIndex = name.lastIndexOf("."); + if (lastIndex > 0) { + String pkg = name.substring(0, lastIndex); + if (getPackage(pkg) == null) { + definePackage(pkg, null, null, null, null, null, null, null); + } + } + return defineClass(name, classBytes, 0, classBytes.length); + } + } catch (IOException ignored) { + } + } + + // Find class in parent, they might be classes in the agent library + try { + return pluginClassLoader.loadClass(name); + } catch (ClassNotFoundException ignored) { + } + + // Find in application class loader if it's referenced by the class in the plugin + try { + return appClassLoader.loadClass(name); + } catch (ClassNotFoundException e) { + throw new ClassNotFoundException(String.format(Locale.ENGLISH, + "%s not found in parent [%s] and agent plugins.", + name, + appClassLoader.getClass().getName())); + } + } + + @Override + public URL getResource(String name) { + // delegate to parent to get resource + URL url = this.pluginClassLoader.getResource(name); + if (url != null) { + return url; + } + return appClassLoader.getResource(name); + } + + @Override + public Enumeration getResources(String name) throws IOException { + return appClassLoader.getResources(name); + } +} diff --git a/agent/agent-instrumentation/src/main/java/org/bithon/agent/instrumentation/loader/PluginClassLoaderManager.java b/agent/agent-instrumentation/src/main/java/org/bithon/agent/instrumentation/loader/InterceptorClassLoaderManager.java similarity index 67% rename from agent/agent-instrumentation/src/main/java/org/bithon/agent/instrumentation/loader/PluginClassLoaderManager.java rename to agent/agent-instrumentation/src/main/java/org/bithon/agent/instrumentation/loader/InterceptorClassLoaderManager.java index bb2876f0ee..8f45c23ca2 100644 --- a/agent/agent-instrumentation/src/main/java/org/bithon/agent/instrumentation/loader/PluginClassLoaderManager.java +++ b/agent/agent-instrumentation/src/main/java/org/bithon/agent/instrumentation/loader/InterceptorClassLoaderManager.java @@ -27,8 +27,7 @@ * @author frankchen * @date 2020-12-31 22:28:23 */ -public final class PluginClassLoaderManager { - private static JarClassLoader defaultLoader; +public final class InterceptorClassLoaderManager { private static final Map LOADER_MAPPING = new ConcurrentHashMap<>(); /** @@ -37,21 +36,9 @@ public final class PluginClassLoaderManager { */ public static ClassLoader getClassLoader(ClassLoader appClassLoader) { return appClassLoader == null - ? defaultLoader + ? PluginClassLoader.getClassLoader() : LOADER_MAPPING.computeIfAbsent(appClassLoader, - k -> new PluginClassLoader(defaultLoader, - appClassLoader)); - } - - public static JarClassLoader getDefaultLoader() { - return defaultLoader; - } - - public static synchronized void createDefault() { - if (defaultLoader == null) { - defaultLoader = new JarClassLoader("plugin", - AgentDirectory.getSubDirectory("plugins"), - AgentClassLoader.getClassLoader()); - } + k -> new InterceptorClassLoader(PluginClassLoader.getClassLoader(), + appClassLoader)); } } diff --git a/agent/agent-instrumentation/src/main/java/org/bithon/agent/instrumentation/loader/PluginClassLoader.java b/agent/agent-instrumentation/src/main/java/org/bithon/agent/instrumentation/loader/PluginClassLoader.java index 7113745b49..f41737c0ed 100644 --- a/agent/agent-instrumentation/src/main/java/org/bithon/agent/instrumentation/loader/PluginClassLoader.java +++ b/agent/agent-instrumentation/src/main/java/org/bithon/agent/instrumentation/loader/PluginClassLoader.java @@ -16,86 +16,24 @@ package org.bithon.agent.instrumentation.loader; -import java.io.IOException; -import java.net.URL; -import java.util.Enumeration; -import java.util.Locale; +import org.bithon.agent.instrumentation.utils.AgentDirectory; /** * @author frank.chen021@outlook.com - * @date 28/12/21 10:31 AM + * @date 2024/11/2 14:21 */ -public class PluginClassLoader extends ClassLoader { - private final JarClassLoader pluginClassLoader; +public class PluginClassLoader { + private static JarClassLoader instance; - private final ClassLoader appClassLoader; - - public PluginClassLoader(JarClassLoader pluginClassLoader, ClassLoader appClassLoader) { - // NOTE: parent is assigned to parent class loader - // This is the key to implement agent lib isolation from app libs - super(null); - - this.pluginClassLoader = pluginClassLoader; - this.appClassLoader = appClassLoader; + public static JarClassLoader getClassLoader() { + return instance; } - /** - * For classes under org.bithon.agent.plugin, we need to make sure the classes are loaded in this class loader, - * instead of the parent class loader. - *

- * This makes sure that this class loader can find those classes referenced in the plugin. - * - */ - @Override - protected Class findClass(String name) throws ClassNotFoundException { - if (name.startsWith("org.bithon.agent.plugin.")) { - try { - byte[] classBytes = pluginClassLoader.getClassByteCode(name); - if (classBytes != null) { - // define the package object for customer-loaded classes, - // so that getPackage could work - int lastIndex = name.lastIndexOf("."); - if (lastIndex > 0) { - String pkg = name.substring(0, lastIndex); - if (getPackage(pkg) == null) { - definePackage(pkg, null, null, null, null, null, null, null); - } - } - return defineClass(name, classBytes, 0, classBytes.length); - } - } catch (IOException ignored) { - } - } - - // Find class in parent, they might be classes in the agent library - try { - return pluginClassLoader.loadClass(name); - } catch (ClassNotFoundException ignored) { - } - - // Find in application class loader if it's referenced by the class in the plugin - try { - return appClassLoader.loadClass(name); - } catch (ClassNotFoundException e) { - throw new ClassNotFoundException(String.format(Locale.ENGLISH, - "%s not found in parent [%s] and agent plugins.", - name, - appClassLoader.getClass().getName())); + public static synchronized void createClassLoader() { + if (instance == null) { + instance = new JarClassLoader("plugin", + AgentDirectory.getSubDirectory("plugins"), + AgentClassLoader.getClassLoader()); } } - - @Override - public URL getResource(String name) { - // delegate to parent to get resource - URL url = this.pluginClassLoader.getResource(name); - if (url != null) { - return url; - } - return appClassLoader.getResource(name); - } - - @Override - public Enumeration getResources(String name) throws IOException { - return appClassLoader.getResources(name); - } } diff --git a/agent/agent-plugins/bithon-sdk/src/main/java/org/bithon/agent/plugin/bithon/sdk/interceptor/MetricRegistryFactory$Create.java b/agent/agent-plugins/bithon-sdk/src/main/java/org/bithon/agent/plugin/bithon/sdk/interceptor/MetricRegistryFactory$Create.java index 2cc0d41d07..f6dcb20801 100644 --- a/agent/agent-plugins/bithon-sdk/src/main/java/org/bithon/agent/plugin/bithon/sdk/interceptor/MetricRegistryFactory$Create.java +++ b/agent/agent-plugins/bithon-sdk/src/main/java/org/bithon/agent/plugin/bithon/sdk/interceptor/MetricRegistryFactory$Create.java @@ -17,7 +17,7 @@ package org.bithon.agent.plugin.bithon.sdk.interceptor; import org.bithon.agent.instrumentation.aop.interceptor.declaration.ReplaceInterceptor; -import org.bithon.agent.instrumentation.loader.PluginClassLoaderManager; +import org.bithon.agent.instrumentation.loader.PluginClassLoader; import org.bithon.agent.observability.dispatcher.IMessageConverter; import org.bithon.agent.observability.metric.collector.IMetricCollector2; import org.bithon.agent.observability.metric.collector.IMetricCollectorBase; @@ -67,7 +67,7 @@ public Object execute(Object[] args, Object returning) { MetricRegistryInvocationHandler proxyHandler = new MetricRegistryInvocationHandler(name, dimensionSpec, metricClass); - Object delegate = Proxy.newProxyInstance(PluginClassLoaderManager.getDefaultLoader(), + Object delegate = Proxy.newProxyInstance(PluginClassLoader.getClassLoader(), new Class[]{IMetricsRegistry.class, IMetricCollector2.class}, proxyHandler); From 0eab21936b2330dd7622bc90a54b804f75420df4 Mon Sep 17 00:00:00 2001 From: Frank Chen Date: Sat, 2 Nov 2024 15:25:24 +0800 Subject: [PATCH 2/4] define default interceptor loader --- .../loader/InterceptorClassLoader.java | 34 ++++++++++++------- .../loader/InterceptorClassLoaderManager.java | 11 +++--- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/agent/agent-instrumentation/src/main/java/org/bithon/agent/instrumentation/loader/InterceptorClassLoader.java b/agent/agent-instrumentation/src/main/java/org/bithon/agent/instrumentation/loader/InterceptorClassLoader.java index 71d56b0e64..3c906127e1 100644 --- a/agent/agent-instrumentation/src/main/java/org/bithon/agent/instrumentation/loader/InterceptorClassLoader.java +++ b/agent/agent-instrumentation/src/main/java/org/bithon/agent/instrumentation/loader/InterceptorClassLoader.java @@ -27,16 +27,19 @@ */ public class InterceptorClassLoader extends ClassLoader { private final JarClassLoader pluginClassLoader; + private final ClassLoader applicationClassLoader; - private final ClassLoader appClassLoader; + public InterceptorClassLoader(JarClassLoader pluginClassLoader) { + this(pluginClassLoader, null); + } - public InterceptorClassLoader(JarClassLoader pluginClassLoader, ClassLoader appClassLoader) { + public InterceptorClassLoader(JarClassLoader pluginClassLoader, ClassLoader applicationClassLoader) { // NOTE: parent is assigned to parent class loader // This is the key to implement agent lib isolation from app libs super(null); this.pluginClassLoader = pluginClassLoader; - this.appClassLoader = appClassLoader; + this.applicationClassLoader = applicationClassLoader; } /** @@ -44,7 +47,6 @@ public InterceptorClassLoader(JarClassLoader pluginClassLoader, ClassLoader appC * instead of the parent class loader. *

* This makes sure that this class loader can find those classes referenced in the plugin. - * */ @Override protected Class findClass(String name) throws ClassNotFoundException { @@ -74,14 +76,20 @@ protected Class findClass(String name) throws ClassNotFoundException { } // Find in application class loader if it's referenced by the class in the plugin - try { - return appClassLoader.loadClass(name); - } catch (ClassNotFoundException e) { - throw new ClassNotFoundException(String.format(Locale.ENGLISH, - "%s not found in parent [%s] and agent plugins.", - name, - appClassLoader.getClass().getName())); + if (applicationClassLoader != null) { + try { + return applicationClassLoader.loadClass(name); + } catch (ClassNotFoundException e) { + throw new ClassNotFoundException(String.format(Locale.ENGLISH, + "%s not found in parent [%s] and agent plugins.", + name, + applicationClassLoader.getClass().getName())); + } } + + throw new ClassNotFoundException(String.format(Locale.ENGLISH, + "%s not found in agent plugins.", + name)); } @Override @@ -91,11 +99,11 @@ public URL getResource(String name) { if (url != null) { return url; } - return appClassLoader.getResource(name); + return applicationClassLoader.getResource(name); } @Override public Enumeration getResources(String name) throws IOException { - return appClassLoader.getResources(name); + return applicationClassLoader.getResources(name); } } diff --git a/agent/agent-instrumentation/src/main/java/org/bithon/agent/instrumentation/loader/InterceptorClassLoaderManager.java b/agent/agent-instrumentation/src/main/java/org/bithon/agent/instrumentation/loader/InterceptorClassLoaderManager.java index 8f45c23ca2..b1d50be14e 100644 --- a/agent/agent-instrumentation/src/main/java/org/bithon/agent/instrumentation/loader/InterceptorClassLoaderManager.java +++ b/agent/agent-instrumentation/src/main/java/org/bithon/agent/instrumentation/loader/InterceptorClassLoaderManager.java @@ -16,8 +16,6 @@ package org.bithon.agent.instrumentation.loader; -import org.bithon.agent.instrumentation.utils.AgentDirectory; - import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -30,15 +28,16 @@ public final class InterceptorClassLoaderManager { private static final Map LOADER_MAPPING = new ConcurrentHashMap<>(); + private static final InterceptorClassLoader DEFAULT_LOADER = new InterceptorClassLoader(PluginClassLoader.getClassLoader()); /** * class loader for class which is being transformed. * it can be null if the class is loaded by bootstrap class loader */ public static ClassLoader getClassLoader(ClassLoader appClassLoader) { return appClassLoader == null - ? PluginClassLoader.getClassLoader() - : LOADER_MAPPING.computeIfAbsent(appClassLoader, - k -> new InterceptorClassLoader(PluginClassLoader.getClassLoader(), - appClassLoader)); + ? DEFAULT_LOADER + : LOADER_MAPPING.computeIfAbsent(appClassLoader, + k -> new InterceptorClassLoader(PluginClassLoader.getClassLoader(), + appClassLoader)); } } From b837b73e8f2b8654d8cee86ae1b78411559fe5c8 Mon Sep 17 00:00:00 2001 From: Frank Chen Date: Sat, 2 Nov 2024 15:26:12 +0800 Subject: [PATCH 3/4] Define metric registry of network per instance to fix #880 --- .../collector/MetricCollectorManager.java | 99 +++---------------- .../collector/MetricRegistryFactory.java | 7 ++ .../NetworkClient$CompleteResponses.java | 3 +- 3 files changed, 21 insertions(+), 88 deletions(-) diff --git a/agent/agent-observability/src/main/java/org/bithon/agent/observability/metric/collector/MetricCollectorManager.java b/agent/agent-observability/src/main/java/org/bithon/agent/observability/metric/collector/MetricCollectorManager.java index 26e005737a..50d025aa70 100644 --- a/agent/agent-observability/src/main/java/org/bithon/agent/observability/metric/collector/MetricCollectorManager.java +++ b/agent/agent-observability/src/main/java/org/bithon/agent/observability/metric/collector/MetricCollectorManager.java @@ -19,16 +19,11 @@ import org.bithon.agent.observability.dispatcher.Dispatcher; import org.bithon.agent.observability.dispatcher.Dispatchers; import org.bithon.agent.observability.dispatcher.IMessageConverter; -import org.bithon.agent.observability.metric.model.IMetricValueProvider; -import org.bithon.agent.observability.metric.model.schema.FieldSpec; -import org.bithon.agent.observability.metric.model.schema.Schema3; import org.bithon.component.commons.concurrency.NamedThreadFactory; import org.bithon.component.commons.logging.ILogAdaptor; import org.bithon.component.commons.logging.LoggerFactory; import org.bithon.component.commons.utils.CollectionUtils; -import java.lang.reflect.Field; -import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.concurrent.ConcurrentHashMap; @@ -37,11 +32,11 @@ import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Supplier; -import java.util.stream.Collectors; /** - * Metric Registry and Dispatcher(in some other system, it's called as reporter) + * Metric Registry and Dispatcher (in some other system, it's called as a reporter) * * @author frankchen */ @@ -52,7 +47,8 @@ public class MetricCollectorManager { private static final MetricCollectorManager INSTANCE = new MetricCollectorManager(); private final ConcurrentMap collectors; private final Dispatcher dispatcher; - ScheduledExecutorService scheduler; + private final ScheduledExecutorService scheduler; + private final AtomicInteger unnamedCollectorIndex = new AtomicInteger(0); static class ManagedMetricCollector { /** @@ -89,7 +85,7 @@ public boolean isEmpty() { this.lastCollectedAt = now; return this.delegation.isEmpty(); } else { - // wait for next round + // wait for the next round lastCollectedAt = System.currentTimeMillis(); return false; } @@ -119,16 +115,7 @@ public static MetricCollectorManager getInstance() { return INSTANCE; } - public boolean collectorExists(String name) { - for (String providerName : collectors.keySet()) { - if (providerName.contains(name)) { - return true; - } - } - return false; - } - - public synchronized T register(String collectorName, T collector) { + public T register(String collectorName, T collector) { if (collectors.containsKey(collectorName)) { throw new RuntimeException(String.format(Locale.ENGLISH, "Metrics Local Storage(%s) already registered!", collectorName)); } @@ -137,50 +124,13 @@ public synchronized T register(String collector return (T) collectors.computeIfAbsent(collectorName, key -> new ManagedMetricCollector(collector)).delegation; } - public synchronized IMetricCollector3 register(String collectorName, - Class measurementClazz, - IMetricCollector3 collector) { - if (collectors.containsKey(collectorName)) { - throw new RuntimeException(String.format(Locale.ENGLISH, "Metrics Local Storage(%s) already registered!", collectorName)); - } - - List fieldSpecs = new ArrayList<>(); - for (Field field : measurementClazz.getDeclaredFields()) { - //noinspection rawtypes - Class fieldClass = field.getType(); - if (IMetricValueProvider.class.isAssignableFrom(fieldClass)) { - // TODO: change type to Sum/Max/Min/Last/Gauge/Histogram - fieldSpecs.add(FieldSpec.of(fieldClass.getName(), FieldSpec.TYPE_LONG)); - } else { - fieldSpecs.add(FieldSpec.of(fieldClass.getName(), FieldSpec.TYPE_STRING)); - } - } - Schema3 schema = new Schema3(collectorName, fieldSpecs); - - //noinspection unchecked - return (IMetricCollector3) collectors.computeIfAbsent(collectorName, key -> new ManagedMetricCollector(collector) { - @Override - public Object collect(IMessageConverter messageConverter) { - List measurementList = collector.collect(interval, lastCollectedAt); - if (CollectionUtils.isEmpty(measurementList)) { - return null; - } - - List values = measurementList.stream().map((measurement) -> { - Field[] fields = measurementClazz.getDeclaredFields(); - Object[] arr = new Object[fields.length]; - int i = 0; - for (Field field : fields) { - try { - arr[i++] = field.get(measurement); - } catch (IllegalAccessException ignored) { - } - } - return arr; - }).collect(Collectors.toList()); - return messageConverter.from(schema, values, lastCollectedAt, interval); - } - }).delegation; + /** + * Register a unnamed collector + */ + public synchronized T register(T collector) { + collectors.put(collector.getClass().getSimpleName() + "-" + unnamedCollectorIndex.getAndIncrement(), + new ManagedMetricCollector(collector)); + return collector; } @SuppressWarnings("unchecked") @@ -206,29 +156,6 @@ public T getOrRegister(String collectorName, Su } } - @SuppressWarnings("unchecked") - public T getOrRegister(String collectorName, Class collectorClass) { - ManagedMetricCollector managedCollector = collectors.get(collectorName); - if (managedCollector != null) { - return (T) managedCollector.delegation; - } - synchronized (this) { - try { - managedCollector = collectors.get(collectorName); - // double check - if (managedCollector != null) { - return (T) managedCollector.delegation; - } - - managedCollector = new ManagedMetricCollector(collectorClass.getConstructor().newInstance()); - collectors.put(collectorName, managedCollector); - return (T) managedCollector.delegation; - } catch (Exception e) { - throw new RuntimeException("Can't create or register metric provider " + collectorName, e); - } - } - } - public void unregister(String name) { collectors.remove(name); } diff --git a/agent/agent-observability/src/main/java/org/bithon/agent/observability/metric/collector/MetricRegistryFactory.java b/agent/agent-observability/src/main/java/org/bithon/agent/observability/metric/collector/MetricRegistryFactory.java index 4f40a56c1c..9efe4d56aa 100644 --- a/agent/agent-observability/src/main/java/org/bithon/agent/observability/metric/collector/MetricRegistryFactory.java +++ b/agent/agent-observability/src/main/java/org/bithon/agent/observability/metric/collector/MetricRegistryFactory.java @@ -51,4 +51,11 @@ public static > R getOrCreateR //noinspection unchecked return (R) collector.registry; } + + public static > R register(Supplier supplier) { + MetricRegistry.Collector collector = MetricCollectorManager.getInstance() + .register(new MetricRegistry.Collector(supplier.get())); + //noinspection unchecked + return (R) collector.registry; + } } diff --git a/agent/agent-plugins/apache-kafka/src/main/java/org/bithon/agent/plugin/apache/kafka/network/interceptor/NetworkClient$CompleteResponses.java b/agent/agent-plugins/apache-kafka/src/main/java/org/bithon/agent/plugin/apache/kafka/network/interceptor/NetworkClient$CompleteResponses.java index 1e7f3c702a..734b7f2aad 100644 --- a/agent/agent-plugins/apache-kafka/src/main/java/org/bithon/agent/plugin/apache/kafka/network/interceptor/NetworkClient$CompleteResponses.java +++ b/agent/agent-plugins/apache-kafka/src/main/java/org/bithon/agent/plugin/apache/kafka/network/interceptor/NetworkClient$CompleteResponses.java @@ -41,8 +41,7 @@ public class NetworkClient$CompleteResponses extends AfterInterceptor { private Field authenticationExceptionField; public NetworkClient$CompleteResponses() { - metricRegistry = MetricRegistryFactory.getOrCreateRegistry("kafka-network", - NetworkMetricRegistry::new); + metricRegistry = MetricRegistryFactory.register(NetworkMetricRegistry::new); try { authenticationExceptionField = ReflectionUtils.getField(ClientResponse.class, "authenticationException"); From e3351f4aa00e654d01887bf8e2a1c38d65376ed4 Mon Sep 17 00:00:00 2001 From: Frank Chen Date: Sat, 2 Nov 2024 15:26:47 +0800 Subject: [PATCH 4/4] Fix style --- .../instrumentation/loader/InterceptorClassLoaderManager.java | 1 + 1 file changed, 1 insertion(+) diff --git a/agent/agent-instrumentation/src/main/java/org/bithon/agent/instrumentation/loader/InterceptorClassLoaderManager.java b/agent/agent-instrumentation/src/main/java/org/bithon/agent/instrumentation/loader/InterceptorClassLoaderManager.java index b1d50be14e..05c265ac0e 100644 --- a/agent/agent-instrumentation/src/main/java/org/bithon/agent/instrumentation/loader/InterceptorClassLoaderManager.java +++ b/agent/agent-instrumentation/src/main/java/org/bithon/agent/instrumentation/loader/InterceptorClassLoaderManager.java @@ -29,6 +29,7 @@ public final class InterceptorClassLoaderManager { private static final Map LOADER_MAPPING = new ConcurrentHashMap<>(); private static final InterceptorClassLoader DEFAULT_LOADER = new InterceptorClassLoader(PluginClassLoader.getClassLoader()); + /** * class loader for class which is being transformed. * it can be null if the class is loaded by bootstrap class loader