diff --git a/CHANGES.md b/CHANGES.md index e3b12390..97e1c6e4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -7,6 +7,7 @@ Apollo Java 2.4.0 ------------------ * [Fix the Cannot enhance @Configuration bean definition issue](https://github.com/apolloconfig/apollo-java/pull/82) * [Feature openapi query namespace support not fill item](https://github.com/apolloconfig/apollo-java/pull/83) +* [Add more observability in apollo config client](https://github.com/apolloconfig/apollo-java/pull/74) ------------------ All issues and pull requests are [here](https://github.com/apolloconfig/apollo-java/milestone/4?closed=1) diff --git a/apollo-client/pom.xml b/apollo-client/pom.xml index 7a8e436a..f643256a 100644 --- a/apollo-client/pom.xml +++ b/apollo-client/pom.xml @@ -97,6 +97,17 @@ mockserver-netty test + + com.github.noconnor + junitperf + test + + + ch.qos.logback + logback-classic + + + diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/ConfigService.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/ConfigService.java index 184c5ee3..02ccdc36 100644 --- a/apollo-client/src/main/java/com/ctrip/framework/apollo/ConfigService.java +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/ConfigService.java @@ -20,6 +20,8 @@ import com.ctrip.framework.apollo.core.ConfigConsts; import com.ctrip.framework.apollo.core.enums.ConfigFileFormat; import com.ctrip.framework.apollo.internals.ConfigManager; +import com.ctrip.framework.apollo.internals.ConfigMonitorInitializer; +import com.ctrip.framework.apollo.monitor.api.ConfigMonitor; import com.ctrip.framework.apollo.spi.ConfigFactory; import com.ctrip.framework.apollo.spi.ConfigRegistry; @@ -30,19 +32,31 @@ */ public class ConfigService { private static final ConfigService s_instance = new ConfigService(); - + private volatile ConfigMonitor m_configMonitor; private volatile ConfigManager m_configManager; private volatile ConfigRegistry m_configRegistry; - + + private ConfigMonitor getMonitor() { + getManager(); + if (m_configMonitor == null) { + synchronized (this) { + if (m_configMonitor == null) { + m_configMonitor = ApolloInjector.getInstance(ConfigMonitor.class); + } + } + } + return m_configMonitor; + } + private ConfigManager getManager() { if (m_configManager == null) { synchronized (this) { if (m_configManager == null) { m_configManager = ApolloInjector.getInstance(ConfigManager.class); + ConfigMonitorInitializer.initialize(); } } } - return m_configManager; } @@ -81,6 +95,10 @@ public static ConfigFile getConfigFile(String namespace, ConfigFileFormat config return s_instance.getManager().getConfigFile(namespace, configFileFormat); } + public static ConfigMonitor getConfigMonitor(){ + return s_instance.getMonitor(); + } + static void setConfig(Config config) { setConfig(ConfigConsts.NAMESPACE_APPLICATION, config); } diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/AbstractConfig.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/AbstractConfig.java index 7ce41dca..22ba6cde 100644 --- a/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/AbstractConfig.java +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/AbstractConfig.java @@ -53,7 +53,7 @@ public abstract class AbstractConfig implements Config { private static final Logger logger = LoggerFactory.getLogger(AbstractConfig.class); - private static final ExecutorService m_executorService; + protected static final ExecutorService m_executorService; private final List m_listeners = Lists.newCopyOnWriteArrayList(); private final Map> m_interestedKeys = Maps.newConcurrentMap(); diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/AbstractConfigFile.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/AbstractConfigFile.java index 3a1c0df0..5ef1d37f 100644 --- a/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/AbstractConfigFile.java +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/AbstractConfigFile.java @@ -16,6 +16,8 @@ */ package com.ctrip.framework.apollo.internals; + +import static com.ctrip.framework.apollo.monitor.internal.ApolloClientMonitorConstant.*; import com.ctrip.framework.apollo.build.ApolloInjector; import com.ctrip.framework.apollo.core.utils.DeferredLoggerFactory; import com.ctrip.framework.apollo.enums.ConfigSourceType; @@ -43,7 +45,7 @@ */ public abstract class AbstractConfigFile implements ConfigFile, RepositoryChangeListener { private static final Logger logger = DeferredLoggerFactory.getLogger(AbstractConfigFile.class); - private static ExecutorService m_executorService; + protected static ExecutorService m_executorService; protected final ConfigRepository m_configRepository; protected final String m_namespace; protected final AtomicReference m_configProperties; @@ -112,7 +114,7 @@ public synchronized void onRepositoryChange(String namespace, Properties newProp this.fireConfigChange(new ConfigFileChangeEvent(m_namespace, oldValue, newValue, changeType)); - Tracer.logEvent("Apollo.Client.ConfigChanges", m_namespace); + Tracer.logEvent(APOLLO_CLIENT_CONFIGCHANGES, m_namespace); } @Override diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/AbstractConfigRepository.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/AbstractConfigRepository.java index b4505297..6b00c4c0 100644 --- a/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/AbstractConfigRepository.java +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/AbstractConfigRepository.java @@ -16,6 +16,7 @@ */ package com.ctrip.framework.apollo.internals; +import static com.ctrip.framework.apollo.monitor.internal.ApolloClientMonitorConstant.*; import com.ctrip.framework.apollo.build.ApolloInjector; import com.ctrip.framework.apollo.util.factory.PropertiesFactory; import java.util.List; @@ -41,7 +42,7 @@ protected boolean trySync() { sync(); return true; } catch (Throwable ex) { - Tracer.logEvent("ApolloConfigException", ExceptionUtil.getDetailMessage(ex)); + Tracer.logEvent(APOLLO_CONFIG_EXCEPTION, ExceptionUtil.getDetailMessage(ex)); logger .warn("Sync config failed, will retry. Repository {}, reason: {}", this.getClass(), ExceptionUtil .getDetailMessage(ex)); diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/ConfigMonitorInitializer.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/ConfigMonitorInitializer.java new file mode 100644 index 00000000..a6c0f421 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/ConfigMonitorInitializer.java @@ -0,0 +1,138 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.internals; + +import static com.ctrip.framework.apollo.monitor.internal.ApolloClientMonitorConstant.MBEAN_NAME; + +import com.ctrip.framework.apollo.build.ApolloInjector; +import com.ctrip.framework.apollo.core.utils.ClassLoaderUtil; +import com.ctrip.framework.apollo.monitor.internal.exporter.AbstractApolloClientMetricsExporter; +import com.ctrip.framework.apollo.monitor.internal.exporter.ApolloClientMetricsExporter; +import com.ctrip.framework.apollo.monitor.internal.jmx.ApolloClientJmxMBeanRegister; +import com.ctrip.framework.apollo.monitor.internal.ApolloClientMonitorContext; +import com.ctrip.framework.apollo.monitor.internal.listener.impl.DefaultApolloClientBootstrapArgsApi; +import com.ctrip.framework.apollo.monitor.internal.listener.impl.DefaultApolloClientExceptionApi; +import com.ctrip.framework.apollo.monitor.internal.listener.impl.DefaultApolloClientNamespaceApi; +import com.ctrip.framework.apollo.monitor.internal.listener.impl.DefaultApolloClientThreadPoolApi; +import com.ctrip.framework.apollo.monitor.internal.exporter.ApolloClientMetricsExporterFactory; +import com.ctrip.framework.apollo.monitor.internal.tracer.ApolloClientMonitorMessageProducer; +import com.ctrip.framework.apollo.monitor.internal.tracer.ApolloClientMessageProducerComposite; +import com.ctrip.framework.apollo.tracer.internals.NullMessageProducer; +import com.ctrip.framework.apollo.tracer.internals.cat.CatMessageProducer; +import com.ctrip.framework.apollo.tracer.internals.cat.CatNames; +import com.ctrip.framework.apollo.tracer.spi.MessageProducer; +import com.ctrip.framework.apollo.util.ConfigUtil; +import com.ctrip.framework.foundation.internals.ServiceBootstrap; +import com.google.common.collect.Lists; +import java.util.List; + +/** + * ConfigMonitorInitializer initializes the Apollo Config Monitor. + */ +public class ConfigMonitorInitializer { + + private static final ApolloClientMonitorContext MONITOR_CONTEXT = ApolloInjector.getInstance( + ApolloClientMonitorContext.class); + protected static volatile boolean hasInitialized = false; + private static ConfigUtil m_configUtil = ApolloInjector.getInstance(ConfigUtil.class); + + public static void initialize() { + if (m_configUtil.isClientMonitorEnabled() && !hasInitialized) { + synchronized (ConfigMonitorInitializer.class) { + if (!hasInitialized) { + doInit(); + hasInitialized = true; + } + } + } + } + + private static void doInit() { + initializeMetricsEventListener(); + initializeMetricsExporter(); + initializeJmxMonitoring(); + } + + + private static void initializeJmxMonitoring() { + if (m_configUtil.isClientMonitorJmxEnabled()) { + MONITOR_CONTEXT.getApolloClientMonitorEventListeners().forEach(metricsListener -> + ApolloClientJmxMBeanRegister.register( + MBEAN_NAME + metricsListener.getName(), metricsListener) + ); + } + } + + private static void initializeMetricsEventListener() { + ConfigManager configManager = ApolloInjector.getInstance( + ConfigManager.class); + DefaultApolloClientBootstrapArgsApi defaultApolloClientBootstrapArgsApi = new DefaultApolloClientBootstrapArgsApi( + m_configUtil); + DefaultApolloClientExceptionApi defaultApolloClientExceptionApi = new DefaultApolloClientExceptionApi(m_configUtil); + DefaultApolloClientNamespaceApi defaultApolloClientNamespaceApi = new DefaultApolloClientNamespaceApi( + configManager); + DefaultApolloClientThreadPoolApi defaultApolloClientThreadPoolApi = new DefaultApolloClientThreadPoolApi( + RemoteConfigRepository.m_executorService, + AbstractConfig.m_executorService, AbstractConfigFile.m_executorService, + AbstractApolloClientMetricsExporter.m_executorService); + + MONITOR_CONTEXT.setApolloClientBootstrapArgsMonitorApi(defaultApolloClientBootstrapArgsApi); + MONITOR_CONTEXT.setApolloClientExceptionMonitorApi(defaultApolloClientExceptionApi); + MONITOR_CONTEXT.setApolloClientNamespaceMonitorApi(defaultApolloClientNamespaceApi); + MONITOR_CONTEXT.setApolloClientThreadPoolMonitorApi(defaultApolloClientThreadPoolApi); + MONITOR_CONTEXT.setApolloClientMonitorEventListeners( + Lists.newArrayList(defaultApolloClientBootstrapArgsApi, + defaultApolloClientNamespaceApi, defaultApolloClientThreadPoolApi, + defaultApolloClientExceptionApi)); + } + + private static void initializeMetricsExporter( + ) { + ApolloClientMetricsExporterFactory exporterFactory = ApolloInjector.getInstance( + ApolloClientMetricsExporterFactory.class); + ApolloClientMetricsExporter metricsReporter = exporterFactory.getMetricsReporter( + MONITOR_CONTEXT.getApolloClientMonitorEventListeners()); + if (metricsReporter != null) { + MONITOR_CONTEXT.setApolloClientMetricsExporter(metricsReporter); + } + } + + public static ApolloClientMessageProducerComposite initializeMessageProducerComposite() { + List producers = ServiceBootstrap.loadAllOrdered(MessageProducer.class); + + if (m_configUtil.isClientMonitorEnabled()) { + producers.add(new ApolloClientMonitorMessageProducer()); + } + + if (ClassLoaderUtil.isClassPresent(CatNames.CAT_CLASS)) { + producers.add(new CatMessageProducer()); + } + + if (producers.isEmpty()) { + producers.add(new NullMessageProducer()); + } + + return new ApolloClientMessageProducerComposite(producers); + } + + // for test only + protected static void reset() { + hasInitialized = false; + m_configUtil = ApolloInjector.getInstance(ConfigUtil.class); + + } +} \ No newline at end of file diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/ConfigServiceLocator.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/ConfigServiceLocator.java index ce9b097c..0ea8e07c 100644 --- a/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/ConfigServiceLocator.java +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/ConfigServiceLocator.java @@ -16,6 +16,8 @@ */ package com.ctrip.framework.apollo.internals; +import static com.ctrip.framework.apollo.monitor.internal.ApolloClientMonitorConstant.*; + import com.ctrip.framework.apollo.core.ApolloClientSystemConsts; import com.ctrip.framework.apollo.core.ServiceNameConsts; import com.ctrip.framework.apollo.core.utils.DeferredLoggerFactory; @@ -218,7 +220,7 @@ private void schedulePeriodicRefresh() { @Override public void run() { logger.debug("refresh config services"); - Tracer.logEvent("Apollo.MetaService", "periodicRefresh"); + Tracer.logEvent(APOLLO_META_SERVICE, "periodicRefresh"); tryUpdateConfigServices(); } }, m_configUtil.getRefreshInterval(), m_configUtil.getRefreshInterval(), @@ -258,7 +260,7 @@ private synchronized void updateConfigServices() { setConfigServices(services); return; } catch (Throwable ex) { - Tracer.logEvent("ApolloConfigException", ExceptionUtil.getDetailMessage(ex)); + Tracer.logEvent(APOLLO_CONFIG_EXCEPTION, ExceptionUtil.getDetailMessage(ex)); transaction.setStatus(ex); exception = ex; } finally { @@ -302,6 +304,6 @@ private void logConfigServices(List serviceDtos) { } private void logConfigService(String serviceUrl) { - Tracer.logEvent("Apollo.Config.Services", serviceUrl); + Tracer.logEvent(APOLLO_CONFIG_SERVICES, serviceUrl); } } diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/DefaultConfig.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/DefaultConfig.java index 750abd0e..586391f0 100644 --- a/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/DefaultConfig.java +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/DefaultConfig.java @@ -16,6 +16,7 @@ */ package com.ctrip.framework.apollo.internals; +import static com.ctrip.framework.apollo.monitor.internal.ApolloClientMonitorConstant.*; import com.ctrip.framework.apollo.core.utils.DeferredLoggerFactory; import com.ctrip.framework.apollo.enums.ConfigSourceType; import com.google.common.collect.Maps; @@ -236,7 +237,7 @@ public synchronized void onRepositoryChange(String namespace, Properties newProp this.fireConfigChange(m_namespace, actualChanges); - Tracer.logEvent("Apollo.Client.ConfigChanges", m_namespace); + Tracer.logEvent(APOLLO_CLIENT_CONFIGCHANGES, m_namespace); } private void updateConfig(Properties newConfigProperties, ConfigSourceType sourceType) { diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/DefaultConfigManager.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/DefaultConfigManager.java index e897b6f7..81c4081c 100644 --- a/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/DefaultConfigManager.java +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/DefaultConfigManager.java @@ -16,15 +16,18 @@ */ package com.ctrip.framework.apollo.internals; -import java.util.Map; +import static com.ctrip.framework.apollo.monitor.internal.ApolloClientMonitorConstant.APOLLO_CLIENT_NAMESPACE_USAGE; import com.ctrip.framework.apollo.Config; import com.ctrip.framework.apollo.ConfigFile; import com.ctrip.framework.apollo.build.ApolloInjector; import com.ctrip.framework.apollo.core.enums.ConfigFileFormat; +import com.ctrip.framework.apollo.enums.ConfigSourceType; import com.ctrip.framework.apollo.spi.ConfigFactory; import com.ctrip.framework.apollo.spi.ConfigFactoryManager; +import com.ctrip.framework.apollo.tracer.Tracer; import com.google.common.collect.Maps; +import java.util.Map; /** * @author Jason Song(song_s@ctrip.com) @@ -44,7 +47,7 @@ public DefaultConfigManager() { @Override public Config getConfig(String namespace) { Config config = m_configs.get(namespace); - + if (config == null) { Object lock = m_configLocks.computeIfAbsent(namespace, key -> new Object()); synchronized (lock) { @@ -58,6 +61,9 @@ public Config getConfig(String namespace) { } } } + if (!ConfigSourceType.NONE.equals(config.getSourceType())) { + Tracer.logMetricsForCount(APOLLO_CLIENT_NAMESPACE_USAGE + ":" + namespace); + } return config; } diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/DefaultInjector.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/DefaultInjector.java index 707ad6c5..5d414070 100644 --- a/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/DefaultInjector.java +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/DefaultInjector.java @@ -17,6 +17,11 @@ package com.ctrip.framework.apollo.internals; import com.ctrip.framework.apollo.exceptions.ApolloConfigException; +import com.ctrip.framework.apollo.monitor.api.ConfigMonitor; +import com.ctrip.framework.apollo.monitor.internal.DefaultConfigMonitor; +import com.ctrip.framework.apollo.monitor.internal.exporter.impl.DefaultApolloClientMetricsExporterFactory; +import com.ctrip.framework.apollo.monitor.internal.ApolloClientMonitorContext; +import com.ctrip.framework.apollo.monitor.internal.exporter.ApolloClientMetricsExporterFactory; import com.ctrip.framework.apollo.spi.ApolloInjectorCustomizer; import com.ctrip.framework.apollo.spi.ConfigFactory; import com.ctrip.framework.apollo.spi.ConfigFactoryManager; @@ -30,7 +35,6 @@ import com.ctrip.framework.apollo.util.factory.PropertiesFactory; import com.ctrip.framework.apollo.util.http.DefaultHttpClient; import com.ctrip.framework.apollo.util.http.HttpClient; - import com.ctrip.framework.apollo.util.yaml.YamlParser; import com.ctrip.framework.foundation.internals.ServiceBootstrap; import com.google.inject.AbstractModule; @@ -105,6 +109,9 @@ protected void configure() { bind(RemoteConfigLongPollService.class).in(Singleton.class); bind(YamlParser.class).in(Singleton.class); bind(PropertiesFactory.class).to(DefaultPropertiesFactory.class).in(Singleton.class); + bind(ConfigMonitor.class).to(DefaultConfigMonitor.class).in(Singleton.class); + bind(ApolloClientMonitorContext.class).in(Singleton.class); + bind(ApolloClientMetricsExporterFactory.class).to(DefaultApolloClientMetricsExporterFactory.class).in(Singleton.class); } } } diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/LocalFileConfigRepository.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/LocalFileConfigRepository.java index 1820fd1a..52786384 100644 --- a/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/LocalFileConfigRepository.java +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/LocalFileConfigRepository.java @@ -16,6 +16,7 @@ */ package com.ctrip.framework.apollo.internals; +import static com.ctrip.framework.apollo.monitor.internal.ApolloClientMonitorConstant.*; import com.ctrip.framework.apollo.core.utils.DeferredLoggerFactory; import com.ctrip.framework.apollo.enums.ConfigSourceType; import java.io.File; @@ -154,7 +155,7 @@ protected void sync() { m_sourceType = ConfigSourceType.LOCAL; transaction.setStatus(Transaction.SUCCESS); } catch (Throwable ex) { - Tracer.logEvent("ApolloConfigException", ExceptionUtil.getDetailMessage(ex)); + Tracer.logEvent(APOLLO_CONFIG_EXCEPTION, ExceptionUtil.getDetailMessage(ex)); transaction.setStatus(ex); exception = ex; //ignore diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/RemoteConfigLongPollService.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/RemoteConfigLongPollService.java index 59806b2a..ccc75576 100644 --- a/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/RemoteConfigLongPollService.java +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/RemoteConfigLongPollService.java @@ -16,6 +16,7 @@ */ package com.ctrip.framework.apollo.internals; +import static com.ctrip.framework.apollo.monitor.internal.ApolloClientMonitorConstant.*; import com.ctrip.framework.apollo.build.ApolloInjector; import com.ctrip.framework.apollo.core.ConfigConsts; import com.ctrip.framework.apollo.core.dto.ApolloConfigNotification; @@ -33,9 +34,9 @@ import com.ctrip.framework.apollo.tracer.spi.Transaction; import com.ctrip.framework.apollo.util.ConfigUtil; import com.ctrip.framework.apollo.util.ExceptionUtil; +import com.ctrip.framework.apollo.util.http.HttpClient; import com.ctrip.framework.apollo.util.http.HttpRequest; import com.ctrip.framework.apollo.util.http.HttpResponse; -import com.ctrip.framework.apollo.util.http.HttpClient; import com.ctrip.framework.foundation.internals.ServiceBootstrap; import com.google.common.base.Joiner; import com.google.common.base.Strings; @@ -50,6 +51,7 @@ import com.google.common.util.concurrent.RateLimiter; import com.google.gson.Gson; import java.lang.reflect.Type; +import java.net.SocketTimeoutException; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentMap; @@ -209,9 +211,12 @@ private void doLongPollingRefresh(String appId, String cluster, String dataCente transaction.setStatus(Transaction.SUCCESS); } catch (Throwable ex) { lastServiceDto = null; - Tracer.logEvent("ApolloConfigException", ExceptionUtil.getDetailMessage(ex)); + Tracer.logEvent(APOLLO_CONFIG_EXCEPTION, ExceptionUtil.getDetailMessage(ex)); transaction.setStatus(ex); long sleepTimeInSecond = m_longPollFailSchedulePolicyInSecond.fail(); + if (ex.getCause() instanceof SocketTimeoutException) { + Tracer.logEvent(APOLLO_CLIENT_NAMESPACE_TIMEOUT, assembleNamespaces()); + } logger.warn( "Long polling failed, will retry in {} seconds. appId: {}, cluster: {}, namespaces: {}, long polling url: {}, reason: {}", sleepTimeInSecond, appId, cluster, assembleNamespaces(), url, ExceptionUtil.getDetailMessage(ex)); diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/RemoteConfigRepository.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/RemoteConfigRepository.java index c3aab684..879f243c 100644 --- a/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/RemoteConfigRepository.java +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/RemoteConfigRepository.java @@ -16,6 +16,8 @@ */ package com.ctrip.framework.apollo.internals; +import static com.ctrip.framework.apollo.monitor.internal.ApolloClientMonitorConstant.*; + import com.ctrip.framework.apollo.Apollo; import com.ctrip.framework.apollo.build.ApolloInjector; import com.ctrip.framework.apollo.core.ConfigConsts; @@ -35,9 +37,9 @@ import com.ctrip.framework.apollo.tracer.spi.Transaction; import com.ctrip.framework.apollo.util.ConfigUtil; import com.ctrip.framework.apollo.util.ExceptionUtil; +import com.ctrip.framework.apollo.util.http.HttpClient; import com.ctrip.framework.apollo.util.http.HttpRequest; import com.ctrip.framework.apollo.util.http.HttpResponse; -import com.ctrip.framework.apollo.util.http.HttpClient; import com.google.common.base.Joiner; import com.google.common.base.Strings; import com.google.common.collect.Lists; @@ -73,7 +75,7 @@ public class RemoteConfigRepository extends AbstractConfigRepository { private final RemoteConfigLongPollService remoteConfigLongPollService; private volatile AtomicReference m_configCache; private final String m_namespace; - private final static ScheduledExecutorService m_executorService; + protected final static ScheduledExecutorService m_executorService; private final AtomicReference m_longPollServiceDto; private final AtomicReference m_remoteMessages; private final RateLimiter m_loadConfigRateLimiter; @@ -111,7 +113,10 @@ public RemoteConfigRepository(String namespace) { @Override public Properties getConfig() { if (m_configCache.get() == null) { + long start = System.currentTimeMillis(); this.sync(); + Tracer.logEvent(APOLLO_CLIENT_NAMESPACE_FIRST_LOAD_SPEND+":"+m_namespace, + String.valueOf(System.currentTimeMillis() - start)); } return transformApolloConfigToProperties(m_configCache.get()); } @@ -133,10 +138,10 @@ private void schedulePeriodicRefresh() { new Runnable() { @Override public void run() { - Tracer.logEvent("Apollo.ConfigService", String.format("periodicRefresh: %s", m_namespace)); + Tracer.logEvent(APOLLO_CONFIGSERVICE, String.format("periodicRefresh: %s", m_namespace)); logger.debug("refresh config for namespace: {}", m_namespace); trySync(); - Tracer.logEvent("Apollo.Client.Version", Apollo.VERSION); + Tracer.logEvent(APOLLO_CLIENT_VERSION, Apollo.VERSION); } }, m_configUtil.getRefreshInterval(), m_configUtil.getRefreshInterval(), m_configUtil.getRefreshIntervalTimeUnit()); @@ -158,7 +163,7 @@ protected synchronized void sync() { } if (current != null) { - Tracer.logEvent(String.format("Apollo.Client.Configs.%s", current.getNamespaceName()), + Tracer.logEvent(String.format(APOLLO_CLIENT_CONFIGS+"%s", current.getNamespaceName()), current.getReleaseKey()); } @@ -189,7 +194,7 @@ private ApolloConfig loadApolloConfig() { String cluster = m_configUtil.getCluster(); String dataCenter = m_configUtil.getDataCenter(); String secret = m_configUtil.getAccessKeySecret(); - Tracer.logEvent("Apollo.Client.ConfigMeta", STRING_JOINER.join(appId, cluster, m_namespace)); + Tracer.logEvent(APOLLO_CLIENT_CONFIGMETA, STRING_JOINER.join(appId, cluster, m_namespace)); int maxRetries = m_configNeedForceRefresh.get() ? 2 : 1; long onErrorSleepTime = 0; // 0 means no sleep Throwable exception = null; @@ -260,15 +265,17 @@ private ApolloConfig loadApolloConfig() { appId, cluster, m_namespace); statusCodeException = new ApolloConfigStatusCodeException(ex.getStatusCode(), message); + Tracer.logEvent(APOLLO_CLIENT_NAMESPACE_NOT_FOUND,m_namespace); + } - Tracer.logEvent("ApolloConfigException", ExceptionUtil.getDetailMessage(statusCodeException)); + Tracer.logEvent(APOLLO_CONFIG_EXCEPTION, ExceptionUtil.getDetailMessage(statusCodeException)); transaction.setStatus(statusCodeException); exception = statusCodeException; if(ex.getStatusCode() == 404) { break retryLoopLabel; } } catch (Throwable ex) { - Tracer.logEvent("ApolloConfigException", ExceptionUtil.getDetailMessage(ex)); + Tracer.logEvent(APOLLO_CONFIG_EXCEPTION, ExceptionUtil.getDetailMessage(ex)); transaction.setStatus(ex); exception = ex; } finally { diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/SimpleConfig.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/SimpleConfig.java index c8897bbd..2d333988 100644 --- a/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/SimpleConfig.java +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/SimpleConfig.java @@ -16,6 +16,7 @@ */ package com.ctrip.framework.apollo.internals; +import static com.ctrip.framework.apollo.monitor.internal.ApolloClientMonitorConstant.*; import com.ctrip.framework.apollo.enums.ConfigSourceType; import java.util.Collections; import java.util.List; @@ -113,7 +114,7 @@ public String apply(ConfigChange input) { this.fireConfigChange(m_namespace, changeMap); - Tracer.logEvent("Apollo.Client.ConfigChanges", m_namespace); + Tracer.logEvent(APOLLO_CLIENT_CONFIGCHANGES, m_namespace); } private void updateConfig(Properties newConfigProperties, ConfigSourceType sourceType) { diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/YamlConfigFile.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/YamlConfigFile.java index 3443d582..05f87569 100644 --- a/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/YamlConfigFile.java +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/YamlConfigFile.java @@ -16,6 +16,7 @@ */ package com.ctrip.framework.apollo.internals; +import static com.ctrip.framework.apollo.monitor.internal.ApolloClientMonitorConstant.*; import com.ctrip.framework.apollo.util.ExceptionUtil; import java.util.Properties; @@ -65,7 +66,7 @@ private boolean tryTransformToProperties() { transformToProperties(); return true; } catch (Throwable ex) { - Tracer.logEvent("ApolloConfigException", ExceptionUtil.getDetailMessage(ex)); + Tracer.logEvent(APOLLO_CONFIG_EXCEPTION, ExceptionUtil.getDetailMessage(ex)); logger.warn("yaml to properties failed, reason: {}", ExceptionUtil.getDetailMessage(ex)); } return false; diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/api/ApolloClientBootstrapArgsMonitorApi.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/api/ApolloClientBootstrapArgsMonitorApi.java new file mode 100644 index 00000000..cd5c33cc --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/api/ApolloClientBootstrapArgsMonitorApi.java @@ -0,0 +1,134 @@ +/* + * Copyright 2022 Authors + * + * 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 com.ctrip.framework.apollo.monitor.api; + +import static com.ctrip.framework.apollo.core.ApolloClientSystemConsts.*; +import static com.ctrip.framework.apollo.core.ConfigConsts.APOLLO_AUTO_UPDATE_INJECTED_SPRING_PROPERTIES; +import static com.ctrip.framework.apollo.monitor.internal.ApolloClientMonitorConstant.*; +import static com.ctrip.framework.apollo.spring.config.PropertySourcesConstants.*; + +import java.util.Collections; +import java.util.Map; + +/** + * @author Rawven + */ +public interface ApolloClientBootstrapArgsMonitorApi { + + /** + * get startup params by key + */ + default Object getStartupArg(String key) { + return getBootstrapArgs().get(key); + } + + /** + * get bootstrap args map + */ + default Map getBootstrapArgs() { + return Collections.emptyMap(); + } + + default String getConfigServiceUrl() { + return (String) getBootstrapArgs().getOrDefault(CONFIG_SERVICE_URL, ""); + } + + default String getAccessKeySecret() { + return (String) getBootstrapArgs().getOrDefault(APOLLO_ACCESS_KEY_SECRET, ""); + } + + default Boolean getAutoUpdateInjectedSpringProperties() { + return (Boolean) getBootstrapArgs().getOrDefault(APOLLO_AUTO_UPDATE_INJECTED_SPRING_PROPERTIES, + false); + } + + default Boolean isBootstrapEnabled() { + return (Boolean) getBootstrapArgs().getOrDefault(APOLLO_BOOTSTRAP_ENABLED, false); + } + + default String getBootstrapNamespaces() { + return (String) getBootstrapArgs().getOrDefault(APOLLO_BOOTSTRAP_NAMESPACES, ""); + } + + default Boolean isBootstrapEagerLoadEnabled() { + return (Boolean) getBootstrapArgs().getOrDefault(APOLLO_BOOTSTRAP_EAGER_LOAD_ENABLED, false); + } + + default Boolean isOverrideSystemProperties() { + return (Boolean) getBootstrapArgs().getOrDefault(APOLLO_OVERRIDE_SYSTEM_PROPERTIES, false); + } + + default String getCacheDir() { + return (String) getBootstrapArgs().getOrDefault(APOLLO_CACHE_DIR, ""); + } + + default String getCluster() { + return (String) getBootstrapArgs().getOrDefault(APOLLO_CLUSTER, ""); + } + + default String getConfigService() { + return (String) getBootstrapArgs().getOrDefault(APOLLO_CONFIG_SERVICE, ""); + } + + default String getClientMonitorExternalForm() { + return (String) getBootstrapArgs().getOrDefault(APOLLO_CLIENT_MONITOR_EXTERNAL_TYPE, ""); + } + + default Boolean isClientMonitorEnabled() { + return (Boolean) getBootstrapArgs().getOrDefault(APOLLO_CLIENT_MONITOR_ENABLED, false); + } + + default Boolean isClientMonitorJmxEnabled() { + return (Boolean) getBootstrapArgs().getOrDefault(APOLLO_CLIENT_MONITOR_JMX_ENABLED, false); + } + + default long getClientMonitorExternalExportPeriod() { + return (Long) getBootstrapArgs().getOrDefault(APOLLO_CLIENT_MONITOR_EXTERNAL_EXPORT_PERIOD, 0L); + } + + default int getClientMonitorExceptionSaveSize() { + return (Integer) getBootstrapArgs().getOrDefault(APOLLO_CLIENT_MONITOR_EXCEPTION_QUEUE_SIZE, 0); + } + + default String getApolloMeta() { + return (String) getBootstrapArgs().getOrDefault(APOLLO_META, ""); + } + + default String getMetaLatestFreshTime() { + return (String) getBootstrapArgs().getOrDefault(META_FRESH, ""); + } + + default Boolean isPropertyNamesCacheEnable() { + return (Boolean) getBootstrapArgs().getOrDefault(APOLLO_PROPERTY_NAMES_CACHE_ENABLE, false); + } + + default Boolean isPropertyOrderEnable() { + return (Boolean) getBootstrapArgs().getOrDefault(APOLLO_PROPERTY_ORDER_ENABLE, false); + } + + default String getVersion() { + return (String) getBootstrapArgs().getOrDefault(VERSION, ""); + } + + default String getEnv() { + return (String) getBootstrapArgs().getOrDefault(ENV, ""); + } + + default String getAppId() { + return (String) getBootstrapArgs().getOrDefault(APP_ID, ""); + } +} \ No newline at end of file diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/api/ApolloClientExceptionMonitorApi.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/api/ApolloClientExceptionMonitorApi.java new file mode 100644 index 00000000..29d2b207 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/api/ApolloClientExceptionMonitorApi.java @@ -0,0 +1,34 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.api; + +import java.util.List; + +/** + * @author Rawven + */ +public interface ApolloClientExceptionMonitorApi { + + /** + * Get exception information the number is limited and can be configured through + * apollo.client.monitor.exception-queue-size + */ + List getApolloConfigExceptionList(); + + Integer getExceptionCountFromStartup(); + +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/api/ApolloClientNamespaceMonitorApi.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/api/ApolloClientNamespaceMonitorApi.java new file mode 100644 index 00000000..fdce6568 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/api/ApolloClientNamespaceMonitorApi.java @@ -0,0 +1,91 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.api; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * @author Rawven + */ +public interface ApolloClientNamespaceMonitorApi { + + /** + * NamespaceMetrics: 1.usageCount 2.firstLoadSpend 3.latestUpdateTime 4.releaseKey + */ + Map getNamespaceMetrics(); + + /** + * get Namespace Config.ItemsNum + */ + Integer getNamespacePropertySize(String namespace); + + /** + * get not found namespaces + */ + List getNotFoundNamespaces(); + + /** + * get timeout namespaces + */ + List getTimeoutNamespaces(); + + + class NamespaceMetrics { + + private AtomicInteger usageCount = new AtomicInteger(0); + private long firstLoadTimeSpendInMs; + private LocalDateTime latestUpdateTime = LocalDateTime.now(); + private String releaseKey = ""; + + public String getReleaseKey() { + return releaseKey; + } + + public void setReleaseKey(String releaseKey) { + this.releaseKey = releaseKey; + } + + public int getUsageCount() { + return usageCount.get(); + } + + public void incrementUsageCount() { + usageCount.incrementAndGet(); + } + + public long getFirstLoadTimeSpendInMs() { + return firstLoadTimeSpendInMs; + } + + public void setFirstLoadTimeSpendInMs(long firstLoadTimeSpendInMs) { + this.firstLoadTimeSpendInMs = firstLoadTimeSpendInMs; + } + + public LocalDateTime getLatestUpdateTime() { + return latestUpdateTime; + } + + public void setLatestUpdateTime(LocalDateTime latestUpdateTime) { + this.latestUpdateTime = latestUpdateTime; + } + } + + +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/api/ApolloClientThreadPoolMonitorApi.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/api/ApolloClientThreadPoolMonitorApi.java new file mode 100644 index 00000000..d38555e4 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/api/ApolloClientThreadPoolMonitorApi.java @@ -0,0 +1,102 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.api; + +import java.util.Map; +import java.util.concurrent.ThreadPoolExecutor; + +/** + * @author Rawven + */ +public interface ApolloClientThreadPoolMonitorApi { + + /** + * get thread pool info key "RemoteConfigRepository" ,"AbstractConfig","AbstractConfigFile"; + */ + Map getThreadPoolInfo(); + + /** + * RemoteConfigRepository.m_executorService + */ + ApolloThreadPoolInfo getRemoteConfigRepositoryThreadPoolInfo(); + + /** + * AbstractConfig.m_executorService + */ + ApolloThreadPoolInfo getAbstractConfigThreadPoolInfo(); + + /** + * AbstractConfigFile.m_executorService + */ + ApolloThreadPoolInfo getAbstractConfigFileThreadPoolInfo(); + + /** + * AbstractApolloClientMetricsExporter.m_executorService + */ + ApolloThreadPoolInfo getMetricsExporterThreadPoolInfo(); + + + class ApolloThreadPoolInfo { + + private ThreadPoolExecutor executor; + + public ApolloThreadPoolInfo(ThreadPoolExecutor executor) { + this.executor = executor; + } + + public ApolloThreadPoolInfo() { + } + + + public int getActiveTaskCount() { + return executor != null ? executor.getActiveCount() : 0; + } + + public int getQueueSize() { + return executor != null ? executor.getQueue().size() : 0; + } + + public int getCorePoolSize() { + return executor != null ? executor.getCorePoolSize() : 0; + } + + public int getMaximumPoolSize() { + return executor != null ? executor.getMaximumPoolSize() : 0; + } + + public int getPoolSize() { + return executor != null ? executor.getPoolSize() : 0; + } + + public long getTotalTaskCount() { + return executor != null ? executor.getTaskCount() : 0; + } + + public long getCompletedTaskCount() { + return executor != null ? executor.getCompletedTaskCount() : 0; + } + + public int getLargestPoolSize() { + return executor != null ? executor.getLargestPoolSize() : 0; + } + + public int getQueueRemainingCapacity() { + return executor != null ? executor.getQueue().remainingCapacity() : 0; + } + + } +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/api/ConfigMonitor.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/api/ConfigMonitor.java new file mode 100644 index 00000000..a1731644 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/api/ConfigMonitor.java @@ -0,0 +1,48 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.api; + +/** + * @author Rawven + */ +public interface ConfigMonitor { + + /** + * get thread pool monitor api + */ + ApolloClientThreadPoolMonitorApi getThreadPoolMonitorApi(); + + /** + * get exception monitor api + */ + ApolloClientExceptionMonitorApi getExceptionMonitorApi(); + + /** + * get namespace monitor api + */ + ApolloClientNamespaceMonitorApi getNamespaceMonitorApi(); + + /** + * get running params monitor api + */ + ApolloClientBootstrapArgsMonitorApi getRunningParamsMonitorApi(); + + /** + * get monitor external system data + */ + String getExporterData(); +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/ApolloClientMonitorConstant.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/ApolloClientMonitorConstant.java new file mode 100644 index 00000000..0a77bdd6 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/ApolloClientMonitorConstant.java @@ -0,0 +1,82 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal; + +/** + * @author Rawven + */ +public class ApolloClientMonitorConstant { + + /** + * common + */ + public static final String MBEAN_NAME = "apollo.client.monitor:type="; + public static final String NAMESPACE = "namespace"; + public static final String TIMESTAMP = "timestamp"; + public static final String THROWABLE = "throwable"; + public static final String NAMESPACE_RELEASE_KEY = "releaseKey"; + public static final String ENV = "env"; + public static final String VERSION = "version"; + public static final String META_FRESH = "metaFreshTime"; + public static final String CONFIG_SERVICE_URL = "configServiceUrl"; + + /** + * tracer + */ + public static final String APOLLO_CLIENT_CONFIGCHANGES = "Apollo.Client.ConfigChanges"; + public static final String APOLLO_CONFIG_EXCEPTION = "ApolloConfigException"; + public static final String APOLLO_META_SERVICE = "Apollo.MetaService"; + public static final String APOLLO_CONFIG_SERVICES = "Apollo.Config.Services"; + public static final String APOLLO_CLIENT_VERSION = "Apollo.Client.Version"; + public static final String APOLLO_CONFIGSERVICE = "Apollo.ConfigService"; + public static final String APOLLO_CONFIGSERVICE_HELP_STR = "periodicRefresh: "; + public static final String APOLLO_CLIENT_CONFIGS = "Apollo.Client.Configs."; + public static final String APOLLO_CLIENT_CONFIGMETA = "Apollo.Client.ConfigMeta"; + public static final String APOLLO_CLIENT_NAMESPACE_NOT_FOUND = "Apollo.Client.NamespaceNotFound"; + public static final String APOLLO_CLIENT_NAMESPACE_TIMEOUT = "Apollo.Client.NamespaceTimeout"; + public static final String APOLLO_CLIENT_NAMESPACE_USAGE = "Apollo.Client.NamespaceUsage"; + public static final String APOLLO_CLIENT_NAMESPACE_FIRST_LOAD_SPEND = "Apollo.Client.NamespaceFirstLoadSpendTime"; + + /** + * listener tag + */ + public static final String TAG_ERROR = "ErrorMonitor"; + public static final String TAG_NAMESPACE = "NamespaceMonitor"; + public static final String TAG_BOOTSTRAP = "BootstrapMonitor"; + public static final String TAG_THREAD_POOL = "ThreadPoolMonitor"; + + /** + * metrics + */ + public static final String METRICS_NAMESPACE_LATEST_UPDATE_TIME = "apollo_client_namespace_latest_update_time"; + public static final String METRICS_NAMESPACE_ITEM_NUM = "apollo_client_namespace_item_num"; + public static final String METRICS_EXCEPTION_NUM = "apollo_client_exception_num"; + public static final String METRICS_NAMESPACE_FIRST_LOAD_SPEND = "apollo_client_namespace_first_load_time_spend_in_ms"; + public static final String METRICS_NAMESPACE_USAGE = "apollo_client_namespace_usage"; + public static final String METRICS_NAMESPACE_NOT_FOUND = "apollo_client_namespace_not_found"; + public static final String METRICS_NAMESPACE_TIMEOUT = "apollo_client_namespace_timeout"; + public static final String METRICS_THREAD_POOL_NAME = "thread_pool_name"; + public static final String METRICS_THREAD_POOL_ACTIVE_TASK_COUNT = "apollo_client_thread_pool_active_task_count"; + public static final String METRICS_THREAD_POOL_QUEUE_SIZE = "apollo_client_thread_pool_queue_size"; + public static final String METRICS_THREAD_POOL_COMPLETED_TASK_COUNT = "apollo_client_thread_pool_completed_task_count"; + public static final String METRICS_THREAD_POOL_POOL_SIZE = "apollo_client_thread_pool_pool_size"; + public static final String METRICS_THREAD_POOL_TOTAL_TASK_COUNT = "apollo_client_thread_pool_total_task_count"; + public static final String METRICS_THREAD_POOL_CORE_POOL_SIZE = "apollo_client_thread_pool_core_pool_size"; + public static final String METRICS_THREAD_POOL_MAXIMUM_POOL_SIZE = "apollo_client_thread_pool_maximum_pool_size"; + public static final String METRICS_THREAD_POOL_LARGEST_POOL_SIZE = "apollo_client_thread_pool_largest_pool_size"; + public static final String METRICS_THREAD_POOL_QUEUE_REMAINING_CAPACITY = "apollo_client_thread_pool_queue_remaining_capacity"; +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/ApolloClientMonitorContext.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/ApolloClientMonitorContext.java new file mode 100644 index 00000000..dbd3d671 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/ApolloClientMonitorContext.java @@ -0,0 +1,103 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal; + +import com.ctrip.framework.apollo.monitor.api.ApolloClientBootstrapArgsMonitorApi; +import com.ctrip.framework.apollo.monitor.api.ApolloClientExceptionMonitorApi; +import com.ctrip.framework.apollo.monitor.api.ApolloClientNamespaceMonitorApi; +import com.ctrip.framework.apollo.monitor.api.ApolloClientThreadPoolMonitorApi; +import com.ctrip.framework.apollo.monitor.internal.exporter.ApolloClientMetricsExporter; +import com.ctrip.framework.apollo.monitor.internal.exporter.impl.NullApolloClientMetricsExporter; +import com.ctrip.framework.apollo.monitor.internal.listener.ApolloClientMonitorEventListener; +import com.ctrip.framework.apollo.monitor.internal.listener.impl.NullClientBootstrapArgsMonitorApi; +import com.ctrip.framework.apollo.monitor.internal.listener.impl.NullClientExceptionMonitorApi; +import com.ctrip.framework.apollo.monitor.internal.listener.impl.NullClientNamespaceMonitorApi; +import com.ctrip.framework.apollo.monitor.internal.listener.impl.NullClientThreadPoolMonitorApi; +import com.google.common.collect.Lists; +import java.util.Collections; +import java.util.List; + +/** + * @author Rawven + */ +public class ApolloClientMonitorContext { + + private ApolloClientExceptionMonitorApi apolloClientExceptionMonitorApi = new NullClientExceptionMonitorApi(); + private ApolloClientNamespaceMonitorApi apolloClientNamespaceMonitorApi = new NullClientNamespaceMonitorApi(); + private ApolloClientBootstrapArgsMonitorApi apolloClientBootstrapArgsMonitorApi = new NullClientBootstrapArgsMonitorApi(); + private ApolloClientThreadPoolMonitorApi apolloClientThreadPoolMonitorApi = new NullClientThreadPoolMonitorApi(); + private ApolloClientMetricsExporter apolloClientMetricsExporter = new NullApolloClientMetricsExporter(); + private List listener = Lists.newArrayList(); + + public void addApolloClientMonitorEventListener(ApolloClientMonitorEventListener listener) { + this.listener.add(listener); + } + + public List getApolloClientMonitorEventListeners() { + return Collections.unmodifiableList(listener); + } + + public void setApolloClientMonitorEventListeners( + List listeners) { + listener = listeners; + } + + public void setApolloClientExceptionMonitorApi( + ApolloClientExceptionMonitorApi apolloClientExceptionMonitorApi) { + this.apolloClientExceptionMonitorApi = apolloClientExceptionMonitorApi; + } + + public void setApolloClientNamespaceMonitorApi( + ApolloClientNamespaceMonitorApi apolloClientNamespaceMonitorApi) { + this.apolloClientNamespaceMonitorApi = apolloClientNamespaceMonitorApi; + } + + public void setApolloClientBootstrapArgsMonitorApi( + ApolloClientBootstrapArgsMonitorApi apolloClientBootstrapArgsMonitorApi) { + this.apolloClientBootstrapArgsMonitorApi = apolloClientBootstrapArgsMonitorApi; + } + + public void setApolloClientThreadPoolMonitorApi( + ApolloClientThreadPoolMonitorApi apolloClientThreadPoolMonitorApi) { + this.apolloClientThreadPoolMonitorApi = apolloClientThreadPoolMonitorApi; + } + + public void setApolloClientMetricsExporter( + ApolloClientMetricsExporter apolloClientMetricsExporter) { + this.apolloClientMetricsExporter = apolloClientMetricsExporter; + } + + public ApolloClientExceptionMonitorApi getExceptionApi() { + return apolloClientExceptionMonitorApi; + } + + public ApolloClientNamespaceMonitorApi getNamespaceApi() { + return apolloClientNamespaceMonitorApi; + } + + public ApolloClientBootstrapArgsMonitorApi getBootstrapArgsApi() { + return apolloClientBootstrapArgsMonitorApi; + } + + public ApolloClientThreadPoolMonitorApi getThreadPoolApi() { + return apolloClientThreadPoolMonitorApi; + } + + public ApolloClientMetricsExporter getMetricsExporter() { + return apolloClientMetricsExporter; + } +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/DefaultConfigMonitor.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/DefaultConfigMonitor.java new file mode 100644 index 00000000..27b6606c --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/DefaultConfigMonitor.java @@ -0,0 +1,60 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal; + +import com.ctrip.framework.apollo.build.ApolloInjector; +import com.ctrip.framework.apollo.monitor.api.ApolloClientBootstrapArgsMonitorApi; +import com.ctrip.framework.apollo.monitor.api.ApolloClientExceptionMonitorApi; +import com.ctrip.framework.apollo.monitor.api.ApolloClientNamespaceMonitorApi; +import com.ctrip.framework.apollo.monitor.api.ApolloClientThreadPoolMonitorApi; +import com.ctrip.framework.apollo.monitor.api.ConfigMonitor; + +/** + * exposes all collected data through ConfigService + * + * @author Rawven + */ +public class DefaultConfigMonitor implements ConfigMonitor { + + private final ApolloClientMonitorContext apolloClientMonitorContext = ApolloInjector.getInstance( + ApolloClientMonitorContext.class); + + @Override + public ApolloClientThreadPoolMonitorApi getThreadPoolMonitorApi() { + return apolloClientMonitorContext.getThreadPoolApi(); + } + + @Override + public ApolloClientExceptionMonitorApi getExceptionMonitorApi() { + return apolloClientMonitorContext.getExceptionApi(); + } + + @Override + public ApolloClientNamespaceMonitorApi getNamespaceMonitorApi() { + return apolloClientMonitorContext.getNamespaceApi(); + } + + @Override + public ApolloClientBootstrapArgsMonitorApi getRunningParamsMonitorApi() { + return apolloClientMonitorContext.getBootstrapArgsApi(); + } + + @Override + public String getExporterData() { + return apolloClientMonitorContext.getMetricsExporter().response(); + } +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/enums/MetricTypeEnums.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/enums/MetricTypeEnums.java new file mode 100644 index 00000000..c4c73440 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/enums/MetricTypeEnums.java @@ -0,0 +1,32 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.enums; + +/** + * @author Rawven + */ +public enum MetricTypeEnums { + /** + * counter + */ + COUNTER, + + /** + * gauge + */ + GAUGE +} \ No newline at end of file diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/event/ApolloClientMonitorEvent.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/event/ApolloClientMonitorEvent.java new file mode 100644 index 00000000..e7b4f077 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/event/ApolloClientMonitorEvent.java @@ -0,0 +1,69 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.event; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * @author Rawven + */ +public class ApolloClientMonitorEvent { + + private final String name; + private final Map attachments; + private String tag; + + public ApolloClientMonitorEvent(String name, String tag, Map attachments) { + this.name = name; + this.tag = tag; + this.attachments = attachments != null ? new HashMap<>(attachments) : Collections.emptyMap(); + } + + public ApolloClientMonitorEvent withTag(String tag) { + this.tag = tag; + return this; + } + + public String getTag() { + return tag; + } + + public String getName() { + return name; + } + + public ApolloClientMonitorEvent putAttachment(String key, Object value) { + this.attachments.put(key, value); + return this; + } + + + @SuppressWarnings("unchecked") + public T getAttachmentValue(String key) { + Object value = attachments.get(key); + if (value == null) { + return null; + } + try { + return (T) value; + } catch (ClassCastException e) { + throw new IllegalArgumentException("Value for key " + key + " is not of expected type", e); + } + } +} \ No newline at end of file diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/event/ApolloClientMonitorEventFactory.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/event/ApolloClientMonitorEventFactory.java new file mode 100644 index 00000000..0bd51ecf --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/event/ApolloClientMonitorEventFactory.java @@ -0,0 +1,46 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.event; + +import java.util.HashMap; + +/** + * @author Rawven + * @date 2024/08/08 + */ +public class ApolloClientMonitorEventFactory { + + private static volatile ApolloClientMonitorEventFactory INSTANCE; + + private ApolloClientMonitorEventFactory() { + } + + public static ApolloClientMonitorEventFactory getInstance() { + if (INSTANCE == null) { + synchronized (ApolloClientMonitorEventFactory.class) { + if (INSTANCE == null) { + INSTANCE = new ApolloClientMonitorEventFactory(); + } + } + } + return INSTANCE; + } + + public ApolloClientMonitorEvent createEvent(String name) { + return new ApolloClientMonitorEvent(name, null, new HashMap<>(2)); + } +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/event/ApolloClientMonitorEventPublisher.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/event/ApolloClientMonitorEventPublisher.java new file mode 100644 index 00000000..7e11b0bb --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/event/ApolloClientMonitorEventPublisher.java @@ -0,0 +1,52 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.event; + +import com.ctrip.framework.apollo.build.ApolloInjector; +import com.ctrip.framework.apollo.monitor.internal.listener.ApolloClientMonitorEventListener; +import com.ctrip.framework.apollo.monitor.internal.ApolloClientMonitorContext; +import com.ctrip.framework.apollo.util.ConfigUtil; + +/** + * @author Rawven + */ +public class ApolloClientMonitorEventPublisher { + + private static ApolloClientMonitorContext MONITOR_CONTEXT = ApolloInjector.getInstance( + ApolloClientMonitorContext.class); + private static ConfigUtil m_configUtil = ApolloInjector.getInstance(ConfigUtil.class); + + public static void publish(ApolloClientMonitorEvent event) { + if (m_configUtil.isClientMonitorEnabled()) { + for (ApolloClientMonitorEventListener listener : MONITOR_CONTEXT.getApolloClientMonitorEventListeners()) { + if (listener.isSupported(event)) { + listener.collect(event); + return; + } + } + } + } + + protected static void reset() { + MONITOR_CONTEXT = ApolloInjector.getInstance( + ApolloClientMonitorContext.class); + m_configUtil = ApolloInjector.getInstance(ConfigUtil.class); + + } +} + + diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/exporter/AbstractApolloClientMetricsExporter.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/exporter/AbstractApolloClientMetricsExporter.java new file mode 100644 index 00000000..0102d8cd --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/exporter/AbstractApolloClientMetricsExporter.java @@ -0,0 +1,106 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.exporter; + +import com.ctrip.framework.apollo.core.utils.ApolloThreadFactory; +import com.ctrip.framework.apollo.core.utils.DeferredLoggerFactory; +import com.ctrip.framework.apollo.monitor.internal.listener.ApolloClientMonitorEventListener; +import com.ctrip.framework.apollo.monitor.internal.model.CounterModel; +import com.ctrip.framework.apollo.monitor.internal.model.GaugeModel; +import com.ctrip.framework.apollo.monitor.internal.model.SampleModel; +import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import org.slf4j.Logger; + +/** + * @author Rawven + */ +public abstract class AbstractApolloClientMetricsExporter implements ApolloClientMetricsExporter { + + public static final ScheduledExecutorService m_executorService; + private static final Logger log = DeferredLoggerFactory.getLogger( + AbstractApolloClientMetricsExporter.class); + private static final long INITIAL_DELAY = 5L; + private static final int THREAD_POOL_SIZE = 1; + + static { + m_executorService = Executors.newScheduledThreadPool(THREAD_POOL_SIZE, + ApolloThreadFactory.create(ApolloClientMetricsExporter.class.getName(), true)); + } + + protected List listeners; + + @Override + public void init(List listeners, long collectPeriod) { + log.info("Initializing metrics exporter with {} listeners and collect period of {} seconds.", + listeners.size(), collectPeriod); + doInit(); + this.listeners = listeners; + initScheduleMetricsCollectSync(collectPeriod); + log.info("Metrics collection scheduled with a period of {} seconds.", collectPeriod); + } + + /** + * Provide initialization extension points + */ + protected abstract void doInit(); + + private void initScheduleMetricsCollectSync(long collectPeriod) { + m_executorService.scheduleAtFixedRate(() -> { + try { + updateMetricsData(); + } catch (Throwable ex) { + log.error("Error updating metrics data", ex); + } + }, INITIAL_DELAY, collectPeriod, TimeUnit.SECONDS); + } + + protected void updateMetricsData() { + log.debug("Start to update metrics data job"); + listeners.forEach(listener -> { + if (listener.isMetricsSampleUpdated()) { + log.debug("Listener {} has updated samples.", listener.getName()); + listener.export().forEach(this::registerSample); + } + }); + } + + protected void registerSample(SampleModel sample) { + try { + switch (sample.getType()) { + case GAUGE: + GaugeModel gaugeModel = (GaugeModel) sample; + registerOrUpdateGaugeSample(gaugeModel.getName(), gaugeModel.getTags(), + gaugeModel.getValue()); + break; + case COUNTER: + CounterModel counterModel = (CounterModel) sample; + registerOrUpdateCounterSample(counterModel.getName(), counterModel.getTags(), + counterModel.getIncreaseValueAndResetZero()); + break; + default: + log.warn("Unsupported sample type: {}", sample.getType()); + break; + } + } catch (Exception e) { + log.error("Register sample error", e); + } + } + +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/exporter/ApolloClientMetricsExporter.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/exporter/ApolloClientMetricsExporter.java new file mode 100644 index 00000000..83f32b5c --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/exporter/ApolloClientMetricsExporter.java @@ -0,0 +1,59 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.exporter; + +import com.ctrip.framework.apollo.core.spi.Ordered; +import com.ctrip.framework.apollo.monitor.internal.listener.ApolloClientMonitorEventListener; +import java.util.List; +import java.util.Map; + +/** + * @author Rawven + */ +public interface ApolloClientMetricsExporter extends Ordered { + + /** + * init method + */ + void init(List listeners, long collectPeriod); + + /** + * Used to access custom monitoring systems + */ + boolean isSupport(String form); + + /** + * register or update counter sample + */ + void registerOrUpdateCounterSample(String name, Map tag, double incrValue); + + + /** + * register or update gauge sample + */ + void registerOrUpdateGaugeSample(String name, Map tag, double value); + + /** + * result of the collect metrics + */ + String response(); + + @Override + default int getOrder() { + return 0; + } +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/exporter/ApolloClientMetricsExporterFactory.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/exporter/ApolloClientMetricsExporterFactory.java new file mode 100644 index 00000000..cec6b6d8 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/exporter/ApolloClientMetricsExporterFactory.java @@ -0,0 +1,31 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.exporter; + +import com.ctrip.framework.apollo.monitor.internal.listener.ApolloClientMonitorEventListener; +import java.util.List; + +/** + * @author Rawven + */ +public interface ApolloClientMetricsExporterFactory { + + /** + * get metrics reporter + */ + ApolloClientMetricsExporter getMetricsReporter(List listeners); +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/exporter/impl/DefaultApolloClientMetricsExporterFactory.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/exporter/impl/DefaultApolloClientMetricsExporterFactory.java new file mode 100644 index 00000000..def890f3 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/exporter/impl/DefaultApolloClientMetricsExporterFactory.java @@ -0,0 +1,75 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.exporter.impl; + +import com.ctrip.framework.apollo.build.ApolloInjector; +import com.ctrip.framework.apollo.core.utils.DeferredLoggerFactory; +import com.ctrip.framework.apollo.core.utils.StringUtils; +import com.ctrip.framework.apollo.exceptions.ApolloConfigException; +import com.ctrip.framework.apollo.monitor.internal.listener.ApolloClientMonitorEventListener; +import com.ctrip.framework.apollo.monitor.internal.exporter.ApolloClientMetricsExporter; +import com.ctrip.framework.apollo.monitor.internal.exporter.ApolloClientMetricsExporterFactory; +import com.ctrip.framework.apollo.tracer.Tracer; +import com.ctrip.framework.apollo.util.ConfigUtil; +import com.ctrip.framework.foundation.internals.ServiceBootstrap; +import java.util.List; +import org.slf4j.Logger; + +/** + * @author Rawven + */ +public class DefaultApolloClientMetricsExporterFactory implements + ApolloClientMetricsExporterFactory { + + private static final Logger logger = DeferredLoggerFactory.getLogger( + DefaultApolloClientMetricsExporterFactory.class); + private final ConfigUtil configUtil = ApolloInjector.getInstance(ConfigUtil.class); + + @Override + public ApolloClientMetricsExporter getMetricsReporter( + List listeners) { + String externalSystemType = configUtil.getMonitorExternalType(); + return findAndInitializeExporter(listeners, externalSystemType); + } + + private ApolloClientMetricsExporter findAndInitializeExporter( + List listeners, String externalSystemType) { + List exporters = ServiceBootstrap.loadAllOrdered( + ApolloClientMetricsExporter.class); + if (StringUtils.isEmpty(externalSystemType)) { + return null; + } + ApolloClientMetricsExporter reporter = exporters.stream() + .filter(metricsExporter -> metricsExporter.isSupport(externalSystemType)) + .findFirst() + .orElse(null); + + if (reporter != null) { + reporter.init(listeners, configUtil.getMonitorExternalExportPeriod()); + } else { + String errorMessage = + "No matching exporter found with monitor-external-type " + externalSystemType; + ApolloConfigException exception = new ApolloConfigException(errorMessage); + logger.error( + "Error initializing exporter for external-type: {}. Please check if external-type is misspelled or the correct dependency is not introduced, such as apollo-plugin-client-prometheus", + externalSystemType, exception); + Tracer.logError(exception); + } + return reporter; + } + +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/exporter/impl/NullApolloClientMetricsExporter.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/exporter/impl/NullApolloClientMetricsExporter.java new file mode 100644 index 00000000..3bc195d5 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/exporter/impl/NullApolloClientMetricsExporter.java @@ -0,0 +1,60 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.exporter.impl; + +import com.ctrip.framework.apollo.core.utils.DeferredLoggerFactory; +import com.ctrip.framework.apollo.monitor.internal.exporter.AbstractApolloClientMetricsExporter; +import com.ctrip.framework.apollo.monitor.internal.listener.ApolloClientMonitorEventListener; +import com.ctrip.framework.apollo.monitor.internal.exporter.ApolloClientMetricsExporter; +import java.util.List; +import java.util.Map; +import org.slf4j.Logger; + +/** + * @author Rawven + */ +public class NullApolloClientMetricsExporter implements ApolloClientMetricsExporter { + + private static final Logger log = DeferredLoggerFactory.getLogger( + NullApolloClientMetricsExporter.class); + + @Override + public void init(List listeners, long collectPeriod) { + } + + @Override + public boolean isSupport(String form) { + return false; + } + + @Override + public void registerOrUpdateCounterSample(String name, Map tag, + double incrValue) { + + } + + @Override + public void registerOrUpdateGaugeSample(String name, Map tag, double value) { + + } + + @Override + public String response() { + log.warn("No metrics exporter found, response empty string"); + return ""; + } +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/jmx/ApolloClientJmxMBeanRegister.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/jmx/ApolloClientJmxMBeanRegister.java new file mode 100644 index 00000000..33d9108d --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/jmx/ApolloClientJmxMBeanRegister.java @@ -0,0 +1,79 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.jmx; + +import static com.ctrip.framework.apollo.monitor.internal.ApolloClientMonitorConstant.MBEAN_NAME; + +import com.ctrip.framework.apollo.core.utils.DeferredLoggerFactory; +import java.lang.management.ManagementFactory; +import javax.management.JMException; +import javax.management.MBeanServer; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import org.slf4j.Logger; + +/** + * @author Rawven + */ +public final class ApolloClientJmxMBeanRegister { + + private static final Logger logger = DeferredLoggerFactory.getLogger( + ApolloClientJmxMBeanRegister.class); + private static MBeanServer mbeanServer; + private static ObjectName ERROR_OBJECT_NAME; + + static { + try { + ERROR_OBJECT_NAME = new ObjectName(MBEAN_NAME + "error"); + } catch (MalformedObjectNameException e) { + logger.warn("MalformedObjectNameException during static initialization.", e); + } + } + + public static synchronized void setMBeanServer(MBeanServer mbeanServer) { + ApolloClientJmxMBeanRegister.mbeanServer = mbeanServer; + } + + public static synchronized ObjectName register(String name, Object mbean) { + try { + ObjectName objectName = new ObjectName(name); + + if (mbeanServer == null) { + mbeanServer = ManagementFactory.getPlatformMBeanServer(); + } + + if (mbeanServer.isRegistered(objectName)) { + mbeanServer.unregisterMBean(objectName); + } + mbeanServer.registerMBean(mbean, objectName); + + return objectName; + } catch (JMException e) { + logger.error("Register JMX MBean failed.", e); + return ERROR_OBJECT_NAME; + } + } + + public static synchronized void unregister(String name) { + try { + MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer(); + mbeanServer.unregisterMBean(new ObjectName(name)); + } catch (JMException e) { + logger.error("Unregister JMX MBean failed.", e); + } + } +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/jmx/mbean/ApolloClientJmxBootstrapArgsMBean.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/jmx/mbean/ApolloClientJmxBootstrapArgsMBean.java new file mode 100644 index 00000000..d00597b5 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/jmx/mbean/ApolloClientJmxBootstrapArgsMBean.java @@ -0,0 +1,35 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.jmx.mbean; + +import java.util.Map; +import javax.management.MXBean; + +/** + * @author Rawven + */ +@MXBean +public interface ApolloClientJmxBootstrapArgsMBean { + // Because JMX does not support all type return values + // declare the interface separately. + + /** + * get bootstrap args map + */ + Map getBootstrapArgsString(); + +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/jmx/mbean/ApolloClientJmxExceptionMBean.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/jmx/mbean/ApolloClientJmxExceptionMBean.java new file mode 100644 index 00000000..076b8639 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/jmx/mbean/ApolloClientJmxExceptionMBean.java @@ -0,0 +1,36 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.jmx.mbean; + +import java.util.List; +import javax.management.MXBean; + +/** + * @author Rawven + */ +@MXBean +public interface ApolloClientJmxExceptionMBean { + // Because JMX does not support all type return values + // declare the interface separately. + + /** + * get exception details + */ + List getApolloConfigExceptionDetails(); + + Integer getExceptionCountFromStartup(); +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/jmx/mbean/ApolloClientJmxNamespaceMBean.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/jmx/mbean/ApolloClientJmxNamespaceMBean.java new file mode 100644 index 00000000..e2a9412a --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/jmx/mbean/ApolloClientJmxNamespaceMBean.java @@ -0,0 +1,92 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.jmx.mbean; + +import java.util.List; +import java.util.Map; +import javax.management.MXBean; + +/** + * @author Rawven + */ +@MXBean +public interface ApolloClientJmxNamespaceMBean { + // Because JMX does not support all type return values + // declare the interface separately. + + /** + * NamespaceMetrics: 1.usageCount 2.firstLoadSpend 3.latestUpdateTime 4.releaseKey + */ + Map getNamespaceMetricsString(); + + /** + * get Namespace Config.ItemsNum + */ + Integer getNamespacePropertySize(String namespace); + + /** + * get not found namespaces + */ + List getNotFoundNamespaces(); + + /** + * get timeout namespaces + */ + List getTimeoutNamespaces(); + + + class NamespaceMetricsString { + + private int usageCount; + private long firstLoadTimeSpendInMs; + private String latestUpdateTime; + private String releaseKey = ""; + + public int getUsageCount() { + return usageCount; + } + + public void setUsageCount(int usageCount) { + this.usageCount = usageCount; + } + + public long getFirstLoadTimeSpendInMs() { + return firstLoadTimeSpendInMs; + } + + public void setFirstLoadTimeSpendInMs(long firstLoadTimeSpendInMs) { + this.firstLoadTimeSpendInMs = firstLoadTimeSpendInMs; + } + + public String getLatestUpdateTime() { + return latestUpdateTime; + } + + public void setLatestUpdateTime(String latestUpdateTime) { + this.latestUpdateTime = latestUpdateTime; + } + + public String getReleaseKey() { + return releaseKey; + } + + public void setReleaseKey(String releaseKey) { + this.releaseKey = releaseKey; + } + } + +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/jmx/mbean/ApolloClientJmxThreadPoolMBean.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/jmx/mbean/ApolloClientJmxThreadPoolMBean.java new file mode 100644 index 00000000..78d090fa --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/jmx/mbean/ApolloClientJmxThreadPoolMBean.java @@ -0,0 +1,29 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.jmx.mbean; + +import com.ctrip.framework.apollo.monitor.api.ApolloClientThreadPoolMonitorApi; +import javax.management.MXBean; + +/** + * @author Rawven + */ +@MXBean +public interface ApolloClientJmxThreadPoolMBean extends ApolloClientThreadPoolMonitorApi { + + +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/listener/AbstractApolloClientMonitorEventListener.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/listener/AbstractApolloClientMonitorEventListener.java new file mode 100644 index 00000000..847410f7 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/listener/AbstractApolloClientMonitorEventListener.java @@ -0,0 +1,137 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.listener; + +import com.ctrip.framework.apollo.monitor.internal.event.ApolloClientMonitorEvent; +import com.ctrip.framework.apollo.monitor.internal.model.CounterModel; +import com.ctrip.framework.apollo.monitor.internal.model.GaugeModel; +import com.ctrip.framework.apollo.monitor.internal.model.SampleModel; +import com.google.common.collect.Maps; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * @author Rawven + */ +public abstract class AbstractApolloClientMonitorEventListener implements + ApolloClientMonitorEventListener { + + private final Map counterSamples = Maps.newConcurrentMap(); + private final Map gaugeSamples = Maps.newConcurrentMap(); + private final AtomicBoolean isUpdated = new AtomicBoolean(); + private final String tag; + + public AbstractApolloClientMonitorEventListener(String tag) { + this.tag = tag; + } + + @Override + public String getName() { + return tag; + } + + @Override + public boolean isSupported(ApolloClientMonitorEvent event) { + return tag.equals(event.getTag()); + } + + @Override + public void collect(ApolloClientMonitorEvent event) { + collect0(event); + isUpdated.set(true); + } + + @Override + public boolean isMetricsSampleUpdated() { + return isUpdated.getAndSet(false); + } + + @Override + public List export() { + export0(); + List samples = new ArrayList<>(counterSamples.values()); + samples.addAll(gaugeSamples.values()); + return samples; + } + + /** + * Specific collection logic + */ + protected void collect0(ApolloClientMonitorEvent event) { + } + + /** + * Convenient for indicators that can only be obtained from the status object + */ + protected void export0() { + } + + + /** + * tool method for updating indicator model + */ + public void createOrUpdateGaugeSample(String metricsName, String[] tagKeys, String[] tagValues, + double value) { + createOrUpdateSample(metricsName, tagKeys, tagValues, value, false); + } + + public void createOrUpdateGaugeSample(String metricsName, double value) { + createOrUpdateSample(metricsName, null, null, value, false); + } + + public void createOrUpdateCounterSample(String metricsName, String[] tagKeys, String[] tagValues, + double increaseValue) { + createOrUpdateSample(metricsName, tagKeys, tagValues, increaseValue, true); + } + + public void createOrUpdateCounterSample(String metricsName, double increaseValue) { + createOrUpdateSample(metricsName, null, null, increaseValue, true); + } + + private void createOrUpdateSample(String metricsName, String[] tagKeys, String[] tagValues, + double value, boolean isCounter) { + String mapKey = metricsName + (tagValues != null ? Arrays.toString(tagValues) : ""); + + if (isCounter) { + CounterModel counter = counterSamples.computeIfAbsent(mapKey, + key -> (CounterModel) CounterModel.create(metricsName, 0) + .putTags(getTags(tagKeys, tagValues))); + counter.increase(value); + } else { + GaugeModel gauge = gaugeSamples.computeIfAbsent(mapKey, + key -> (GaugeModel) GaugeModel.create(metricsName, 0) + .putTags(getTags(tagKeys, tagValues))); + gauge.setValue(value); + } + } + + private Map getTags(String[] tagKeys, String[] tagValues) { + if (tagKeys != null && tagValues != null && tagKeys.length == tagValues.length) { + Map tags = Maps.newHashMap(); + for (int i = 0; i < tagKeys.length; i++) { + tags.put(tagKeys[i], tagValues[i]); + } + return tags; + } + return Collections.emptyMap(); + } + +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/listener/ApolloClientMonitorEventListener.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/listener/ApolloClientMonitorEventListener.java new file mode 100644 index 00000000..d808d24d --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/listener/ApolloClientMonitorEventListener.java @@ -0,0 +1,55 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.listener; + +import com.ctrip.framework.apollo.monitor.internal.event.ApolloClientMonitorEvent; +import com.ctrip.framework.apollo.monitor.internal.model.SampleModel; +import java.util.List; + +/** + * @author Rawven + */ +public interface ApolloClientMonitorEventListener { + + + /** + * mbean name + */ + String getName(); + + /** + * is support the event + */ + boolean isSupported(ApolloClientMonitorEvent event); + + /** + * collect metrics from event + */ + void collect(ApolloClientMonitorEvent event); + + /** + * is samples updated + */ + boolean isMetricsSampleUpdated(); + + /** + * export to a format recognized by the monitoring system + */ + List export(); + + +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/DefaultApolloClientBootstrapArgsApi.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/DefaultApolloClientBootstrapArgsApi.java new file mode 100644 index 00000000..19ca9b30 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/DefaultApolloClientBootstrapArgsApi.java @@ -0,0 +1,108 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.listener.impl; + +import static com.ctrip.framework.apollo.core.ApolloClientSystemConsts.*; +import static com.ctrip.framework.apollo.core.ConfigConsts.APOLLO_AUTO_UPDATE_INJECTED_SPRING_PROPERTIES; +import static com.ctrip.framework.apollo.monitor.internal.ApolloClientMonitorConstant.*; +import static com.ctrip.framework.apollo.spring.config.PropertySourcesConstants.*; + +import com.ctrip.framework.apollo.Apollo; +import com.ctrip.framework.apollo.core.utils.DeferredLoggerFactory; +import com.ctrip.framework.apollo.monitor.api.ApolloClientBootstrapArgsMonitorApi; +import com.ctrip.framework.apollo.monitor.internal.jmx.mbean.ApolloClientJmxBootstrapArgsMBean; +import com.ctrip.framework.apollo.monitor.internal.listener.AbstractApolloClientMonitorEventListener; +import com.ctrip.framework.apollo.monitor.internal.event.ApolloClientMonitorEvent; +import com.ctrip.framework.apollo.util.ConfigUtil; +import com.google.common.collect.Maps; +import java.util.Map; +import org.slf4j.Logger; + +/** + * @author Rawven + */ +public class DefaultApolloClientBootstrapArgsApi extends + AbstractApolloClientMonitorEventListener implements + ApolloClientBootstrapArgsMonitorApi, ApolloClientJmxBootstrapArgsMBean { + + private static final Logger logger = DeferredLoggerFactory.getLogger( + DefaultApolloClientBootstrapArgsApi.class); + private final Map bootstrapArgs = Maps.newHashMap(); + private final Map bootstrapArgsString = Maps.newHashMap(); + + public DefaultApolloClientBootstrapArgsApi(ConfigUtil configUtil) { + super(TAG_BOOTSTRAP); + bootstrapArgs.put(APOLLO_ACCESS_KEY_SECRET, configUtil.getAccessKeySecret()); + bootstrapArgs.put(APOLLO_AUTO_UPDATE_INJECTED_SPRING_PROPERTIES, + configUtil.isAutoUpdateInjectedSpringPropertiesEnabled()); + bootstrapArgs.put(APOLLO_BOOTSTRAP_ENABLED, + Boolean.parseBoolean(System.getProperty(APOLLO_BOOTSTRAP_ENABLED))); + bootstrapArgs.put(APOLLO_BOOTSTRAP_NAMESPACES, + System.getProperty(APOLLO_BOOTSTRAP_NAMESPACES)); + bootstrapArgs.put(APOLLO_BOOTSTRAP_EAGER_LOAD_ENABLED, + Boolean.parseBoolean(System.getProperty(APOLLO_BOOTSTRAP_EAGER_LOAD_ENABLED))); + bootstrapArgs.put(APOLLO_OVERRIDE_SYSTEM_PROPERTIES, configUtil.isOverrideSystemProperties()); + bootstrapArgs.put(APOLLO_CACHE_DIR, configUtil.getDefaultLocalCacheDir()); + bootstrapArgs.put(APOLLO_CLUSTER, configUtil.getCluster()); + bootstrapArgs.put(APOLLO_CONFIG_SERVICE, + System.getProperty(APOLLO_CONFIG_SERVICE)); + bootstrapArgs.put(APOLLO_CLIENT_MONITOR_EXTERNAL_TYPE, configUtil.getMonitorExternalType()); + bootstrapArgs.put(APOLLO_CLIENT_MONITOR_ENABLED, configUtil.isClientMonitorEnabled()); + bootstrapArgs.put(APOLLO_CLIENT_MONITOR_EXTERNAL_EXPORT_PERIOD, + configUtil.getMonitorExternalExportPeriod()); + bootstrapArgs.put(APOLLO_META, configUtil.getMetaServerDomainName()); + bootstrapArgs.put(APOLLO_PROPERTY_NAMES_CACHE_ENABLE, configUtil.isPropertyNamesCacheEnabled()); + bootstrapArgs.put(APOLLO_PROPERTY_ORDER_ENABLE, configUtil.isPropertiesOrderEnabled()); + bootstrapArgs.put(APOLLO_CLIENT_MONITOR_JMX_ENABLED, configUtil.isClientMonitorJmxEnabled()); + bootstrapArgs.put(APOLLO_CLIENT_MONITOR_EXCEPTION_QUEUE_SIZE, + configUtil.getMonitorExceptionQueueSize()); + bootstrapArgs.put(APP_ID, configUtil.getAppId()); + bootstrapArgs.put(ENV, configUtil.getApolloEnv()); + bootstrapArgs.put(VERSION, Apollo.VERSION); + bootstrapArgs.forEach((key, value) -> { + if (value != null) { + bootstrapArgsString.put(key, value.toString()); + } + }); + + } + + @Override + public void collect0(ApolloClientMonitorEvent event) { + String argName = event.getName(); + if (bootstrapArgs.containsKey(argName)) { + bootstrapArgs.put(argName, event.getAttachmentValue(argName)); + } else { + logger.warn("Unhandled event name: {}", argName); + } + } + + @Override + public boolean isMetricsSampleUpdated() { + return false; + } + + @Override + public Map getBootstrapArgs() { + return bootstrapArgs; + } + + @Override + public Map getBootstrapArgsString() { + return bootstrapArgsString; + } +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/DefaultApolloClientExceptionApi.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/DefaultApolloClientExceptionApi.java new file mode 100644 index 00000000..ba650a12 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/DefaultApolloClientExceptionApi.java @@ -0,0 +1,82 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.listener.impl; + +import static com.ctrip.framework.apollo.monitor.internal.ApolloClientMonitorConstant.METRICS_EXCEPTION_NUM; +import static com.ctrip.framework.apollo.monitor.internal.ApolloClientMonitorConstant.TAG_ERROR; +import static com.ctrip.framework.apollo.monitor.internal.ApolloClientMonitorConstant.THROWABLE; + +import com.ctrip.framework.apollo.build.ApolloInjector; +import com.ctrip.framework.apollo.exceptions.ApolloConfigException; +import com.ctrip.framework.apollo.monitor.api.ApolloClientExceptionMonitorApi; +import com.ctrip.framework.apollo.monitor.internal.jmx.mbean.ApolloClientJmxExceptionMBean; +import com.ctrip.framework.apollo.monitor.internal.listener.AbstractApolloClientMonitorEventListener; +import com.ctrip.framework.apollo.monitor.internal.event.ApolloClientMonitorEvent; +import com.ctrip.framework.apollo.util.ConfigUtil; +import com.google.common.collect.EvictingQueue; +import com.google.common.collect.Queues; +import java.util.ArrayList; +import java.util.List; +import java.util.Queue; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +/** + * @author Rawven + */ +public class DefaultApolloClientExceptionApi extends + AbstractApolloClientMonitorEventListener implements + ApolloClientExceptionMonitorApi, ApolloClientJmxExceptionMBean { + + private final AtomicInteger exceptionCountFromStartup = new AtomicInteger(0); + private final Queue exceptionsQueue; + + public DefaultApolloClientExceptionApi(ConfigUtil configUtil) { + super(TAG_ERROR); + int monitorExceptionQueueSize = configUtil.getMonitorExceptionQueueSize(); + EvictingQueue evictingQueue = EvictingQueue.create( + monitorExceptionQueueSize); + exceptionsQueue = Queues.synchronizedQueue(evictingQueue); + } + + @Override + public List getApolloConfigExceptionList() { + return new ArrayList<>(exceptionsQueue); + } + + @Override + public Integer getExceptionCountFromStartup() { + return exceptionCountFromStartup.get(); + } + + @Override + public void collect0(ApolloClientMonitorEvent event) { + ApolloConfigException exception = event.getAttachmentValue(THROWABLE); + if (exception != null) { + exceptionsQueue.add(exception); + exceptionCountFromStartup.incrementAndGet(); + createOrUpdateCounterSample(METRICS_EXCEPTION_NUM, 1); + } + } + + @Override + public List getApolloConfigExceptionDetails() { + return exceptionsQueue.stream() + .map(ApolloConfigException::getMessage) + .collect(Collectors.toList()); + } +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/DefaultApolloClientNamespaceApi.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/DefaultApolloClientNamespaceApi.java new file mode 100644 index 00000000..b6527b8b --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/DefaultApolloClientNamespaceApi.java @@ -0,0 +1,199 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.listener.impl; + + +import static com.ctrip.framework.apollo.monitor.internal.ApolloClientMonitorConstant.*; + +import com.ctrip.framework.apollo.Config; +import com.ctrip.framework.apollo.ConfigFile; +import com.ctrip.framework.apollo.core.utils.DeferredLoggerFactory; +import com.ctrip.framework.apollo.internals.ConfigManager; +import com.ctrip.framework.apollo.monitor.api.ApolloClientNamespaceMonitorApi; +import com.ctrip.framework.apollo.monitor.internal.jmx.mbean.ApolloClientJmxNamespaceMBean; +import com.ctrip.framework.apollo.monitor.internal.ApolloClientMonitorConstant; +import com.ctrip.framework.apollo.monitor.internal.listener.AbstractApolloClientMonitorEventListener; +import com.ctrip.framework.apollo.monitor.internal.event.ApolloClientMonitorEvent; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; +import org.slf4j.Logger; + +/** + * @author Rawven + */ +public class DefaultApolloClientNamespaceApi extends + AbstractApolloClientMonitorEventListener implements + ApolloClientNamespaceMonitorApi, ApolloClientJmxNamespaceMBean { + + private static final Logger logger = DeferredLoggerFactory.getLogger( + DefaultApolloClientNamespaceApi.class); + private final ConfigManager configManager; + private final Map namespaces = Maps.newConcurrentMap(); + private final Set namespace404 = Sets.newCopyOnWriteArraySet(); + private final Set namespaceTimeout = Sets.newCopyOnWriteArraySet(); + + public DefaultApolloClientNamespaceApi(ConfigManager configManager + ) { + super(TAG_NAMESPACE); + this.configManager = configManager; + } + + @Override + public void collect0(ApolloClientMonitorEvent event) { + String namespace = event.getAttachmentValue(NAMESPACE); + String eventName = event.getName(); + + switch (eventName) { + case APOLLO_CLIENT_NAMESPACE_NOT_FOUND: + handleNamespaceNotFound(namespace); + break; + case APOLLO_CLIENT_NAMESPACE_TIMEOUT: + handleNamespaceTimeout(namespace); + break; + default: + handleNormalNamespace(namespace, event); + break; + } + } + + private void handleNormalNamespace(String namespace, ApolloClientMonitorEvent event) { + namespace404.remove(namespace); + namespaceTimeout.remove(namespace); + NamespaceMetrics namespaceMetrics = namespaces.computeIfAbsent(namespace, + k -> new NamespaceMetrics()); + collectMetrics(event, namespaceMetrics, namespace); + } + + private void collectMetrics(ApolloClientMonitorEvent event, NamespaceMetrics namespaceMetrics, + String namespace) { + String eventName = event.getName(); + switch (eventName) { + case APOLLO_CLIENT_NAMESPACE_USAGE: + handleUsageEvent(namespaceMetrics, namespace); + break; + case METRICS_NAMESPACE_LATEST_UPDATE_TIME: + handleUpdateTimeEvent(event, namespaceMetrics); + break; + case APOLLO_CLIENT_NAMESPACE_FIRST_LOAD_SPEND: + handleFirstLoadSpendEvent(event, namespaceMetrics); + break; + case NAMESPACE_RELEASE_KEY: + handleReleaseKeyEvent(event, namespaceMetrics); + break; + default: + logger.warn("Unhandled event name: {}", eventName); + break; + } + } + + private void handleNamespaceNotFound(String namespace) { + namespace404.add(namespace); + } + + private void handleNamespaceTimeout(String namespace) { + namespaceTimeout.add(namespace); + } + + + private void handleUsageEvent(NamespaceMetrics namespaceMetrics, String namespace) { + namespaceMetrics.incrementUsageCount(); + createOrUpdateCounterSample(ApolloClientMonitorConstant.METRICS_NAMESPACE_USAGE, + new String[]{NAMESPACE}, new String[]{namespace}, 1); + } + + private void handleUpdateTimeEvent(ApolloClientMonitorEvent event, + NamespaceMetrics namespaceMetrics) { + namespaceMetrics.setLatestUpdateTime(LocalDateTime.now()); + } + + private void handleFirstLoadSpendEvent(ApolloClientMonitorEvent event, + NamespaceMetrics namespaceMetrics) { + long firstLoadSpendTime = event.getAttachmentValue(ApolloClientMonitorConstant.TIMESTAMP); + namespaceMetrics.setFirstLoadTimeSpendInMs(firstLoadSpendTime); + } + + private void handleReleaseKeyEvent(ApolloClientMonitorEvent event, + NamespaceMetrics namespaceMetrics) { + String releaseKey = event.getAttachmentValue(NAMESPACE_RELEASE_KEY); + namespaceMetrics.setReleaseKey(releaseKey); + } + + @Override + public void export0() { + namespaces.forEach((namespace, metrics) -> { + // update NamespaceMetrics + createOrUpdateGaugeSample( + METRICS_NAMESPACE_FIRST_LOAD_SPEND, + new String[]{NAMESPACE}, new String[]{namespace}, + metrics.getFirstLoadTimeSpendInMs()); + + createOrUpdateGaugeSample( + METRICS_NAMESPACE_ITEM_NUM, + new String[]{NAMESPACE}, new String[]{namespace}, + configManager.getConfig(namespace).getPropertyNames().size()); + }); + + // update NamespaceStatus metrics + createOrUpdateGaugeSample(METRICS_NAMESPACE_NOT_FOUND, + namespace404.size()); + + createOrUpdateGaugeSample(METRICS_NAMESPACE_TIMEOUT, + namespaceTimeout.size()); + } + + @Override + public Map getNamespaceMetrics() { + return Collections.unmodifiableMap(namespaces); + } + + @Override + public List getNotFoundNamespaces() { + return new ArrayList<>(namespace404); + } + + @Override + public List getTimeoutNamespaces() { + return new ArrayList<>(namespaceTimeout); + } + + @Override + public Map getNamespaceMetricsString() { + Map namespaceMetricsStringMap = Maps.newHashMap(); + namespaces.forEach((namespace, metrics) -> { + NamespaceMetricsString namespaceMetricsString = new NamespaceMetricsString(); + namespaceMetricsString.setFirstLoadTimeSpendInMs(metrics.getFirstLoadTimeSpendInMs()); + namespaceMetricsString.setLatestUpdateTime(metrics.getLatestUpdateTime().toString()); + namespaceMetricsString.setUsageCount(metrics.getUsageCount()); + namespaceMetricsString.setReleaseKey(metrics.getReleaseKey()); + namespaceMetricsStringMap.put(namespace, namespaceMetricsString); + }); + return namespaceMetricsStringMap; + } + + @Override + public Integer getNamespacePropertySize(String namespace) { + Config config = configManager.getConfig(namespace); + return (config != null) ? config.getPropertyNames().size() : 0; + } + +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/DefaultApolloClientThreadPoolApi.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/DefaultApolloClientThreadPoolApi.java new file mode 100644 index 00000000..84316629 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/DefaultApolloClientThreadPoolApi.java @@ -0,0 +1,128 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.listener.impl; + +import static com.ctrip.framework.apollo.monitor.internal.ApolloClientMonitorConstant.*; + +import com.ctrip.framework.apollo.internals.AbstractConfig; +import com.ctrip.framework.apollo.internals.AbstractConfigFile; +import com.ctrip.framework.apollo.internals.RemoteConfigRepository; +import com.ctrip.framework.apollo.monitor.api.ApolloClientThreadPoolMonitorApi; +import com.ctrip.framework.apollo.monitor.internal.exporter.AbstractApolloClientMetricsExporter; +import com.ctrip.framework.apollo.monitor.internal.jmx.mbean.ApolloClientJmxThreadPoolMBean; +import com.ctrip.framework.apollo.monitor.internal.listener.AbstractApolloClientMonitorEventListener; +import com.google.common.collect.Maps; +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ThreadPoolExecutor; + +/** + * @author Rawven + */ +public class DefaultApolloClientThreadPoolApi extends + AbstractApolloClientMonitorEventListener implements + ApolloClientThreadPoolMonitorApi, ApolloClientJmxThreadPoolMBean { + + public static final String REMOTE_CONFIG_REPOSITORY = RemoteConfigRepository.class.getSimpleName(); + public static final String ABSTRACT_CONFIG = AbstractConfig.class.getSimpleName(); + public static final String ABSTRACT_CONFIG_FILE = AbstractConfigFile.class.getSimpleName(); + public static final String METRICS_EXPORTER = AbstractApolloClientMetricsExporter.class.getSimpleName(); + private final Map executorMap = Maps.newHashMap(); + + public DefaultApolloClientThreadPoolApi( + ExecutorService remoteConfigRepositoryExecutorService, + ExecutorService abstractConfigExecutorService, + ExecutorService abstractConfigFileExecutorService, + ExecutorService metricsExporterExecutorService) { + super(TAG_THREAD_POOL); + executorMap.put(REMOTE_CONFIG_REPOSITORY, + new ApolloThreadPoolInfo((ThreadPoolExecutor) remoteConfigRepositoryExecutorService)); + executorMap.put(ABSTRACT_CONFIG, + new ApolloThreadPoolInfo((ThreadPoolExecutor) abstractConfigExecutorService)); + executorMap.put(ABSTRACT_CONFIG_FILE, + new ApolloThreadPoolInfo((ThreadPoolExecutor) abstractConfigFileExecutorService)); + executorMap.put(METRICS_EXPORTER, + new ApolloThreadPoolInfo((ThreadPoolExecutor) metricsExporterExecutorService)); + } + + @Override + public void export0() { + executorMap.forEach((key, value) -> exportThreadPoolMetrics(value, key)); + } + + private void exportThreadPoolMetrics(ApolloThreadPoolInfo info, String threadPoolName) { + + createOrUpdateGaugeSample(METRICS_THREAD_POOL_ACTIVE_TASK_COUNT, + new String[]{METRICS_THREAD_POOL_NAME}, new String[]{threadPoolName}, + info.getActiveTaskCount()); + createOrUpdateGaugeSample(METRICS_THREAD_POOL_QUEUE_SIZE, + new String[]{METRICS_THREAD_POOL_NAME}, new String[]{threadPoolName}, + info.getQueueSize()); + createOrUpdateGaugeSample(METRICS_THREAD_POOL_COMPLETED_TASK_COUNT, + new String[]{METRICS_THREAD_POOL_NAME}, new String[]{threadPoolName}, + (double) info.getCompletedTaskCount()); + createOrUpdateGaugeSample(METRICS_THREAD_POOL_POOL_SIZE, new String[]{METRICS_THREAD_POOL_NAME}, + new String[]{threadPoolName}, info.getPoolSize()); + createOrUpdateGaugeSample(METRICS_THREAD_POOL_TOTAL_TASK_COUNT, + new String[]{METRICS_THREAD_POOL_NAME}, new String[]{threadPoolName}, + (double) info.getTotalTaskCount()); + createOrUpdateGaugeSample(METRICS_THREAD_POOL_CORE_POOL_SIZE, + new String[]{METRICS_THREAD_POOL_NAME}, new String[]{threadPoolName}, + info.getCorePoolSize()); + createOrUpdateGaugeSample(METRICS_THREAD_POOL_MAXIMUM_POOL_SIZE, + new String[]{METRICS_THREAD_POOL_NAME}, new String[]{threadPoolName}, + info.getMaximumPoolSize()); + createOrUpdateGaugeSample(METRICS_THREAD_POOL_LARGEST_POOL_SIZE, + new String[]{METRICS_THREAD_POOL_NAME}, new String[]{threadPoolName}, + info.getLargestPoolSize()); + createOrUpdateGaugeSample(METRICS_THREAD_POOL_QUEUE_REMAINING_CAPACITY, + new String[]{METRICS_THREAD_POOL_NAME}, new String[]{threadPoolName}, + info.getQueueRemainingCapacity()); + } + + + @Override + public boolean isMetricsSampleUpdated() { + // memory status special + return true; + } + + @Override + public Map getThreadPoolInfo() { + return executorMap; + } + + @Override + public ApolloThreadPoolInfo getRemoteConfigRepositoryThreadPoolInfo() { + return executorMap.get(REMOTE_CONFIG_REPOSITORY); + } + + @Override + public ApolloThreadPoolInfo getAbstractConfigThreadPoolInfo() { + return executorMap.get(ABSTRACT_CONFIG); + } + + @Override + public ApolloThreadPoolInfo getAbstractConfigFileThreadPoolInfo() { + return executorMap.get(ABSTRACT_CONFIG_FILE); + } + + @Override + public ApolloThreadPoolInfo getMetricsExporterThreadPoolInfo() { + return executorMap.get(METRICS_EXPORTER); + } +} \ No newline at end of file diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/NullClientBootstrapArgsMonitorApi.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/NullClientBootstrapArgsMonitorApi.java new file mode 100644 index 00000000..88ddd7b8 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/NullClientBootstrapArgsMonitorApi.java @@ -0,0 +1,34 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.listener.impl; + +import com.ctrip.framework.apollo.monitor.api.ApolloClientBootstrapArgsMonitorApi; +import com.ctrip.framework.apollo.monitor.internal.jmx.mbean.ApolloClientJmxBootstrapArgsMBean; +import java.util.Collections; +import java.util.Map; + +/** + * @author Rawven + */ +public class NullClientBootstrapArgsMonitorApi implements ApolloClientBootstrapArgsMonitorApi, + ApolloClientJmxBootstrapArgsMBean { + + @Override + public Map getBootstrapArgsString() { + return Collections.emptyMap(); + } +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/NullClientExceptionMonitorApi.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/NullClientExceptionMonitorApi.java new file mode 100644 index 00000000..5a21f802 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/NullClientExceptionMonitorApi.java @@ -0,0 +1,44 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.listener.impl; + +import com.ctrip.framework.apollo.monitor.api.ApolloClientExceptionMonitorApi; +import com.ctrip.framework.apollo.monitor.internal.jmx.mbean.ApolloClientJmxExceptionMBean; +import java.util.Collections; +import java.util.List; + +/** + * @author Rawven + */ +public class NullClientExceptionMonitorApi implements ApolloClientExceptionMonitorApi, + ApolloClientJmxExceptionMBean { + + @Override + public List getApolloConfigExceptionList() { + return Collections.emptyList(); + } + + @Override + public Integer getExceptionCountFromStartup() { + return 0; + } + + @Override + public List getApolloConfigExceptionDetails() { + return Collections.emptyList(); + } +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/NullClientNamespaceMonitorApi.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/NullClientNamespaceMonitorApi.java new file mode 100644 index 00000000..70a9b2ae --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/NullClientNamespaceMonitorApi.java @@ -0,0 +1,57 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.listener.impl; + +import com.ctrip.framework.apollo.monitor.api.ApolloClientNamespaceMonitorApi; +import com.ctrip.framework.apollo.monitor.internal.jmx.mbean.ApolloClientJmxNamespaceMBean; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * @author Rawven + */ +public class NullClientNamespaceMonitorApi implements ApolloClientNamespaceMonitorApi, + ApolloClientJmxNamespaceMBean { + + @Override + public Map getNamespaceMetrics() { + return Collections.emptyMap(); + } + + + @Override + public List getNotFoundNamespaces() { + return Collections.emptyList(); + } + + @Override + public List getTimeoutNamespaces() { + return Collections.emptyList(); + } + + @Override + public Map getNamespaceMetricsString() { + return Collections.emptyMap(); + } + + @Override + public Integer getNamespacePropertySize(String namespace) { + return 0; + } + +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/NullClientThreadPoolMonitorApi.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/NullClientThreadPoolMonitorApi.java new file mode 100644 index 00000000..03e5c1b5 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/NullClientThreadPoolMonitorApi.java @@ -0,0 +1,56 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.listener.impl; + +import com.ctrip.framework.apollo.monitor.api.ApolloClientThreadPoolMonitorApi; +import com.ctrip.framework.apollo.monitor.internal.jmx.mbean.ApolloClientJmxThreadPoolMBean; +import java.util.Collections; +import java.util.Map; + +/** + * @author Rawven + */ +public class NullClientThreadPoolMonitorApi implements ApolloClientThreadPoolMonitorApi, + ApolloClientJmxThreadPoolMBean { + + private final ApolloThreadPoolInfo NULL_THREAD_POOL_INFO = new ApolloThreadPoolInfo(); + + @Override + public Map getThreadPoolInfo() { + return Collections.emptyMap(); + } + + @Override + public ApolloThreadPoolInfo getRemoteConfigRepositoryThreadPoolInfo() { + return NULL_THREAD_POOL_INFO; + } + + @Override + public ApolloThreadPoolInfo getAbstractConfigThreadPoolInfo() { + return NULL_THREAD_POOL_INFO; + } + + @Override + public ApolloThreadPoolInfo getAbstractConfigFileThreadPoolInfo() { + return NULL_THREAD_POOL_INFO; + } + + @Override + public ApolloThreadPoolInfo getMetricsExporterThreadPoolInfo() { + return NULL_THREAD_POOL_INFO; + } +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/model/CounterModel.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/model/CounterModel.java new file mode 100644 index 00000000..566ce718 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/model/CounterModel.java @@ -0,0 +1,53 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.model; + +import com.ctrip.framework.apollo.monitor.internal.enums.MetricTypeEnums; + +/** + * @author Rawven + */ +public class CounterModel extends SampleModel { + + private CounterModel(String name, double num) { + if (name == null || name.isEmpty()) { + throw new IllegalArgumentException("Name cannot be null or empty"); + } + if (Double.isNaN(num) || Double.isInfinite(num)) { + throw new IllegalArgumentException("Number must be a valid double"); + } + setName(name); + setType(MetricTypeEnums.COUNTER); + this.value.set(num); + } + + public static CounterModel create(String name, double value) { + return new CounterModel(name, value); + } + + public void increase(double value) { + if (Double.isNaN(value) || Double.isInfinite(value)) { + throw new IllegalArgumentException("Value must be a valid double"); + } + this.value.addAndGet(value); + } + + public double getIncreaseValueAndResetZero() { + return value.getAndSet(0.0); + } + +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/model/GaugeModel.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/model/GaugeModel.java new file mode 100644 index 00000000..0abf0699 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/model/GaugeModel.java @@ -0,0 +1,39 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.model; + +import com.ctrip.framework.apollo.monitor.internal.enums.MetricTypeEnums; + +/** + * @author Rawven + */ +public class GaugeModel extends SampleModel { + + private GaugeModel(String name, double value) { + if (name == null || name.isEmpty()) { + throw new IllegalArgumentException("Name cannot be null or empty"); + } + setName(name); + setType(MetricTypeEnums.GAUGE); + this.value.set(value); + } + + public static GaugeModel create(String name, double value) { + return new GaugeModel(name, value); + } + +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/model/SampleModel.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/model/SampleModel.java new file mode 100644 index 00000000..177d7bd3 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/model/SampleModel.java @@ -0,0 +1,73 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.model; + +import com.ctrip.framework.apollo.monitor.internal.enums.MetricTypeEnums; +import com.google.common.util.concurrent.AtomicDouble; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * @author Rawven + */ +public class SampleModel { + + protected final AtomicDouble value = new AtomicDouble(); + private final Map tags = new HashMap<>(1); + private String name; + private MetricTypeEnums type; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public SampleModel putTag(String key, String value) { + tags.put(key, value); + return this; + } + + public SampleModel putTags(Map tags) { + this.tags.putAll(tags); + return this; + } + + public MetricTypeEnums getType() { + return type; + } + + public void setType(MetricTypeEnums type) { + this.type = type; + } + + public Map getTags() { + return Collections.unmodifiableMap(tags); + } + + public double getValue() { + return value.get(); + } + + public void setValue(double value) { + this.value.set(value); + } +} + diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/tracer/ApolloClientMessageProducerComposite.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/tracer/ApolloClientMessageProducerComposite.java new file mode 100644 index 00000000..8ae27a72 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/tracer/ApolloClientMessageProducerComposite.java @@ -0,0 +1,83 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.tracer; + +import com.ctrip.framework.apollo.tracer.internals.NullTransaction; +import com.ctrip.framework.apollo.tracer.spi.MessageProducer; +import com.ctrip.framework.apollo.tracer.spi.Transaction; +import java.util.List; + +/** + * message producer composite + * + * @author Rawven + */ +public class ApolloClientMessageProducerComposite implements MessageProducer { + + public static final NullTransaction NULL_TRANSACTION = new NullTransaction(); + private final List producers; + + public ApolloClientMessageProducerComposite(List producers) { + this.producers = producers; + } + + @Override + public void logError(Throwable cause) { + for (MessageProducer producer : producers) { + producer.logError(cause); + } + } + + @Override + public void logError(String message, Throwable cause) { + for (MessageProducer producer : producers) { + producer.logError(message, cause); + } + } + + @Override + public void logEvent(String type, String name) { + for (MessageProducer producer : producers) { + producer.logEvent(type, name); + } + } + + @Override + public void logEvent(String type, String name, String status, String nameValuePairs) { + for (MessageProducer producer : producers) { + producer.logEvent(type, name, status, nameValuePairs); + } + } + + @Override + public void logMetricsForCount(String name) { + for (MessageProducer producer : producers) { + producer.logMetricsForCount(name); + } + } + + @Override + public Transaction newTransaction(String type, String name) { + for (MessageProducer producer : producers) { + Transaction transaction = producer.newTransaction(type, name); + if (transaction != null) { + return transaction; + } + } + return NULL_TRANSACTION; + } +} \ No newline at end of file diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/tracer/ApolloClientMessageProducerManager.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/tracer/ApolloClientMessageProducerManager.java new file mode 100644 index 00000000..748f2c79 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/tracer/ApolloClientMessageProducerManager.java @@ -0,0 +1,43 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.tracer; + +import com.ctrip.framework.apollo.internals.ConfigMonitorInitializer; +import com.ctrip.framework.apollo.tracer.spi.MessageProducer; +import com.ctrip.framework.apollo.tracer.spi.MessageProducerManager; + +/** + * @author Rawven + */ +public class ApolloClientMessageProducerManager implements MessageProducerManager { + + private static MessageProducer producer; + + public ApolloClientMessageProducerManager() { + producer = ConfigMonitorInitializer.initializeMessageProducerComposite(); + } + + @Override + public MessageProducer getProducer() { + return producer; + } + + @Override + public int getOrder() { + return -1; + } +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/tracer/ApolloClientMonitorMessageProducer.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/tracer/ApolloClientMonitorMessageProducer.java new file mode 100644 index 00000000..b744ce2d --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/tracer/ApolloClientMonitorMessageProducer.java @@ -0,0 +1,200 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.tracer; + +import static com.ctrip.framework.apollo.monitor.internal.ApolloClientMonitorConstant.*; +import static com.ctrip.framework.apollo.monitor.internal.tracer.ApolloClientMessageProducerComposite.NULL_TRANSACTION; + + +import com.ctrip.framework.apollo.exceptions.ApolloConfigException; +import com.ctrip.framework.apollo.monitor.internal.event.ApolloClientMonitorEventFactory; +import com.ctrip.framework.apollo.monitor.internal.event.ApolloClientMonitorEventPublisher; +import com.ctrip.framework.apollo.tracer.spi.MessageProducer; +import com.ctrip.framework.apollo.tracer.spi.Transaction; + +import java.time.LocalDate; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * @author Rawven + */ +public class ApolloClientMonitorMessageProducer implements MessageProducer { + + public static final List TAGS = Collections.unmodifiableList(Arrays.asList( + APOLLO_CLIENT_CONFIGCHANGES, + APOLLO_CONFIG_EXCEPTION, + APOLLO_META_SERVICE, + APOLLO_CONFIG_SERVICES, + APOLLO_CLIENT_VERSION, + APOLLO_CONFIGSERVICE, + APOLLO_CLIENT_CONFIGMETA, + APOLLO_CLIENT_NAMESPACE_TIMEOUT, + APOLLO_CLIENT_NAMESPACE_USAGE, + APOLLO_CLIENT_NAMESPACE_NOT_FOUND + )); + + @Override + public void logError(Throwable cause) { + publishErrorEvent(cause); + } + + @Override + public void logError(String message, Throwable cause) { + publishErrorEvent(cause); + } + + @Override + public void logEvent(String type, String name) { + if (TAGS.contains(type)) { + handleTaggedEvent(type, name); + } else if (type.startsWith(APOLLO_CLIENT_CONFIGS)) { + handleClientConfigEvent(type, name); + } else if (type.startsWith(APOLLO_CLIENT_NAMESPACE_FIRST_LOAD_SPEND)) { + handleFirstLoadTimeEvent(type, name); + } + } + + private void handleTaggedEvent(String type, String name) { + switch (type) { + case APOLLO_CONFIGSERVICE: + name = name.substring(APOLLO_CONFIGSERVICE_HELP_STR.length()); + // fall through + case APOLLO_CLIENT_CONFIGCHANGES: + publishConfigChangeEvent(name); + break; + case APOLLO_CONFIG_EXCEPTION: + logError(new ApolloConfigException(name)); + break; + case APOLLO_META_SERVICE: + publishMetaServiceEvent(); + break; + case APOLLO_CONFIG_SERVICES: + publishConfigServiceEvent(name); + break; + case APOLLO_CLIENT_VERSION: + publishClientVersionEvent(name); + break; + case APOLLO_CLIENT_NAMESPACE_TIMEOUT: + publishNamespaceTimeoutEvent(name); + break; + case APOLLO_CLIENT_NAMESPACE_NOT_FOUND: + publishNamespaceNotFoundEvent(name); + break; + case APOLLO_CLIENT_CONFIGMETA: + // 不需要收集 + break; + default: + break; + } + } + + + private void publishErrorEvent(Throwable cause) { + ApolloClientMonitorEventPublisher.publish( + ApolloClientMonitorEventFactory.getInstance().createEvent(TAG_ERROR) + .withTag(TAG_ERROR) + .putAttachment(THROWABLE, cause)); + } + + private void publishConfigChangeEvent(String name) { + ApolloClientMonitorEventPublisher.publish( + ApolloClientMonitorEventFactory.getInstance() + .createEvent(METRICS_NAMESPACE_LATEST_UPDATE_TIME) + .putAttachment(NAMESPACE, name) + .withTag(TAG_NAMESPACE)); + } + + private void publishMetaServiceEvent() { + ApolloClientMonitorEventPublisher.publish( + ApolloClientMonitorEventFactory.getInstance().createEvent(META_FRESH) + .withTag(TAG_BOOTSTRAP) + .putAttachment(META_FRESH, LocalDate.now().toString())); + } + + private void publishConfigServiceEvent(String name) { + ApolloClientMonitorEventPublisher.publish( + ApolloClientMonitorEventFactory.getInstance().createEvent(CONFIG_SERVICE_URL) + .withTag(TAG_BOOTSTRAP) + .putAttachment(CONFIG_SERVICE_URL, name)); + } + + private void publishClientVersionEvent(String name) { + ApolloClientMonitorEventPublisher.publish( + ApolloClientMonitorEventFactory.getInstance().createEvent(VERSION) + .withTag(TAG_BOOTSTRAP) + .putAttachment(VERSION, name)); + } + + private void publishNamespaceTimeoutEvent(String name) { + ApolloClientMonitorEventPublisher.publish( + ApolloClientMonitorEventFactory.getInstance().createEvent(APOLLO_CLIENT_NAMESPACE_TIMEOUT) + .putAttachment(NAMESPACE, name) + .withTag(TAG_NAMESPACE)); + } + + private void publishNamespaceNotFoundEvent(String name) { + ApolloClientMonitorEventPublisher.publish( + ApolloClientMonitorEventFactory.getInstance().createEvent(APOLLO_CLIENT_NAMESPACE_NOT_FOUND) + .withTag(TAG_NAMESPACE) + .putAttachment(NAMESPACE, name)); + } + + private void handleClientConfigEvent(String type, String name) { + String namespace = type.substring(APOLLO_CLIENT_CONFIGS.length()); + ApolloClientMonitorEventPublisher.publish( + ApolloClientMonitorEventFactory.getInstance().createEvent(NAMESPACE_RELEASE_KEY) + .withTag(TAG_NAMESPACE) + .putAttachment(NAMESPACE_RELEASE_KEY, name) + .putAttachment(NAMESPACE, namespace)); + } + + private void handleFirstLoadTimeEvent(String type, String name) { + String[] split = type.split(":"); + String namespace = split[1]; + long firstLoadTime = Long.parseLong(name); + ApolloClientMonitorEventPublisher.publish( + ApolloClientMonitorEventFactory.getInstance() + .createEvent(APOLLO_CLIENT_NAMESPACE_FIRST_LOAD_SPEND) + .putAttachment(NAMESPACE, namespace) + .putAttachment(TIMESTAMP, firstLoadTime) + .withTag(TAG_NAMESPACE)); + } + + @Override + public void logEvent(String type, String name, String status, String nameValuePairs) { + // ignore + } + + @Override + public void logMetricsForCount(String name) { + String[] split = name.split(":"); + if (split.length == 2 && APOLLO_CLIENT_NAMESPACE_USAGE.equals(split[0])) { + ApolloClientMonitorEventPublisher.publish( + ApolloClientMonitorEventFactory.getInstance() + .createEvent(APOLLO_CLIENT_NAMESPACE_USAGE) + .putAttachment(NAMESPACE, split[1]) + .withTag(TAG_NAMESPACE)); + } + } + + @Override + public Transaction newTransaction(String type, String name) { + return NULL_TRANSACTION; + } +} \ No newline at end of file diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/boot/ApolloApplicationContextInitializer.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/boot/ApolloApplicationContextInitializer.java index 17890055..05decef5 100644 --- a/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/boot/ApolloApplicationContextInitializer.java +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/boot/ApolloApplicationContextInitializer.java @@ -93,7 +93,12 @@ public class ApolloApplicationContextInitializer implements ApolloClientSystemConsts.APOLLO_CONFIG_SERVICE, ApolloClientSystemConsts.APOLLO_PROPERTY_ORDER_ENABLE, ApolloClientSystemConsts.APOLLO_PROPERTY_NAMES_CACHE_ENABLE, - ApolloClientSystemConsts.APOLLO_OVERRIDE_SYSTEM_PROPERTIES}; + ApolloClientSystemConsts.APOLLO_OVERRIDE_SYSTEM_PROPERTIES, + ApolloClientSystemConsts.APOLLO_CLIENT_MONITOR_EXTERNAL_TYPE, + ApolloClientSystemConsts.APOLLO_CLIENT_MONITOR_ENABLED, + ApolloClientSystemConsts.APOLLO_CLIENT_MONITOR_EXTERNAL_EXPORT_PERIOD, + ApolloClientSystemConsts.APOLLO_CLIENT_MONITOR_JMX_ENABLED, + ApolloClientSystemConsts.APOLLO_CLIENT_MONITOR_EXCEPTION_QUEUE_SIZE,}; private final ConfigPropertySourceFactory configPropertySourceFactory = SpringInjector .getInstance(ConfigPropertySourceFactory.class); @@ -132,6 +137,7 @@ protected void initialize(ConfigurableEnvironment environment) { } String namespaces = environment.getProperty(PropertySourcesConstants.APOLLO_BOOTSTRAP_NAMESPACES, ConfigConsts.NAMESPACE_APPLICATION); + System.setProperty(PropertySourcesConstants.APOLLO_BOOTSTRAP_NAMESPACES, namespaces); logger.debug("Apollo bootstrap namespaces: {}", namespaces); List namespaceList = NAMESPACE_SPLITTER.splitToList(namespaces); @@ -197,14 +203,14 @@ public void postProcessEnvironment(ConfigurableEnvironment configurableEnvironme initializeSystemProperty(configurableEnvironment); Boolean eagerLoadEnabled = configurableEnvironment.getProperty(PropertySourcesConstants.APOLLO_BOOTSTRAP_EAGER_LOAD_ENABLED, Boolean.class, false); - + System.setProperty(PropertySourcesConstants.APOLLO_BOOTSTRAP_EAGER_LOAD_ENABLED, String.valueOf(eagerLoadEnabled)); //EnvironmentPostProcessor should not be triggered if you don't want Apollo Loading before Logging System Initialization if (!eagerLoadEnabled) { return; } Boolean bootstrapEnabled = configurableEnvironment.getProperty(PropertySourcesConstants.APOLLO_BOOTSTRAP_ENABLED, Boolean.class, false); - + System.setProperty(PropertySourcesConstants.APOLLO_BOOTSTRAP_ENABLED, String.valueOf(bootstrapEnabled)); if (bootstrapEnabled) { DeferredLogger.enable(); initialize(configurableEnvironment); diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/util/ConfigUtil.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/util/ConfigUtil.java index 9b99a4bf..83a324f0 100644 --- a/apollo-client/src/main/java/com/ctrip/framework/apollo/util/ConfigUtil.java +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/util/ConfigUtil.java @@ -71,6 +71,11 @@ public class ConfigUtil { private boolean propertyNamesCacheEnabled = false; private boolean propertyFileCacheEnabled = true; private boolean overrideSystemProperties = true; + private boolean clientMonitorEnabled = false; + private boolean clientMonitorJmxEnabled = false; + private String monitorExternalType = "NONE"; + private long monitorExternalExportPeriod = 10; + private int monitorExceptionQueueSize = 25; public ConfigUtil() { warnLogRateLimiter = RateLimiter.create(0.017); // 1 warning log output per minute @@ -86,6 +91,11 @@ public ConfigUtil() { initPropertyNamesCacheEnabled(); initPropertyFileCacheEnabled(); initOverrideSystemProperties(); + initClientMonitorEnabled(); + initClientMonitorJmxEnabled(); + initClientMonitorExternalType(); + initClientMonitorExternalExportPeriod(); + initClientMonitorExceptionQueueSize(); } /** @@ -490,7 +500,75 @@ private void initOverrideSystemProperties() { ApolloClientSystemConsts.APOLLO_OVERRIDE_SYSTEM_PROPERTIES, overrideSystemProperties); } + + + private void initClientMonitorExternalType() { + monitorExternalType = System.getProperty(ApolloClientSystemConsts.APOLLO_CLIENT_MONITOR_EXTERNAL_TYPE); + if (Strings.isNullOrEmpty(monitorExternalType)) { + monitorExternalType = Foundation.app() + .getProperty(ApolloClientSystemConsts.APOLLO_CLIENT_MONITOR_EXTERNAL_TYPE, "NONE"); + } + } + + public String getMonitorExternalType() { + return monitorExternalType; + } + + private void initClientMonitorExternalExportPeriod() { + Integer value = getCustomizedIntegerValue(ApolloClientSystemConsts.APOLLO_CLIENT_MONITOR_EXTERNAL_EXPORT_PERIOD); + + if (value != null) { + if (value <= 0) { + logger.warn("Config for {} is invalid: {}, remain default value: 10", + ApolloClientSystemConsts.APOLLO_CLIENT_MONITOR_EXTERNAL_EXPORT_PERIOD, value); + } else { + monitorExternalExportPeriod = value; + } + } + } + + public long getMonitorExternalExportPeriod() { + return monitorExternalExportPeriod; + } + + private void initClientMonitorEnabled() { + clientMonitorEnabled = getPropertyBoolean(ApolloClientSystemConsts.APOLLO_CLIENT_MONITOR_ENABLED, + ApolloClientSystemConsts.APOLLO_CLIENT_MONITOR_ENABLED, + clientMonitorEnabled); + } + + public boolean isClientMonitorEnabled() { + return clientMonitorEnabled; + } + + private void initClientMonitorJmxEnabled() { + clientMonitorJmxEnabled = getPropertyBoolean(ApolloClientSystemConsts.APOLLO_CLIENT_MONITOR_JMX_ENABLED, + ApolloClientSystemConsts.APOLLO_CLIENT_MONITOR_JMX_ENABLED, + clientMonitorJmxEnabled); + } + + public boolean isClientMonitorJmxEnabled() { + return clientMonitorJmxEnabled; + } + + private void initClientMonitorExceptionQueueSize() { + Integer value = getCustomizedIntegerValue(ApolloClientSystemConsts.APOLLO_CLIENT_MONITOR_EXCEPTION_QUEUE_SIZE); + + if (value != null) { + if (value <= 0) { + logger.warn("Config for {} is invalid: {}, remain default value: 25", + ApolloClientSystemConsts.APOLLO_CLIENT_MONITOR_EXCEPTION_QUEUE_SIZE, value); + } else { + monitorExceptionQueueSize = value; + } + } + } + + public int getMonitorExceptionQueueSize() { + return monitorExceptionQueueSize; + } + private boolean getPropertyBoolean(String propertyName, String envName, boolean defaultVal) { String enablePropertyNamesCache = System.getProperty(propertyName); if (Strings.isNullOrEmpty(enablePropertyNamesCache)) { @@ -509,4 +587,4 @@ private boolean getPropertyBoolean(String propertyName, String envName, boolean } return defaultVal; } -} +} \ No newline at end of file diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/util/ExceptionUtil.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/util/ExceptionUtil.java index 28df3f5f..875246a1 100644 --- a/apollo-client/src/main/java/com/ctrip/framework/apollo/util/ExceptionUtil.java +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/util/ExceptionUtil.java @@ -64,4 +64,4 @@ public static String getDetailMessage(Throwable ex) { return builder.toString(); } -} +} \ No newline at end of file diff --git a/apollo-client/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/apollo-client/src/main/resources/META-INF/additional-spring-configuration-metadata.json index a14b1d03..0bb9b644 100644 --- a/apollo-client/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/apollo-client/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -63,6 +63,42 @@ "description": "apollo config service address. if it's configured apollo client will not refresh config services from remote meta service.", "defaultValue": "" }, + { + "name": "apollo.client.monitor.enabled", + "type": "java.lang.Boolean", + "sourceType": "com.ctrip.framework.apollo.core.ApolloClientSystemConsts", + "description": "apollo client monitor enabled.", + "defaultValue": false + }, + { + "name": "apollo.client.monitor.jmx.enabled", + "type": "java.lang.Boolean", + "sourceType": "com.ctrip.framework.apollo.core.ApolloClientSystemConsts", + "description": "apollo client monitor jmx enabled.", + "defaultValue": false + }, + { + "name": "apollo.client.monitor.external.type", + "type": "java.lang.String", + "sourceType": "com.ctrip.framework.apollo.core.ApolloClientSystemConsts", + "description": "apollo client monitor external monitoring system type.", + "defaultValue": "" + }, + + { + "name": "apollo.client.monitor.external.export-period", + "type": "java.lang.String", + "sourceType": "com.ctrip.framework.apollo.core.ApolloClientSystemConsts", + "description": "apollo client monitor external metrics export period.", + "defaultValue": "" + }, + { + "name": "apollo.client.monitor.exception-queue-size", + "type": "java.lang.String", + "sourceType": "com.ctrip.framework.apollo.core.ApolloClientSystemConsts", + "description": "apollo client monitor exception-queue-size.", + "defaultValue": "" + }, { "name": "apollo.meta", "type": "java.net.URI", diff --git a/apollo-client/src/main/resources/META-INF/services/com.ctrip.framework.apollo.tracer.spi.MessageProducerManager b/apollo-client/src/main/resources/META-INF/services/com.ctrip.framework.apollo.tracer.spi.MessageProducerManager new file mode 100644 index 00000000..7b56522b --- /dev/null +++ b/apollo-client/src/main/resources/META-INF/services/com.ctrip.framework.apollo.tracer.spi.MessageProducerManager @@ -0,0 +1 @@ +com.ctrip.framework.apollo.monitor.internal.tracer.ApolloClientMessageProducerManager \ No newline at end of file diff --git a/apollo-client/src/test/java/com/ctrip/framework/apollo/internals/ConfigMonitorInitializerTest.java b/apollo-client/src/test/java/com/ctrip/framework/apollo/internals/ConfigMonitorInitializerTest.java new file mode 100644 index 00000000..25be1005 --- /dev/null +++ b/apollo-client/src/test/java/com/ctrip/framework/apollo/internals/ConfigMonitorInitializerTest.java @@ -0,0 +1,86 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.internals; + +import com.ctrip.framework.apollo.build.MockInjector; +import com.ctrip.framework.apollo.monitor.internal.ApolloClientMonitorContext; +import com.ctrip.framework.apollo.monitor.internal.exporter.ApolloClientMetricsExporterFactory; +import com.ctrip.framework.apollo.util.ConfigUtil; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class ConfigMonitorInitializerTest { + + @Mock + private ConfigUtil mockConfigUtil; + @Mock + private ApolloClientMonitorContext mockMonitorContext; + @Mock + private ApolloClientMetricsExporterFactory mockExporterFactory; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + MockInjector.setInstance(ConfigUtil.class, mockConfigUtil); + MockInjector.setInstance(ApolloClientMonitorContext.class, mockMonitorContext); + MockInjector.setInstance(ApolloClientMetricsExporterFactory.class, mockExporterFactory); + resetConfigMonitorInitializer(); + } + + @Test + public void testInitializeWhenMonitorEnabledAndNotInitialized() { + when(mockConfigUtil.isClientMonitorEnabled()).thenReturn(true); + ConfigMonitorInitializer.initialize(); + assertTrue(ConfigMonitorInitializer.hasInitialized); + //ConfigMonitorInitializer.53line + DefaultApolloClientBootstrapArgsApi.64line + verify(mockConfigUtil, times(2)).isClientMonitorEnabled(); + } + + @Test + public void testInitializeWhenMonitorDisabled() { + when(mockConfigUtil.isClientMonitorEnabled()).thenReturn(false); + ConfigMonitorInitializer.initialize(); + assertFalse(ConfigMonitorInitializer.hasInitialized); + } + + @Test + public void testInitializeWhenAlreadyInitialized() { + when(mockConfigUtil.isClientMonitorEnabled()).thenReturn(true); + ConfigMonitorInitializer.hasInitialized = true; + ConfigMonitorInitializer.initialize(); + verify(mockConfigUtil, times(1)).isClientMonitorEnabled(); + } + + @Test + public void testReset() { + ConfigMonitorInitializer.reset(); + assertFalse(ConfigMonitorInitializer.hasInitialized); + } + + private void resetConfigMonitorInitializer() { + ConfigMonitorInitializer.reset(); + } + +} diff --git a/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/ApolloClientMonitorContextTest.java b/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/ApolloClientMonitorContextTest.java new file mode 100644 index 00000000..00d9145a --- /dev/null +++ b/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/ApolloClientMonitorContextTest.java @@ -0,0 +1,95 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal; +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import com.ctrip.framework.apollo.monitor.internal.exporter.ApolloClientMetricsExporter; +import com.ctrip.framework.apollo.monitor.internal.exporter.impl.NullApolloClientMetricsExporter; +import com.ctrip.framework.apollo.monitor.internal.listener.ApolloClientMonitorEventListener; +import com.ctrip.framework.apollo.monitor.internal.listener.impl.DefaultApolloClientBootstrapArgsApi; +import com.ctrip.framework.apollo.monitor.internal.listener.impl.DefaultApolloClientExceptionApi; +import com.ctrip.framework.apollo.monitor.internal.listener.impl.DefaultApolloClientNamespaceApi; +import com.ctrip.framework.apollo.monitor.internal.listener.impl.DefaultApolloClientThreadPoolApi; +import com.ctrip.framework.apollo.monitor.internal.listener.impl.NullClientBootstrapArgsMonitorApi; +import com.ctrip.framework.apollo.monitor.internal.listener.impl.NullClientExceptionMonitorApi; +import com.ctrip.framework.apollo.monitor.internal.listener.impl.NullClientNamespaceMonitorApi; +import com.ctrip.framework.apollo.monitor.internal.listener.impl.NullClientThreadPoolMonitorApi; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +import java.util.List; + +public class ApolloClientMonitorContextTest { + + @Mock + private DefaultApolloClientExceptionApi exceptionMonitorApi; + @Mock + private DefaultApolloClientNamespaceApi namespaceMonitorApi; + @Mock + private DefaultApolloClientBootstrapArgsApi bootstrapArgsMonitorApi; + @Mock + private DefaultApolloClientThreadPoolApi threadPoolMonitorApi; + @Mock + private ApolloClientMetricsExporter metricsExporter; + + private ApolloClientMonitorContext monitorContext; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + monitorContext = new ApolloClientMonitorContext(); + } + + @Test + public void testInitContext(){ + assertTrue(monitorContext.getBootstrapArgsApi() instanceof NullClientBootstrapArgsMonitorApi); + assertTrue(monitorContext.getNamespaceApi() instanceof NullClientNamespaceMonitorApi); + assertTrue(monitorContext.getThreadPoolApi() instanceof NullClientThreadPoolMonitorApi); + assertTrue(monitorContext.getExceptionApi() instanceof NullClientExceptionMonitorApi); + assertTrue(monitorContext.getMetricsExporter() instanceof NullApolloClientMetricsExporter); + } + + @Test + public void testSettingAndGettingApis() { + monitorContext.setApolloClientExceptionMonitorApi(exceptionMonitorApi); + monitorContext.setApolloClientNamespaceMonitorApi(namespaceMonitorApi); + monitorContext.setApolloClientBootstrapArgsMonitorApi(bootstrapArgsMonitorApi); + monitorContext.setApolloClientThreadPoolMonitorApi(threadPoolMonitorApi); + monitorContext.setApolloClientMetricsExporter(metricsExporter); + + assertSame(exceptionMonitorApi, monitorContext.getExceptionApi()); + assertSame(namespaceMonitorApi, monitorContext.getNamespaceApi()); + assertSame(bootstrapArgsMonitorApi, monitorContext.getBootstrapArgsApi()); + assertSame(threadPoolMonitorApi, monitorContext.getThreadPoolApi()); + assertSame(metricsExporter, monitorContext.getMetricsExporter()); + } + + @Test + public void testGetCollectors() { + ApolloClientMonitorEventListener listener = Mockito.mock(ApolloClientMonitorEventListener.class); + ApolloClientMonitorEventListener listener2 = Mockito.mock(ApolloClientMonitorEventListener.class); + monitorContext.addApolloClientMonitorEventListener(listener); + monitorContext.addApolloClientMonitorEventListener(listener2); + + List listeners = monitorContext.getApolloClientMonitorEventListeners(); + assertEquals(2, listeners.size()); + } +} diff --git a/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/DefaultConfigMonitorTest.java b/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/DefaultConfigMonitorTest.java new file mode 100644 index 00000000..2f1ffc6c --- /dev/null +++ b/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/DefaultConfigMonitorTest.java @@ -0,0 +1,79 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal; +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import com.ctrip.framework.apollo.build.ApolloInjector; +import com.ctrip.framework.apollo.build.MockInjector; +import com.ctrip.framework.apollo.monitor.api.ApolloClientBootstrapArgsMonitorApi; +import com.ctrip.framework.apollo.monitor.api.ApolloClientExceptionMonitorApi; +import com.ctrip.framework.apollo.monitor.api.ApolloClientNamespaceMonitorApi; +import com.ctrip.framework.apollo.monitor.api.ApolloClientThreadPoolMonitorApi; +import com.ctrip.framework.apollo.monitor.internal.exporter.ApolloClientMetricsExporter; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +public class DefaultConfigMonitorTest { + + @Mock + private ApolloClientExceptionMonitorApi exceptionMonitorApi; + @Mock + private ApolloClientNamespaceMonitorApi namespaceMonitorApi; + @Mock + private ApolloClientBootstrapArgsMonitorApi bootstrapArgsMonitorApi; + @Mock + private ApolloClientThreadPoolMonitorApi threadPoolMonitorApi; + @Mock + private ApolloClientMetricsExporter metricsExporter; + @Mock + private ApolloClientMonitorContext monitorContext; + + private DefaultConfigMonitor configMonitor; + + @Before + public void setUp(){ + MockitoAnnotations.initMocks(this); + when(monitorContext.getExceptionApi()).thenReturn(exceptionMonitorApi); + when(monitorContext.getNamespaceApi()).thenReturn(namespaceMonitorApi); + when(monitorContext.getBootstrapArgsApi()).thenReturn(bootstrapArgsMonitorApi); + when(monitorContext.getThreadPoolApi()).thenReturn(threadPoolMonitorApi); + when(monitorContext.getMetricsExporter()).thenReturn(metricsExporter); + MockInjector.setInstance(ApolloClientMonitorContext.class, monitorContext); + + configMonitor = new DefaultConfigMonitor(); + + } + + @Test + public void testApis(){ + assertSame(exceptionMonitorApi, configMonitor.getExceptionMonitorApi()); + assertSame(namespaceMonitorApi, configMonitor.getNamespaceMonitorApi()); + assertSame(bootstrapArgsMonitorApi, configMonitor.getRunningParamsMonitorApi()); + assertSame(threadPoolMonitorApi, configMonitor.getThreadPoolMonitorApi()); + } + + @Test + public void testExporterData(){ + String data = "data"; + when(metricsExporter.response()).thenReturn(data); + + assertEquals(data, configMonitor.getExporterData()); + } +} diff --git a/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/event/ApolloClientMonitorEventFactoryTest.java b/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/event/ApolloClientMonitorEventFactoryTest.java new file mode 100644 index 00000000..876ad176 --- /dev/null +++ b/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/event/ApolloClientMonitorEventFactoryTest.java @@ -0,0 +1,53 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.event; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import org.junit.Before; +import org.junit.Test; + +public class ApolloClientMonitorEventFactoryTest { + + private ApolloClientMonitorEventFactory factory; + + @Before + public void setUp() { + factory = ApolloClientMonitorEventFactory.getInstance(); + } + + @Test + public void testGetInstance() { + ApolloClientMonitorEventFactory instance1 = ApolloClientMonitorEventFactory.getInstance(); + ApolloClientMonitorEventFactory instance2 = ApolloClientMonitorEventFactory.getInstance(); + + assertNotNull(instance1); + assertNotNull(instance2); + // 验证两个实例是同一个 + assertSame(instance1, instance2); + } + + @Test + public void testCreateEvent() { + String eventName = "TestEvent"; + ApolloClientMonitorEvent event = factory.createEvent(eventName); + + assertNotNull(event); + assertEquals(eventName, event.getName()); + } +} diff --git a/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/event/ApolloClientMonitorEventPublisherTest.java b/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/event/ApolloClientMonitorEventPublisherTest.java new file mode 100644 index 00000000..04241217 --- /dev/null +++ b/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/event/ApolloClientMonitorEventPublisherTest.java @@ -0,0 +1,81 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.event; + +import static org.mockito.Mockito.*; + +import com.ctrip.framework.apollo.build.MockInjector; +import com.ctrip.framework.apollo.monitor.internal.listener.ApolloClientMonitorEventListener; +import com.ctrip.framework.apollo.monitor.internal.ApolloClientMonitorContext; +import com.ctrip.framework.apollo.util.ConfigUtil; +import org.junit.Before; +import org.junit.Test; + +import java.util.Collections; + +public class ApolloClientMonitorEventPublisherTest { + + private ApolloClientMonitorContext mockCollectorManager; + private ConfigUtil mockConfigUtil; + private ApolloClientMonitorEventListener mockListener; + private ApolloClientMonitorEvent mockEvent; + + @Before + public void setUp() { + mockCollectorManager = mock(ApolloClientMonitorContext.class); + mockConfigUtil = mock(ConfigUtil.class); + mockListener = mock(ApolloClientMonitorEventListener.class); + mockEvent = mock(ApolloClientMonitorEvent.class); + + // 使用 Mockito 来模拟静态方法 + MockInjector.setInstance(ApolloClientMonitorContext.class, mockCollectorManager); + MockInjector.setInstance(ConfigUtil.class, mockConfigUtil); + ApolloClientMonitorEventPublisher.reset(); + } + + @Test + public void testPublish_WhenClientMonitorEnabled_CollectorSupportsEvent() { + when(mockConfigUtil.isClientMonitorEnabled()).thenReturn(true); + when(mockCollectorManager.getApolloClientMonitorEventListeners()).thenReturn(Collections.singletonList( + mockListener)); + when(mockListener.isSupported(mockEvent)).thenReturn(true); + + ApolloClientMonitorEventPublisher.publish(mockEvent); + + verify(mockListener).collect(mockEvent); + } + + @Test + public void testPublish_WhenClientMonitorEnabled_CollectorDoesNotSupportEvent() { + when(mockConfigUtil.isClientMonitorEnabled()).thenReturn(true); + when(mockCollectorManager.getApolloClientMonitorEventListeners()).thenReturn(Collections.singletonList(mockListener)); + when(mockListener.isSupported(mockEvent)).thenReturn(false); + + ApolloClientMonitorEventPublisher.publish(mockEvent); + + verify(mockListener, never()).collect(mockEvent); + } + + @Test + public void testPublish_WhenClientMonitorDisabled() { + when(mockConfigUtil.isClientMonitorEnabled()).thenReturn(false); + + ApolloClientMonitorEventPublisher.publish(mockEvent); + + verify(mockCollectorManager, never()).getApolloClientMonitorEventListeners(); + } +} diff --git a/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/exporter/AbstractApolloClientMetricsExporterTest.java b/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/exporter/AbstractApolloClientMetricsExporterTest.java new file mode 100644 index 00000000..8c1454f8 --- /dev/null +++ b/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/exporter/AbstractApolloClientMetricsExporterTest.java @@ -0,0 +1,122 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.exporter; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import com.ctrip.framework.apollo.monitor.internal.enums.MetricTypeEnums; +import com.ctrip.framework.apollo.monitor.internal.listener.ApolloClientMonitorEventListener; +import com.ctrip.framework.apollo.monitor.internal.model.CounterModel; +import com.ctrip.framework.apollo.monitor.internal.model.GaugeModel; +import com.ctrip.framework.apollo.monitor.internal.model.SampleModel; +import java.util.Collections; +import java.util.Map; +import org.junit.Before; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +public class AbstractApolloClientMetricsExporterTest { + + private TestMetricsExporter exporter; + private ApolloClientMonitorEventListener mockListener; + + @Before + public void setUp() { + exporter = new TestMetricsExporter(); + mockListener = mock(ApolloClientMonitorEventListener.class); + } + + @Test + public void testInit() { + List collectors = new ArrayList<>(); + collectors.add(mockListener); + long collectPeriod = 10L; + + exporter.init(collectors, collectPeriod); + + assertEquals(collectors, exporter.getCollectors()); + } + + @Test + public void testUpdateMetricsData() { + List samples = new ArrayList<>(); + GaugeModel gauge = mock(GaugeModel.class); + when(gauge.getType()).thenReturn(MetricTypeEnums.GAUGE); + when(gauge.getName()).thenReturn("testGauge"); + when(gauge.getValue()).thenReturn(10.0); + samples.add(gauge); + + when(mockListener.isMetricsSampleUpdated()).thenReturn(true); + when(mockListener.export()).thenReturn(samples); + + exporter.init(Collections.singletonList(mockListener), 10L); + exporter.updateMetricsData(); + + verify(mockListener).export(); + verify(gauge).getValue(); + } + + @Test + public void testRegisterSampleGauge() { + GaugeModel gaugeModel = (GaugeModel) GaugeModel.create("testGauge", 5.0).putTag("key", "value"); + + exporter.registerSample(gaugeModel); + } + + @Test + public void testRegisterSampleCounter() { + CounterModel counterModel = (CounterModel) CounterModel.create("testCounter", 5.0) + .putTag("key", "value"); + exporter.registerSample(counterModel); + } + + private class TestMetricsExporter extends AbstractApolloClientMetricsExporter { + + @Override + protected void doInit() { + } + + public List getCollectors() { + return listeners; + } + + @Override + public boolean isSupport(String form) { + return false; + } + + @Override + public void registerOrUpdateCounterSample(String name, Map tag, + double incrValue) { + + } + + @Override + public void registerOrUpdateGaugeSample(String name, Map tag, double value) { + + } + + @Override + public String response() { + return ""; + } + } + +} \ No newline at end of file diff --git a/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/exporter/DefaultApolloClientMetricsExporterFactoryTest.java b/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/exporter/DefaultApolloClientMetricsExporterFactoryTest.java new file mode 100644 index 00000000..bce2079d --- /dev/null +++ b/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/exporter/DefaultApolloClientMetricsExporterFactoryTest.java @@ -0,0 +1,84 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.exporter; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import com.ctrip.framework.apollo.build.MockInjector; +import com.ctrip.framework.apollo.monitor.internal.exporter.impl.DefaultApolloClientMetricsExporterFactory; +import com.ctrip.framework.apollo.monitor.internal.listener.ApolloClientMonitorEventListener; +import com.ctrip.framework.apollo.util.ConfigUtil; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.Collections; +import java.util.List; + +public class DefaultApolloClientMetricsExporterFactoryTest { + + private DefaultApolloClientMetricsExporterFactory factory; + + @Mock + private ConfigUtil configUtil; + + @Mock + private ApolloClientMonitorEventListener monitorEventListener; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + MockInjector.setInstance(ConfigUtil.class, configUtil); + factory = new DefaultApolloClientMetricsExporterFactory(); + } + + @Test + public void testGetMetricsReporter_NoExternalSystemType() { + when(configUtil.getMonitorExternalType()).thenReturn(null); + + ApolloClientMetricsExporter result = factory.getMetricsReporter(Collections.emptyList()); + + assertNull(result); + verify(configUtil).getMonitorExternalType(); + } + + @Test + public void testGetMetricsReporter_ExporterFound() { + when(configUtil.getMonitorExternalType()).thenReturn("mocktheus"); + when(configUtil.isClientMonitorJmxEnabled()).thenReturn(true); + when(configUtil.getMonitorExternalExportPeriod()).thenReturn(1000L); + when(monitorEventListener.getName()).thenReturn("testMBean"); + List collectors = Collections.singletonList(monitorEventListener); + + ApolloClientMetricsExporter result = factory.getMetricsReporter(collectors); + + assertNotNull(result); + assertTrue(result instanceof MockApolloClientMetricsExporter); + } + + @Test + public void testGetMetricsReporter_ExporterNotFound() { + when(configUtil.getMonitorExternalType()).thenReturn("unknownType"); + + ApolloClientMetricsExporter result = factory.getMetricsReporter(Collections.emptyList()); + + assertNull(result); + verify(configUtil).getMonitorExternalType(); + } +} \ No newline at end of file diff --git a/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/exporter/MockApolloClientMetricsExporter.java b/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/exporter/MockApolloClientMetricsExporter.java new file mode 100644 index 00000000..894af2dc --- /dev/null +++ b/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/exporter/MockApolloClientMetricsExporter.java @@ -0,0 +1,48 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.exporter; + +import java.util.Map; + +public class MockApolloClientMetricsExporter extends AbstractApolloClientMetricsExporter { + + @Override + protected void doInit() { + + } + + @Override + public boolean isSupport(String form) { + return "mocktheus".equals(form); + } + + @Override + public void registerOrUpdateCounterSample(String name, Map tag, + double incrValue) { + + } + + @Override + public void registerOrUpdateGaugeSample(String name, Map tag, double value) { + + } + + @Override + public String response() { + return ""; + } +} diff --git a/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/jmx/ApolloClientJmxMBeanRegisterTest.java b/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/jmx/ApolloClientJmxMBeanRegisterTest.java new file mode 100644 index 00000000..a3fec5de --- /dev/null +++ b/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/jmx/ApolloClientJmxMBeanRegisterTest.java @@ -0,0 +1,66 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.jmx; + +import static org.mockito.Mockito.*; +import static org.junit.Assert.*; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.MockitoAnnotations; + +import javax.management.MBeanServer; +import javax.management.ObjectName; + +public class ApolloClientJmxMBeanRegisterTest { + + private MBeanServer mockMBeanServer; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mockMBeanServer = mock(MBeanServer.class); + ApolloClientJmxMBeanRegister.setMBeanServer(mockMBeanServer); + } + + @Test + public void testRegister_MBeanNotRegistered() throws Exception { + String name = "com.example:type=TestMBean"; + Object mbean = new Object(); + + when(mockMBeanServer.isRegistered(any(ObjectName.class))).thenReturn(false); + ObjectName objectName = ApolloClientJmxMBeanRegister.register(name, mbean); + + assertNotNull(objectName); + verify(mockMBeanServer).registerMBean(mbean, objectName); + } + + @Test + public void testRegister_MBeanAlreadyRegistered() throws Exception { + String name = "com.example:type=TestMBean"; + Object mbean = new Object(); + + ObjectName objectName = new ObjectName(name); + when(mockMBeanServer.isRegistered(objectName)).thenReturn(true); + + ApolloClientJmxMBeanRegister.register(name, mbean); + + verify(mockMBeanServer).unregisterMBean(objectName); + verify(mockMBeanServer).registerMBean(mbean, objectName); + } + +} diff --git a/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/DefaultApolloClientBootstrapArgsApiTest.java b/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/DefaultApolloClientBootstrapArgsApiTest.java new file mode 100644 index 00000000..c37699e1 --- /dev/null +++ b/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/DefaultApolloClientBootstrapArgsApiTest.java @@ -0,0 +1,90 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.listener.impl; + +import static com.ctrip.framework.apollo.core.ApolloClientSystemConsts.*; +import static org.mockito.Mockito.*; +import static org.junit.Assert.*; + +import com.ctrip.framework.apollo.core.enums.Env; +import com.ctrip.framework.apollo.util.ConfigUtil; +import com.ctrip.framework.apollo.monitor.internal.event.ApolloClientMonitorEvent; +import org.junit.Before; +import org.junit.Test; + +import java.util.Map; + +public class DefaultApolloClientBootstrapArgsApiTest { + + private ConfigUtil configUtil; + private DefaultApolloClientBootstrapArgsApi api; + + @Before + public void setUp() { + configUtil = mock(ConfigUtil.class); + when(configUtil.getAccessKeySecret()).thenReturn("secret"); + when(configUtil.isAutoUpdateInjectedSpringPropertiesEnabled()).thenReturn(true); + when(configUtil.isOverrideSystemProperties()).thenReturn(false); + when(configUtil.getDefaultLocalCacheDir()).thenReturn("/cache"); + when(configUtil.getCluster()).thenReturn("default"); + when(configUtil.getAppId()).thenReturn("myApp"); + when(configUtil.getApolloEnv()).thenReturn(Env.DEV); + when(configUtil.getMetaServerDomainName()).thenReturn("http://meta.server"); + + api = new DefaultApolloClientBootstrapArgsApi(configUtil); + } + + @Test + public void testGetAccessKeySecret() { + assertEquals("secret", api.getAccessKeySecret()); + } + + @Test + public void testGetAutoUpdateInjectedSpringProperties() { + assertTrue(api.getAutoUpdateInjectedSpringProperties()); + } + + @Test + public void testGetCacheDir() { + assertEquals("/cache", api.getCacheDir()); + } + + @Test + public void testCollect0() { + ApolloClientMonitorEvent event = mock(ApolloClientMonitorEvent.class); + when(event.getName()).thenReturn(APOLLO_ACCESS_KEY_SECRET); + when(event.getAttachmentValue(APOLLO_ACCESS_KEY_SECRET)).thenReturn("newSecret"); + + api.collect0(event); + + assertEquals("newSecret", api.getAccessKeySecret()); + } + + @Test + public void testUnhandledEvent() { + ApolloClientMonitorEvent event = mock(ApolloClientMonitorEvent.class); + when(event.getName()).thenReturn("unknownEvent"); + api.collect0(event); + } + + @Test + public void testGetBootstrapArgs() { + Map bootstrapArgs = api.getBootstrapArgs(); + assertNotNull(bootstrapArgs); + assertTrue(bootstrapArgs.containsKey(APOLLO_ACCESS_KEY_SECRET)); + } +} \ No newline at end of file diff --git a/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/DefaultApolloClientExceptionApiTest.java b/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/DefaultApolloClientExceptionApiTest.java new file mode 100644 index 00000000..1dc115c7 --- /dev/null +++ b/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/DefaultApolloClientExceptionApiTest.java @@ -0,0 +1,109 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.listener.impl; + +import static com.ctrip.framework.apollo.monitor.internal.ApolloClientMonitorConstant.THROWABLE; +import static org.mockito.Mockito.*; +import static org.junit.Assert.*; + +import com.ctrip.framework.apollo.core.ApolloClientSystemConsts; +import com.ctrip.framework.apollo.monitor.internal.event.ApolloClientMonitorEvent; +import com.ctrip.framework.apollo.exceptions.ApolloConfigException; +import com.ctrip.framework.apollo.util.ConfigUtil; +import org.junit.Before; +import org.junit.Test; + +import java.util.List; + +public class DefaultApolloClientExceptionApiTest { + + private DefaultApolloClientExceptionApi exceptionApi; + + @Before + public void setUp() { + int someQueueSize = 10; + ConfigUtil configUtil = mock(ConfigUtil.class); + when(configUtil.getMonitorExceptionQueueSize()).thenReturn(someQueueSize); + System.setProperty(ApolloClientSystemConsts.APOLLO_CLIENT_MONITOR_EXCEPTION_QUEUE_SIZE, String.valueOf(someQueueSize)); + exceptionApi = new DefaultApolloClientExceptionApi(configUtil); + } + + @Test + public void testCollect0_AddsException() { + ApolloConfigException exception = new ApolloConfigException("Test Exception"); + ApolloClientMonitorEvent event = mock(ApolloClientMonitorEvent.class); + when(event.getAttachmentValue(THROWABLE)).thenReturn(exception); + + exceptionApi.collect0(event); + + List exceptions = exceptionApi.getApolloConfigExceptionList(); + assertEquals(1, exceptions.size()); + assertEquals(exception, exceptions.get(0)); + } + + @Test + public void testCollect0_IncrementsExceptionCount() { + ApolloConfigException exception = new ApolloConfigException("Test Exception"); + ApolloClientMonitorEvent event = mock(ApolloClientMonitorEvent.class); + when(event.getAttachmentValue(THROWABLE)).thenReturn(exception); + + exceptionApi.collect0(event); + exceptionApi.collect0(event); + + assertEquals(2, exceptionApi.getApolloConfigExceptionList().size()); + } + + @Test + public void testGetApolloConfigExceptionDetails() { + ApolloConfigException exception1 = new ApolloConfigException("First Exception"); + ApolloConfigException exception2 = new ApolloConfigException("Second Exception"); + + ApolloClientMonitorEvent event1 = mock(ApolloClientMonitorEvent.class); + ApolloClientMonitorEvent event2 = mock(ApolloClientMonitorEvent.class); + + when(event1.getAttachmentValue(THROWABLE)).thenReturn(exception1); + when(event2.getAttachmentValue(THROWABLE)).thenReturn(exception2); + + exceptionApi.collect0(event1); + exceptionApi.collect0(event2); + + List details = exceptionApi.getApolloConfigExceptionDetails(); + assertEquals(2, details.size()); + assertTrue(details.contains("First Exception")); + assertTrue(details.contains("Second Exception")); + } + + @Test + public void testCollect0_HandlesMaxQueueSize() { + for (int i = 0; i < 10; i++) { + ApolloClientMonitorEvent event = mock(ApolloClientMonitorEvent.class); + when(event.getAttachmentValue(THROWABLE)).thenReturn( + new ApolloConfigException("Exception " + i)); + exceptionApi.collect0(event); + } + + assertEquals(10, exceptionApi.getApolloConfigExceptionList().size()); + + // Add one more to exceed the size. + ApolloClientMonitorEvent overflowEvent = mock(ApolloClientMonitorEvent.class); + when(overflowEvent.getAttachmentValue(THROWABLE)).thenReturn( + new ApolloConfigException("Overflow Exception")); + exceptionApi.collect0(overflowEvent); + + assertEquals(10, exceptionApi.getApolloConfigExceptionList().size()); + } +} \ No newline at end of file diff --git a/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/DefaultApolloClientNamespaceApiTest.java b/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/DefaultApolloClientNamespaceApiTest.java new file mode 100644 index 00000000..e94b097f --- /dev/null +++ b/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/DefaultApolloClientNamespaceApiTest.java @@ -0,0 +1,110 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.listener.impl; + +import com.ctrip.framework.apollo.Config; +import com.ctrip.framework.apollo.internals.ConfigManager; +import com.ctrip.framework.apollo.monitor.internal.event.ApolloClientMonitorEvent; +import com.ctrip.framework.apollo.monitor.internal.event.ApolloClientMonitorEventFactory; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.Collections; + +import static com.ctrip.framework.apollo.monitor.internal.ApolloClientMonitorConstant.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +public class DefaultApolloClientNamespaceApiTest { + + @Mock + private ConfigManager configManager; + + @Mock + private Config config; + + @InjectMocks + private DefaultApolloClientNamespaceApi namespaceApi; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + when(configManager.getConfig(anyString())).thenReturn(config); + } + + @Test + public void testCollectNamespaceNotFound() { + ApolloClientMonitorEvent event = ApolloClientMonitorEventFactory + .getInstance().createEvent(APOLLO_CLIENT_NAMESPACE_NOT_FOUND) + .putAttachment(NAMESPACE, "testNamespace"); + + namespaceApi.collect0(event); + + assertTrue(namespaceApi.getNotFoundNamespaces().contains("testNamespace")); + } + + @Test + public void testCollectNamespaceTimeout() { + ApolloClientMonitorEvent event = ApolloClientMonitorEventFactory + .getInstance().createEvent(APOLLO_CLIENT_NAMESPACE_TIMEOUT) + .putAttachment(NAMESPACE, "testNamespace"); + + namespaceApi.collect0(event); + + assertTrue(namespaceApi.getTimeoutNamespaces().contains("testNamespace")); + } + + @Test + public void testCollectNormalNamespace() { + ApolloClientMonitorEvent event = ApolloClientMonitorEventFactory + .getInstance().createEvent(APOLLO_CLIENT_NAMESPACE_USAGE) + .putAttachment(NAMESPACE, "testNamespace"); + + namespaceApi.collect0(event); + + // Verify that the usage count has been incremented + assertEquals(1, namespaceApi.getNamespaceMetrics().get("testNamespace").getUsageCount()); + } + + @Test + public void testGetNamespacePropertySize() { + when(config.getPropertyNames()).thenReturn(Collections.singleton("property1")); + + Integer propertySize = namespaceApi.getNamespacePropertySize("testNamespace"); + + assertEquals(Integer.valueOf(1), propertySize); + } + + @Test + public void testExportMetrics() { + // Set up some initial state + ApolloClientMonitorEvent event = ApolloClientMonitorEventFactory + .getInstance().createEvent(APOLLO_CLIENT_NAMESPACE_USAGE) + .putAttachment(NAMESPACE, "testNamespace"); + namespaceApi.collect0(event); + + // Call the export method + namespaceApi.export0(); + + // Verify interactions with the configManager + verify(configManager).getConfig("testNamespace"); + } +} \ No newline at end of file diff --git a/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/DefaultApolloClientThreadPoolApiTest.java b/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/DefaultApolloClientThreadPoolApiTest.java new file mode 100644 index 00000000..f1d93b23 --- /dev/null +++ b/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/DefaultApolloClientThreadPoolApiTest.java @@ -0,0 +1,92 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.listener.impl; + +import static org.junit.Assert.*; + +import com.ctrip.framework.apollo.monitor.api.ApolloClientThreadPoolMonitorApi.ApolloThreadPoolInfo; +import lombok.SneakyThrows; +import org.junit.Before; +import org.junit.Test; + +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadPoolExecutor; + +public class DefaultApolloClientThreadPoolApiTest { + + private DefaultApolloClientThreadPoolApi threadPoolApi; + private ThreadPoolExecutor remoteConfigExecutor; + private ThreadPoolExecutor abstractConfigExecutor; + private ThreadPoolExecutor abstractConfigFileExecutor; + private ThreadPoolExecutor metricsExporterExecutor; + + @Before + public void setUp() { + remoteConfigExecutor = (ThreadPoolExecutor) Executors.newFixedThreadPool(2); + abstractConfigExecutor = (ThreadPoolExecutor) Executors.newFixedThreadPool(2); + abstractConfigFileExecutor = (ThreadPoolExecutor) Executors.newFixedThreadPool(2); + metricsExporterExecutor = (ThreadPoolExecutor) Executors.newFixedThreadPool(2); + threadPoolApi = new DefaultApolloClientThreadPoolApi( + remoteConfigExecutor, + abstractConfigExecutor, + abstractConfigFileExecutor, + metricsExporterExecutor + ); + } + + @SneakyThrows + @Test + public void testExportThreadPoolMetrics() { + remoteConfigExecutor.execute(() -> { + }); + remoteConfigExecutor.execute(() -> { + }); + // 等待任务执行完成 + Thread.sleep(200); + threadPoolApi.export0(); + + ApolloThreadPoolInfo info = threadPoolApi.getRemoteConfigRepositoryThreadPoolInfo(); + assertEquals(0, info.getQueueSize()); + assertEquals(2, info.getCompletedTaskCount()); + assertEquals(2, info.getPoolSize()); + } + + @Test + public void testGetThreadPoolInfo() { + assertNotNull(threadPoolApi.getThreadPoolInfo()); + assertEquals(4, threadPoolApi.getThreadPoolInfo().size()); + } + + @Test + public void testMetricsSampleUpdated() { + assertTrue(threadPoolApi.isMetricsSampleUpdated()); + } + + @Test + public void testGetAbstractConfigThreadPoolInfo() { + ApolloThreadPoolInfo info = threadPoolApi.getAbstractConfigThreadPoolInfo(); + assertNotNull(info); + } + + @Test + public void testGetAbstractConfigFileThreadPoolInfo() { + ApolloThreadPoolInfo info = threadPoolApi.getAbstractConfigFileThreadPoolInfo(); + assertNotNull(info); + } + + +} diff --git a/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/NullClientBootstrapArgsMonitorApiTest.java b/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/NullClientBootstrapArgsMonitorApiTest.java new file mode 100644 index 00000000..d8ece6a1 --- /dev/null +++ b/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/NullClientBootstrapArgsMonitorApiTest.java @@ -0,0 +1,157 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.listener.impl; + +import static org.junit.Assert.*; + +import org.junit.Before; +import org.junit.Test; + +import java.util.Map; + +public class NullClientBootstrapArgsMonitorApiTest { + + private NullClientBootstrapArgsMonitorApi bootstrapArgsMonitorApi; + + @Before + public void setUp() { + bootstrapArgsMonitorApi = new NullClientBootstrapArgsMonitorApi(); + } + + @Test + public void testGetStartupParams() { + assertEquals(null, bootstrapArgsMonitorApi.getStartupArg("testKey")); + } + + @Test + public void testGetConfigServiceUrl() { + assertEquals("", bootstrapArgsMonitorApi.getConfigServiceUrl()); + } + + @Test + public void testGetAccessKeySecret() { + assertEquals("", bootstrapArgsMonitorApi.getAccessKeySecret()); + } + + @Test + public void testGetAutoUpdateInjectedSpringProperties() { + assertFalse(bootstrapArgsMonitorApi.getAutoUpdateInjectedSpringProperties()); + } + + @Test + public void testIsBootstrapEnabled() { + assertFalse(bootstrapArgsMonitorApi.isBootstrapEnabled()); + } + + @Test + public void testGetBootstrapNamespaces() { + assertEquals("", bootstrapArgsMonitorApi.getBootstrapNamespaces()); + } + + @Test + public void testIsBootstrapEagerLoadEnabled() { + assertFalse(bootstrapArgsMonitorApi.isBootstrapEagerLoadEnabled()); + } + + @Test + public void testIsOverrideSystemProperties() { + assertFalse(bootstrapArgsMonitorApi.isOverrideSystemProperties()); + } + + @Test + public void testGetCacheDir() { + assertEquals("", bootstrapArgsMonitorApi.getCacheDir()); + } + + @Test + public void testGetCluster() { + assertEquals("", bootstrapArgsMonitorApi.getCluster()); + } + + @Test + public void testGetConfigService() { + assertEquals("", bootstrapArgsMonitorApi.getConfigService()); + } + + @Test + public void testIsClientMonitorEnabled() { + assertFalse(bootstrapArgsMonitorApi.isClientMonitorEnabled()); + } + + @Test + public void testIsClientMonitorJmxEnabled() { + assertFalse(bootstrapArgsMonitorApi.isClientMonitorJmxEnabled()); + } + + @Test + public void testGetClientMonitorExternalForm() { + assertEquals("", bootstrapArgsMonitorApi.getClientMonitorExternalForm()); + } + + @Test + public void testGetClientMonitorExternalExportPeriod() { + assertEquals(0, bootstrapArgsMonitorApi.getClientMonitorExternalExportPeriod()); + } + + @Test + public void testGetClientMonitorExceptionSaveSize() { + assertEquals(0, bootstrapArgsMonitorApi.getClientMonitorExceptionSaveSize()); + } + + @Test + public void testGetApolloMeta() { + assertEquals("", bootstrapArgsMonitorApi.getApolloMeta()); + } + + @Test + public void testGetMetaLatestFreshTime() { + assertEquals("", bootstrapArgsMonitorApi.getMetaLatestFreshTime()); + } + + @Test + public void testIsPropertyNamesCacheEnable() { + assertFalse(bootstrapArgsMonitorApi.isPropertyNamesCacheEnable()); + } + + @Test + public void testIsPropertyOrderEnable() { + assertFalse(bootstrapArgsMonitorApi.isPropertyOrderEnable()); + } + + @Test + public void testGetVersion() { + assertEquals("", bootstrapArgsMonitorApi.getVersion()); + } + + @Test + public void testGetEnv() { + assertEquals("", bootstrapArgsMonitorApi.getEnv()); + } + + @Test + public void testGetAppId() { + assertEquals("", bootstrapArgsMonitorApi.getAppId()); + } + + @Test + public void testGetBootstrapArgs() { + Map bootstrapArgs = bootstrapArgsMonitorApi.getBootstrapArgs(); + + assertNotNull(bootstrapArgs); + assertTrue(bootstrapArgs.isEmpty()); + } +} diff --git a/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/NullClientExceptionMonitorApiTest.java b/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/NullClientExceptionMonitorApiTest.java new file mode 100644 index 00000000..1412358d --- /dev/null +++ b/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/NullClientExceptionMonitorApiTest.java @@ -0,0 +1,50 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.listener.impl; + +import static org.junit.Assert.*; + +import org.junit.Before; +import org.junit.Test; + +import java.util.List; + +public class NullClientExceptionMonitorApiTest { + + private NullClientExceptionMonitorApi exceptionMonitorApi; + + @Before + public void setUp() { + exceptionMonitorApi = new NullClientExceptionMonitorApi(); + } + + @Test + public void testGetApolloConfigExceptionList() { + List exceptionList = exceptionMonitorApi.getApolloConfigExceptionList(); + + assertNotNull(exceptionList); + assertTrue(exceptionList.isEmpty()); + } + + @Test + public void testGetApolloConfigExceptionDetails() { + List exceptionDetails = exceptionMonitorApi.getApolloConfigExceptionDetails(); + + assertNotNull(exceptionDetails); + assertTrue(exceptionDetails.isEmpty()); + } +} diff --git a/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/NullClientNamespaceMonitorApiTest.java b/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/NullClientNamespaceMonitorApiTest.java new file mode 100644 index 00000000..d44645f4 --- /dev/null +++ b/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/NullClientNamespaceMonitorApiTest.java @@ -0,0 +1,68 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.listener.impl; + +import static org.junit.Assert.*; + +import com.ctrip.framework.apollo.monitor.api.ApolloClientNamespaceMonitorApi.NamespaceMetrics; +import java.util.Set; +import org.junit.Before; +import org.junit.Test; + +import java.util.List; +import java.util.Map; + +public class NullClientNamespaceMonitorApiTest { + + private NullClientNamespaceMonitorApi namespaceMonitorApi; + + @Before + public void setUp() { + namespaceMonitorApi = new NullClientNamespaceMonitorApi(); + } + + @Test + public void testGetNamespaceMetrics() { + Map metrics = namespaceMonitorApi.getNamespaceMetrics(); + + assertNotNull(metrics); + assertTrue(metrics.isEmpty()); + } + + @Test + public void testGetNamespaceItemNames() { + Integer testNamespace = namespaceMonitorApi.getNamespacePropertySize("testNamespace"); + assertEquals(0, testNamespace.intValue()); + + } + + @Test + public void testGetNotFoundNamespaces() { + List notFoundNamespaces = namespaceMonitorApi.getNotFoundNamespaces(); + + assertNotNull(notFoundNamespaces); + assertTrue(notFoundNamespaces.isEmpty()); + } + + @Test + public void testGetTimeoutNamespaces() { + List timeoutNamespaces = namespaceMonitorApi.getTimeoutNamespaces(); + + assertNotNull(timeoutNamespaces); + assertTrue(timeoutNamespaces.isEmpty()); + } +} diff --git a/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/NullClientThreadPoolMonitorApiTest.java b/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/NullClientThreadPoolMonitorApiTest.java new file mode 100644 index 00000000..81f812c7 --- /dev/null +++ b/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/listener/impl/NullClientThreadPoolMonitorApiTest.java @@ -0,0 +1,51 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.listener.impl; + +import static org.junit.Assert.*; + +import com.ctrip.framework.apollo.monitor.api.ApolloClientThreadPoolMonitorApi.ApolloThreadPoolInfo; +import org.junit.Before; +import org.junit.Test; + +import java.util.Map; + +public class NullClientThreadPoolMonitorApiTest { + + private NullClientThreadPoolMonitorApi monitorApi; + + @Before + public void setUp() { + monitorApi = new NullClientThreadPoolMonitorApi(); + } + + @Test + public void testGetThreadPoolInfo() { + Map threadPoolInfo = monitorApi.getThreadPoolInfo(); + + assertNotNull(threadPoolInfo); + assertTrue(threadPoolInfo.isEmpty()); + } + + @Test + public void testGetRemoteConfigRepositoryThreadPoolInfo() { + ApolloThreadPoolInfo info = monitorApi.getRemoteConfigRepositoryThreadPoolInfo(); + assertNotNull(info); + assertEquals(0, info.getPoolSize()); + } + +} diff --git a/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/tracer/ApolloClientMessageProducerCompositeTest.java b/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/tracer/ApolloClientMessageProducerCompositeTest.java new file mode 100644 index 00000000..b0eb740f --- /dev/null +++ b/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/tracer/ApolloClientMessageProducerCompositeTest.java @@ -0,0 +1,134 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.tracer; + +import static org.mockito.Mockito.*; +import static org.junit.Assert.*; + +import com.ctrip.framework.apollo.tracer.spi.MessageProducer; +import com.ctrip.framework.apollo.tracer.spi.Transaction; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.Arrays; +import java.util.List; + +public class ApolloClientMessageProducerCompositeTest { + + private ApolloClientMessageProducerComposite composite; + + @Mock + private MessageProducer producer1; + + @Mock + private MessageProducer producer2; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + List producers = Arrays.asList(producer1, producer2); + composite = new ApolloClientMessageProducerComposite(producers); + } + + @Test + public void testLogError_Throwable() { + Throwable cause = new Exception("Test exception"); + + composite.logError(cause); + + verify(producer1).logError(cause); + verify(producer2).logError(cause); + } + + @Test + public void testLogError_String_Throwable() { + String message = "Test error message"; + Throwable cause = new Exception("Test exception"); + + composite.logError(message, cause); + + verify(producer1).logError(message, cause); + verify(producer2).logError(message, cause); + } + + @Test + public void testLogEvent_Type_Name() { + String type = "EVENT_TYPE"; + String name = "EVENT_NAME"; + + composite.logEvent(type, name); + + verify(producer1).logEvent(type, name); + verify(producer2).logEvent(type, name); + } + + @Test + public void testLogEvent_Type_Name_Status_NameValuePairs() { + String type = "EVENT_TYPE"; + String name = "EVENT_NAME"; + String status = "SUCCESS"; + String nameValuePairs = "key=value"; + + composite.logEvent(type, name, status, nameValuePairs); + + verify(producer1).logEvent(type, name, status, nameValuePairs); + verify(producer2).logEvent(type, name, status, nameValuePairs); + } + + @Test + public void testLogMetricsForCount() { + String name = "METRIC_NAME"; + + composite.logMetricsForCount(name); + + verify(producer1).logMetricsForCount(name); + verify(producer2).logMetricsForCount(name); + } + + @Test + public void testNewTransaction() { + String type = "TRANSACTION_TYPE"; + String name = "TRANSACTION_NAME"; + + Transaction transaction1 = mock(Transaction.class); + when(producer1.newTransaction(type, name)).thenReturn(null); + when(producer2.newTransaction(type, name)).thenReturn(transaction1); + + Transaction result = composite.newTransaction(type, name); + + assertEquals(transaction1, result); + verify(producer1).newTransaction(type, name); + verify(producer2).newTransaction(type, name); + } + + @Test + public void testNewTransaction_NoValidTransaction() { + String type = "TRANSACTION_TYPE"; + String name = "TRANSACTION_NAME"; + + when(producer1.newTransaction(type, name)).thenReturn(null); + when(producer2.newTransaction(type, name)).thenReturn(null); + + Transaction result = composite.newTransaction(type, name); + + assertEquals(ApolloClientMessageProducerComposite.NULL_TRANSACTION, result); + verify(producer1).newTransaction(type, name); + verify(producer2).newTransaction(type, name); + } +} diff --git a/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/tracer/ApolloClientMonitorMessageProducerTest.java b/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/tracer/ApolloClientMonitorMessageProducerTest.java new file mode 100644 index 00000000..dde82909 --- /dev/null +++ b/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/tracer/ApolloClientMonitorMessageProducerTest.java @@ -0,0 +1,83 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.tracer; + +import static com.ctrip.framework.apollo.monitor.internal.ApolloClientMonitorConstant.*; +import static org.junit.Assert.*; + +import com.ctrip.framework.apollo.tracer.spi.Transaction; +import org.junit.Before; +import org.junit.Test; +import org.mockito.MockitoAnnotations; + + +public class ApolloClientMonitorMessageProducerTest { + + private ApolloClientMonitorMessageProducer producer; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + producer = new ApolloClientMonitorMessageProducer(); + } + + @Test + public void testLogError_Throwable() { + Throwable cause = new Exception("Test exception"); + + producer.logError(cause); + } + + @Test + public void testLogError_String_Throwable() { + String message = "Test error message"; + Throwable cause = new Exception("Test exception"); + + producer.logError(message, cause); + } + + @Test + public void testLogEvent_TaggedEvent() { + String type = ApolloClientMonitorMessageProducer.TAGS.get(0); // APOLLO_CLIENT_CONFIGCHANGES + String name = "Test event"; + + producer.logEvent(type, name); + } + + @Test + public void testLogEvent_ClientConfigEvent() { + String type = APOLLO_CLIENT_CONFIGS + "namespace"; + String name = "Test config"; + + producer.logEvent(type, name); + } + + @Test + public void testLogMetricsForCount() { + String name = APOLLO_CLIENT_NAMESPACE_USAGE + ":testNamespace"; + + producer.logMetricsForCount(name); + } + + @Test + public void testNewTransaction() { + Transaction result = producer.newTransaction("type", "name"); + + assertEquals(ApolloClientMessageProducerComposite.NULL_TRANSACTION, result); + } +} \ No newline at end of file diff --git a/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/stress/ApolloClientMonitorStressTest.java b/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/stress/ApolloClientMonitorStressTest.java new file mode 100644 index 00000000..778bd527 --- /dev/null +++ b/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/stress/ApolloClientMonitorStressTest.java @@ -0,0 +1,56 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.stress; + +import static com.ctrip.framework.apollo.monitor.internal.ApolloClientMonitorConstant.*; + +import com.ctrip.framework.apollo.ConfigService; +import com.ctrip.framework.apollo.monitor.internal.event.ApolloClientMonitorEventFactory; +import com.ctrip.framework.apollo.monitor.internal.event.ApolloClientMonitorEventPublisher; +import com.github.noconnor.junitperf.JUnitPerfRule; +import com.github.noconnor.junitperf.JUnitPerfTest; +import org.junit.Ignore; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +@Ignore("Stress test") +@RunWith(SpringJUnit4ClassRunner.class) +@SpringBootTest(classes = ApolloClientMonitorStressTest.class) +public class ApolloClientMonitorStressTest { + + @Rule + public JUnitPerfRule perfTestRule = new JUnitPerfRule(); + + @Test + @JUnitPerfTest(threads = 25, durationMs = 10000, warmUpMs = 1000, maxExecutionsPerSecond = 1000) + public void testConfigMonitor() { + System.out.println("abcdeft"); + ConfigService.getConfigMonitor().getExporterData(); + } + + @Test + @JUnitPerfTest(threads = 50, durationMs = 10000, warmUpMs = 1000, maxExecutionsPerSecond = 1000) + public void testPublishEvent() { + ApolloClientMonitorEventPublisher.publish( + ApolloClientMonitorEventFactory.getInstance() + .createEvent(APOLLO_CLIENT_NAMESPACE_USAGE) + .putAttachment(NAMESPACE, "application")); + } +} diff --git a/apollo-client/src/test/java/com/ctrip/framework/apollo/util/ConfigUtilTest.java b/apollo-client/src/test/java/com/ctrip/framework/apollo/util/ConfigUtilTest.java index 23a37362..18cda2dd 100644 --- a/apollo-client/src/test/java/com/ctrip/framework/apollo/util/ConfigUtilTest.java +++ b/apollo-client/src/test/java/com/ctrip/framework/apollo/util/ConfigUtilTest.java @@ -255,6 +255,92 @@ public void testCustomizePropertiesOrdered() { configUtil.isPropertiesOrderEnabled()); } + @Test + public void testMonitorExternalType() { + String someMonitorExternalType = "someType"; + System.setProperty(ApolloClientSystemConsts.APOLLO_CLIENT_MONITOR_EXTERNAL_TYPE, someMonitorExternalType); + + ConfigUtil configUtil = new ConfigUtil(); + + assertEquals(someMonitorExternalType, configUtil.getMonitorExternalType()); + } + + @Test + public void testCustomizeMonitorExternalCollectPeriod() { + int somePeriod = 5; + System.setProperty(ApolloClientSystemConsts.APOLLO_CLIENT_MONITOR_EXTERNAL_EXPORT_PERIOD, String.valueOf(somePeriod)); + + ConfigUtil configUtil = new ConfigUtil(); + + assertEquals(somePeriod, configUtil.getMonitorExternalExportPeriod()); + } + + @Test + public void testCustomizeInvalidMonitorExternalCollectPeriod() { + String someInvalidPeriod = "a"; + System.setProperty(ApolloClientSystemConsts.APOLLO_CLIENT_MONITOR_EXTERNAL_EXPORT_PERIOD, someInvalidPeriod); + + ConfigUtil configUtil = new ConfigUtil(); + + assertEquals(10, configUtil.getMonitorExternalExportPeriod()); // Default value + } + + @Test + public void testClientMonitorEnabled() { + System.setProperty(ApolloClientSystemConsts.APOLLO_CLIENT_MONITOR_ENABLED, "true"); + + ConfigUtil configUtil = new ConfigUtil(); + + assertTrue(configUtil.isClientMonitorEnabled()); + } + + @Test + public void testClientMonitorEnabledDefault() { + System.clearProperty(ApolloClientSystemConsts.APOLLO_CLIENT_MONITOR_ENABLED); + + ConfigUtil configUtil = new ConfigUtil(); + + assertFalse(configUtil.isClientMonitorEnabled()); // Default value + } + + @Test + public void testClientMonitorJmxEnabled() { + System.setProperty(ApolloClientSystemConsts.APOLLO_CLIENT_MONITOR_JMX_ENABLED, "true"); + + ConfigUtil configUtil = new ConfigUtil(); + + assertTrue(configUtil.isClientMonitorJmxEnabled()); + } + + @Test + public void testClientMonitorJmxEnabledDefault() { + System.clearProperty(ApolloClientSystemConsts.APOLLO_CLIENT_MONITOR_JMX_ENABLED); + + ConfigUtil configUtil = new ConfigUtil(); + + assertFalse(configUtil.isClientMonitorJmxEnabled()); // Default value + } + + @Test + public void testCustomizeMonitorExceptionQueueSize() { + int someQueueSize = 10; + System.setProperty(ApolloClientSystemConsts.APOLLO_CLIENT_MONITOR_EXCEPTION_QUEUE_SIZE, String.valueOf(someQueueSize)); + + ConfigUtil configUtil = new ConfigUtil(); + + assertEquals(someQueueSize, configUtil.getMonitorExceptionQueueSize()); + } + + @Test + public void testCustomizeInvalidMonitorExceptionQueueSize() { + String someInvalidQueueSize = "a"; + System.setProperty(ApolloClientSystemConsts.APOLLO_CLIENT_MONITOR_EXCEPTION_QUEUE_SIZE, someInvalidQueueSize); + + ConfigUtil configUtil = new ConfigUtil(); + + assertEquals(25, configUtil.getMonitorExceptionQueueSize()); // Default value + } + @Test public void test() { ConfigUtil configUtil = new ConfigUtil(); diff --git a/apollo-client/src/test/resources/META-INF/services/com.ctrip.framework.apollo.monitor.internal.exporter.ApolloClientMetricsExporter b/apollo-client/src/test/resources/META-INF/services/com.ctrip.framework.apollo.monitor.internal.exporter.ApolloClientMetricsExporter new file mode 100644 index 00000000..2deb4099 --- /dev/null +++ b/apollo-client/src/test/resources/META-INF/services/com.ctrip.framework.apollo.monitor.internal.exporter.ApolloClientMetricsExporter @@ -0,0 +1 @@ +com.ctrip.framework.apollo.monitor.internal.exporter.MockApolloClientMetricsExporter \ No newline at end of file diff --git a/apollo-core/src/main/java/com/ctrip/framework/apollo/core/ApolloClientSystemConsts.java b/apollo-core/src/main/java/com/ctrip/framework/apollo/core/ApolloClientSystemConsts.java index 0fa0550a..2bf8f850 100644 --- a/apollo-core/src/main/java/com/ctrip/framework/apollo/core/ApolloClientSystemConsts.java +++ b/apollo-core/src/main/java/com/ctrip/framework/apollo/core/ApolloClientSystemConsts.java @@ -161,4 +161,28 @@ public class ApolloClientSystemConsts { * enable apollo overrideSystemProperties */ public static final String APOLLO_OVERRIDE_SYSTEM_PROPERTIES = "apollo.override-system-properties"; + + /** + * apollo client monitor enabled + */ + public static final String APOLLO_CLIENT_MONITOR_ENABLED = "apollo.client.monitor.enabled"; + + /** + * apollo client monitor exception save size + */ + public static final String APOLLO_CLIENT_MONITOR_EXCEPTION_QUEUE_SIZE = "apollo.client.monitor.exception-queue-size"; + /** + * apollo client monitor jmx enabled + */ + public static final String APOLLO_CLIENT_MONITOR_JMX_ENABLED = "apollo.client.monitor.jmx.enabled"; + + /** + * apollo client monitor form {such as jmx,prometheus} + */ + public static final String APOLLO_CLIENT_MONITOR_EXTERNAL_TYPE = "apollo.client.monitor.external.type"; + + /** + * apollo client monitor collect period + */ + public static final String APOLLO_CLIENT_MONITOR_EXTERNAL_EXPORT_PERIOD = "apollo.client.monitor.external.export-period"; } diff --git a/apollo-core/src/main/java/com/ctrip/framework/apollo/core/ConfigConsts.java b/apollo-core/src/main/java/com/ctrip/framework/apollo/core/ConfigConsts.java index a6108dfb..19f33278 100644 --- a/apollo-core/src/main/java/com/ctrip/framework/apollo/core/ConfigConsts.java +++ b/apollo-core/src/main/java/com/ctrip/framework/apollo/core/ConfigConsts.java @@ -24,5 +24,6 @@ public interface ConfigConsts { String APOLLO_META_KEY = "apollo.meta"; String CONFIG_FILE_CONTENT_KEY = "content"; String NO_APPID_PLACEHOLDER = "ApolloNoAppIdPlaceHolder"; + String APOLLO_AUTO_UPDATE_INJECTED_SPRING_PROPERTIES = "ApolloAutoUpdateInjectedSpringProperties"; long NOTIFICATION_ID_PLACEHOLDER = -1; } diff --git a/apollo-core/src/main/java/com/ctrip/framework/apollo/tracer/Tracer.java b/apollo-core/src/main/java/com/ctrip/framework/apollo/tracer/Tracer.java index e97e8a6d..d8971db0 100644 --- a/apollo-core/src/main/java/com/ctrip/framework/apollo/tracer/Tracer.java +++ b/apollo-core/src/main/java/com/ctrip/framework/apollo/tracer/Tracer.java @@ -88,6 +88,14 @@ public static void logEvent(String type, String name, String status, String name type, name, status, nameValuePairs, ex); } } + + public static void logMetricsForCount(String name) { + try { + getProducer().logMetricsForCount(name); + } catch (Throwable ex) { + logger.warn("Failed to log metrics for count: {}", name, ex); + } + } public static Transaction newTransaction(String type, String name) { try { diff --git a/apollo-core/src/main/java/com/ctrip/framework/apollo/tracer/internals/cat/CatMessageProducer.java b/apollo-core/src/main/java/com/ctrip/framework/apollo/tracer/internals/cat/CatMessageProducer.java index cb525f90..e1796073 100644 --- a/apollo-core/src/main/java/com/ctrip/framework/apollo/tracer/internals/cat/CatMessageProducer.java +++ b/apollo-core/src/main/java/com/ctrip/framework/apollo/tracer/internals/cat/CatMessageProducer.java @@ -45,6 +45,11 @@ public void logEvent(String type, String name, String status, String nameValuePa status, nameValuePairs); } + @Override + public void logMetricsForCount(String name) { + Cat.logMetricForCount(name); + } + @Override public Transaction newTransaction(String type, String name) { return new CatTransaction(Cat.newTransaction(type, name)); diff --git a/apollo-core/src/main/java/com/ctrip/framework/apollo/tracer/internals/cat/CatTransaction.java b/apollo-core/src/main/java/com/ctrip/framework/apollo/tracer/internals/cat/CatTransaction.java index bccdb5e9..0251c6f8 100644 --- a/apollo-core/src/main/java/com/ctrip/framework/apollo/tracer/internals/cat/CatTransaction.java +++ b/apollo-core/src/main/java/com/ctrip/framework/apollo/tracer/internals/cat/CatTransaction.java @@ -50,4 +50,4 @@ public void addData(String key, Object value) { public void complete() { catTransaction.complete(); } -} +} \ No newline at end of file diff --git a/apollo-core/src/main/java/com/ctrip/framework/apollo/tracer/spi/MessageProducer.java b/apollo-core/src/main/java/com/ctrip/framework/apollo/tracer/spi/MessageProducer.java index 61eb8040..7654c56c 100644 --- a/apollo-core/src/main/java/com/ctrip/framework/apollo/tracer/spi/MessageProducer.java +++ b/apollo-core/src/main/java/com/ctrip/framework/apollo/tracer/spi/MessageProducer.java @@ -16,10 +16,12 @@ */ package com.ctrip.framework.apollo.tracer.spi; +import com.ctrip.framework.apollo.core.spi.Ordered; + /** * @author Jason Song(song_s@ctrip.com) */ -public interface MessageProducer { +public interface MessageProducer extends Ordered { /** * Log an error. * @@ -52,6 +54,16 @@ public interface MessageProducer { */ void logEvent(String type, String name, String status, String nameValuePairs); + + /** + * log metrics for count + * + * @param name metrics name + */ + default void logMetricsForCount(String name) { + //do nothing + } + /** * Create a new transaction with given type and name. * @@ -59,4 +71,10 @@ public interface MessageProducer { * @param name transaction name */ Transaction newTransaction(String type, String name); + + + @Override + default int getOrder() { + return 0; + } } diff --git a/apollo-plugin/apollo-plugin-client-prometheus/pom.xml b/apollo-plugin/apollo-plugin-client-prometheus/pom.xml new file mode 100644 index 00000000..07cb99c6 --- /dev/null +++ b/apollo-plugin/apollo-plugin-client-prometheus/pom.xml @@ -0,0 +1,45 @@ + + + + 4.0.0 + + apollo-plugin + com.ctrip.framework.apollo + ${revision} + ../pom.xml + + + apollo-plugin-client-prometheus + Apollo Plugin Prometheus + jar + + + + com.ctrip.framework.apollo + apollo-client + provided + + + io.prometheus + simpleclient_common + + + + \ No newline at end of file diff --git a/apollo-plugin/apollo-plugin-client-prometheus/src/main/java/com/ctrip/framework/apollo/monitor/internal/exporter/impl/PrometheusApolloClientMetricsExporter.java b/apollo-plugin/apollo-plugin-client-prometheus/src/main/java/com/ctrip/framework/apollo/monitor/internal/exporter/impl/PrometheusApolloClientMetricsExporter.java new file mode 100644 index 00000000..a07e3209 --- /dev/null +++ b/apollo-plugin/apollo-plugin-client-prometheus/src/main/java/com/ctrip/framework/apollo/monitor/internal/exporter/impl/PrometheusApolloClientMetricsExporter.java @@ -0,0 +1,102 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.exporter.impl; + +import com.ctrip.framework.apollo.core.utils.DeferredLoggerFactory; +import com.ctrip.framework.apollo.monitor.internal.exporter.AbstractApolloClientMetricsExporter; +import com.ctrip.framework.apollo.monitor.internal.exporter.ApolloClientMetricsExporter; +import com.ctrip.framework.apollo.monitor.internal.listener.impl.DefaultApolloClientNamespaceApi; +import com.google.common.collect.Maps; +import io.prometheus.client.Collector; +import io.prometheus.client.CollectorRegistry; +import io.prometheus.client.Counter; +import io.prometheus.client.Gauge; +import io.prometheus.client.exporter.common.TextFormat; +import java.io.IOException; +import java.io.StringWriter; +import java.util.HashMap; +import java.util.Map; +import org.slf4j.Logger; + +/** + * @author Rawven + */ +public class PrometheusApolloClientMetricsExporter extends + AbstractApolloClientMetricsExporter implements ApolloClientMetricsExporter { + + private static final String PROMETHEUS = "prometheus"; + private final Logger logger = DeferredLoggerFactory.getLogger( + DefaultApolloClientNamespaceApi.class); + protected CollectorRegistry registry; + protected Map map; + + @Override + public void doInit() { + registry = new CollectorRegistry(); + map = Maps.newConcurrentMap(); + } + + @Override + public boolean isSupport(String form) { + return PROMETHEUS.equals(form); + } + + + @Override + public void registerOrUpdateCounterSample(String name, Map tags, + double incrValue) { + Counter counter = (Counter) map.computeIfAbsent(name, + key -> createCounter(key, tags)); + counter.labels(tags.values().toArray(new String[0])).inc(incrValue); + } + + private Counter createCounter(String name, Map tags) { + return Counter.build() + .name(name) + .help("apollo counter metrics") + .labelNames(tags.keySet().toArray(new String[0])) + .register(registry); + } + + @Override + public void registerOrUpdateGaugeSample(String name, Map tags, double value) { + Gauge gauge = (Gauge) map.computeIfAbsent(name, key -> createGauge(key, tags)); + gauge.labels(tags.values().toArray(new String[0])).set(value); + } + + private Gauge createGauge(String name, Map tags) { + return Gauge.build() + .name(name) + .help("apollo gauge metrics") + .labelNames(tags.keySet().toArray(new String[0])) + .register(registry); + } + + + @Override + public String response() { + try (StringWriter writer = new StringWriter()) { + TextFormat.writeFormat(TextFormat.CONTENT_TYPE_OPENMETRICS_100, writer, + registry.metricFamilySamples()); + return writer.toString(); + } catch (IOException e) { + logger.error("Write metrics to Prometheus format failed", e); + return ""; + } + } +} + \ No newline at end of file diff --git a/apollo-plugin/apollo-plugin-client-prometheus/src/main/resources/META-INF/services/com.ctrip.framework.apollo.monitor.internal.exporter.ApolloClientMetricsExporter b/apollo-plugin/apollo-plugin-client-prometheus/src/main/resources/META-INF/services/com.ctrip.framework.apollo.monitor.internal.exporter.ApolloClientMetricsExporter new file mode 100644 index 00000000..7296cdce --- /dev/null +++ b/apollo-plugin/apollo-plugin-client-prometheus/src/main/resources/META-INF/services/com.ctrip.framework.apollo.monitor.internal.exporter.ApolloClientMetricsExporter @@ -0,0 +1 @@ +com.ctrip.framework.apollo.monitor.internal.exporter.impl.PrometheusApolloClientMetricsExporter \ No newline at end of file diff --git a/apollo-plugin/apollo-plugin-client-prometheus/src/test/java/com/ctrip/framework/apollo/monitor/internal/exporter/impl/PrometheusApolloClientMetricsExporterTest.java b/apollo-plugin/apollo-plugin-client-prometheus/src/test/java/com/ctrip/framework/apollo/monitor/internal/exporter/impl/PrometheusApolloClientMetricsExporterTest.java new file mode 100644 index 00000000..a0940776 --- /dev/null +++ b/apollo-plugin/apollo-plugin-client-prometheus/src/test/java/com/ctrip/framework/apollo/monitor/internal/exporter/impl/PrometheusApolloClientMetricsExporterTest.java @@ -0,0 +1,78 @@ +/* + * Copyright 2022 Apollo Authors + * + * 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 com.ctrip.framework.apollo.monitor.internal.exporter.impl; +import static org.junit.Assert.*; + +import io.prometheus.client.Counter; +import io.prometheus.client.Gauge; +import org.junit.Before; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +public class PrometheusApolloClientMetricsExporterTest { + + private PrometheusApolloClientMetricsExporter exporter; + + @Before + public void setUp() { + exporter = new PrometheusApolloClientMetricsExporter(); + exporter.doInit(); + } + + @Test + public void testIsSupport() { + assertTrue(exporter.isSupport("prometheus")); + assertFalse(exporter.isSupport("other")); + } + + @Test + public void testRegisterOrUpdateCounterSample() { + String name = "test_counter"; + Map tags = new HashMap<>(); + tags.put("tag1", "value1"); + + exporter.registerOrUpdateCounterSample(name, tags, 1.0); + + Counter counter = (Counter) exporter.map.get(name); + + assertNotNull(counter); + assertEquals(1.0, counter.labels("value1").get(), 0.001); + } + + @Test + public void testRegisterOrUpdateGaugeSample() { + String name = "test_gauge"; + Map tags = new HashMap<>(); + tags.put("tag2", "value2"); + + exporter.registerOrUpdateGaugeSample(name, tags, 3.0); + + Gauge gauge = (Gauge) exporter.map.get(name); + + assertNotNull(gauge); + assertEquals(3.0, gauge.labels("value2").get(), 0.001); + } + + @Test + public void testResponse() { + String response = exporter.response(); + assertNotNull(response); + assertFalse(response.isEmpty()); + } +} diff --git a/apollo-plugin/apollo-plugin-client-prometheus/src/test/resources/META-INF/services/com.ctrip.framework.apollo.monitor.internal.exporter.ApolloClientMetricsExporter b/apollo-plugin/apollo-plugin-client-prometheus/src/test/resources/META-INF/services/com.ctrip.framework.apollo.monitor.internal.exporter.ApolloClientMetricsExporter new file mode 100644 index 00000000..7296cdce --- /dev/null +++ b/apollo-plugin/apollo-plugin-client-prometheus/src/test/resources/META-INF/services/com.ctrip.framework.apollo.monitor.internal.exporter.ApolloClientMetricsExporter @@ -0,0 +1 @@ +com.ctrip.framework.apollo.monitor.internal.exporter.impl.PrometheusApolloClientMetricsExporter \ No newline at end of file diff --git a/apollo-plugin/pom.xml b/apollo-plugin/pom.xml index 3a47b738..f0d1b00f 100644 --- a/apollo-plugin/pom.xml +++ b/apollo-plugin/pom.xml @@ -31,6 +31,7 @@ apollo-plugin-log4j2 + apollo-plugin-client-prometheus diff --git a/pom.xml b/pom.xml index d153bf11..31321a3c 100644 --- a/pom.xml +++ b/pom.xml @@ -65,6 +65,7 @@ UTF-8 2.7.18 3.1.0 + 1.36.0 3.10.1 2.22.2 @@ -136,6 +137,12 @@ 5.7.0 test + + com.github.noconnor + junitperf + ${junitperf} + test + com.github.stefanbirkner system-lambda