From 7de469ed24088cefea91a44b85285cf08b312f0a Mon Sep 17 00:00:00 2001 From: liu Date: Thu, 1 Aug 2024 17:19:41 +0800 Subject: [PATCH] feat(client): Add more observability in apollo config client --- .../ctrip/framework/apollo/ConfigService.java | 36 ++- .../apollo/internals/AbstractConfig.java | 2 +- .../apollo/internals/AbstractConfigFile.java | 7 +- .../internals/AbstractConfigRepository.java | 4 +- .../internals/ConfigMonitorInitializer.java | 113 +++++++ .../internals/ConfigServiceLocator.java | 40 +-- .../apollo/internals/DefaultConfig.java | 4 +- .../internals/DefaultConfigManager.java | 25 +- .../apollo/internals/DefaultInjector.java | 12 +- .../internals/LocalFileConfigRepository.java | 4 +- .../RemoteConfigLongPollService.java | 15 +- .../internals/RemoteConfigRepository.java | 36 ++- .../apollo/internals/SimpleConfig.java | 4 +- .../apollo/internals/YamlConfigFile.java | 4 +- .../api/ApolloExceptionMonitorApi.java | 38 +++ .../api/ApolloNamespaceMonitorApi.java | 53 ++++ .../api/ApolloRunningParamsMonitorApi.java | 70 +++++ .../api/ApolloThreadPoolMonitorApi.java | 89 ++++++ .../apollo/monitor/api/ConfigMonitor.java | 33 ++ .../internal/DefaultConfigMonitor.java | 78 +++++ .../monitor/internal/MonitorConstant.java | 29 ++ .../monitor/internal/NullConfigMonitor.java | 58 ++++ .../internal/NullExceptionMonitorApi.java | 34 ++ .../internal/NullNamespaceMonitorApi.java | 89 ++++++ .../internal/NullRunningParamsMonitorApi.java | 132 ++++++++ .../internal/NullThreadPoolMonitorApi.java | 172 ++++++++++ .../collector/AbstractMetricsCollector.java | 80 +++++ .../internal/collector/MetricsCollector.java | 52 +++ .../collector/MetricsCollectorManager.java | 36 +++ .../DefaultApolloExceptionCollector.java | 84 +++++ .../DefaultApolloNamespaceCollector.java | 296 ++++++++++++++++++ .../DefaultApolloRunningParamsCollector.java | 230 ++++++++++++++ .../DefaultApolloThreadPoolCollector.java | 257 +++++++++++++++ .../DefaultMetricsCollectorManager.java | 42 +++ .../exporter/AbstractMetricsExporter.java | 108 +++++++ .../internal/exporter/MetricsExporter.java | 62 ++++ .../exporter/MetricsExporterFactory.java | 28 ++ .../DefaultMetricsExporterFactory.java | 77 +++++ .../monitor/internal/model/CounterModel.java | 82 +++++ .../monitor/internal/model/GaugeModel.java | 98 ++++++ .../monitor/internal/model/MetricsEvent.java | 94 ++++++ .../internal/model/MetricsEventPusher.java | 45 +++ .../monitor/internal/model/MetricsModel.java | 48 +++ .../tracer/ClientMessageProducerManager.java | 43 +++ .../tracer/MessageProducerComposite.java | 85 +++++ .../tracer/MonitorMessageProducer.java | 152 +++++++++ .../apollo/monitor/internal/util/JMXUtil.java | 63 ++++ .../monitor/internal/util/MeterType.java | 25 ++ .../ApolloApplicationContextInitializer.java | 11 +- .../framework/apollo/util/ConfigUtil.java | 134 ++++++-- .../framework/apollo/util/ExceptionUtil.java | 2 +- ...itional-spring-configuration-metadata.json | 29 ++ ...k.apollo.tracer.spi.MessageProducerManager | 1 + .../AbstractApolloMetricsCollectorTest.java | 90 ++++++ .../AbstractApolloMetricsExporterTest.java | 123 ++++++++ ...faultApolloMetricsExporterFactoryTest.java | 60 ++++ .../apollo/core/ApolloClientSystemConsts.java | 20 ++ .../framework/apollo/core/ConfigConsts.java | 1 + .../DefaultMessageProducerManager.java | 22 +- .../tracer/internals/cat/CatTransaction.java | 2 +- .../apollo/tracer/spi/MessageProducer.java | 10 +- .../apollo-plugin-client-prometheus/pom.xml | 46 +++ .../prometheus/PrometheusMetricExporter.java | 106 +++++++ ....monitor.internal.exporter.MetricsExporter | 1 + apollo-plugin/pom.xml | 1 + 65 files changed, 3832 insertions(+), 95 deletions(-) create mode 100644 apollo-client/src/main/java/com/ctrip/framework/apollo/internals/ConfigMonitorInitializer.java create mode 100644 apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/api/ApolloExceptionMonitorApi.java create mode 100644 apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/api/ApolloNamespaceMonitorApi.java create mode 100644 apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/api/ApolloRunningParamsMonitorApi.java create mode 100644 apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/api/ApolloThreadPoolMonitorApi.java create mode 100644 apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/api/ConfigMonitor.java create mode 100644 apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/DefaultConfigMonitor.java create mode 100644 apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/MonitorConstant.java create mode 100644 apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/NullConfigMonitor.java create mode 100644 apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/NullExceptionMonitorApi.java create mode 100644 apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/NullNamespaceMonitorApi.java create mode 100644 apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/NullRunningParamsMonitorApi.java create mode 100644 apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/NullThreadPoolMonitorApi.java create mode 100644 apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/collector/AbstractMetricsCollector.java create mode 100644 apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/collector/MetricsCollector.java create mode 100644 apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/collector/MetricsCollectorManager.java create mode 100644 apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/collector/internal/DefaultApolloExceptionCollector.java create mode 100644 apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/collector/internal/DefaultApolloNamespaceCollector.java create mode 100644 apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/collector/internal/DefaultApolloRunningParamsCollector.java create mode 100644 apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/collector/internal/DefaultApolloThreadPoolCollector.java create mode 100644 apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/collector/internal/DefaultMetricsCollectorManager.java create mode 100644 apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/exporter/AbstractMetricsExporter.java create mode 100644 apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/exporter/MetricsExporter.java create mode 100644 apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/exporter/MetricsExporterFactory.java create mode 100644 apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/exporter/internals/DefaultMetricsExporterFactory.java create mode 100644 apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/model/CounterModel.java create mode 100644 apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/model/GaugeModel.java create mode 100644 apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/model/MetricsEvent.java create mode 100644 apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/model/MetricsEventPusher.java create mode 100644 apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/model/MetricsModel.java create mode 100644 apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/tracer/ClientMessageProducerManager.java create mode 100644 apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/tracer/MessageProducerComposite.java create mode 100644 apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/tracer/MonitorMessageProducer.java create mode 100644 apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/util/JMXUtil.java create mode 100644 apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/util/MeterType.java create mode 100644 apollo-client/src/main/resources/META-INF/services/com.ctrip.framework.apollo.tracer.spi.MessageProducerManager create mode 100644 apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/collector/AbstractApolloMetricsCollectorTest.java create mode 100644 apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/exporter/AbstractApolloMetricsExporterTest.java create mode 100644 apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/exporter/DefaultApolloMetricsExporterFactoryTest.java create mode 100644 apollo-plugin/apollo-plugin-client-prometheus/pom.xml create mode 100644 apollo-plugin/apollo-plugin-client-prometheus/src/main/java/com/ctrip/framework/apollo/plugin/prometheus/PrometheusMetricExporter.java create mode 100644 apollo-plugin/apollo-plugin-client-prometheus/src/main/resources/META-INF/services/com.ctrip.framework.apollo.monitor.internal.exporter.MetricsExporter 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..06a7f46d 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,8 +20,14 @@ 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.monitor.internal.NullConfigMonitor; import com.ctrip.framework.apollo.spi.ConfigFactory; import com.ctrip.framework.apollo.spi.ConfigRegistry; +import com.ctrip.framework.apollo.util.ConfigUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Entry point for client config use @@ -30,10 +36,30 @@ */ public class ConfigService { private static final ConfigService s_instance = new ConfigService(); - + private static final Logger log = LoggerFactory.getLogger(ConfigService.class); + private volatile ConfigMonitor m_configMonitor; private volatile ConfigManager m_configManager; private volatile ConfigRegistry m_configRegistry; - + private static final ConfigUtil m_configUtil = ApolloInjector.getInstance(ConfigUtil.class); + + private ConfigMonitor getMonitor() { + getManager(); + if (m_configMonitor == null) { + synchronized (this) { + if (m_configMonitor == null) { + if (m_configUtil.isClientMonitorEnabled()) { + m_configMonitor = ApolloInjector.getInstance( + ConfigMonitor.class); + }else { + log.warn("ConfigService.getMonitor is called but apollo.client.monitor.enabled is set to false, so return NullConfigMonitor"); + m_configMonitor = new NullConfigMonitor(); + } + } + } + } + return m_configMonitor; + } + private ConfigManager getManager() { if (m_configManager == null) { synchronized (this) { @@ -42,7 +68,7 @@ private ConfigManager getManager() { } } } - + ConfigMonitorInitializer.initializeMonitorSystem(); return m_configManager; } @@ -81,6 +107,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..8fc574cf 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,9 @@ */ package com.ctrip.framework.apollo.internals; + +import static com.ctrip.framework.apollo.monitor.internal.tracer.MessageProducerComposite.APOLLO_CLIENT_CONFIGCHANGES; + import com.ctrip.framework.apollo.build.ApolloInjector; import com.ctrip.framework.apollo.core.utils.DeferredLoggerFactory; import com.ctrip.framework.apollo.enums.ConfigSourceType; @@ -43,7 +46,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 +115,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..62d3e9ab 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,8 @@ */ package com.ctrip.framework.apollo.internals; +import static com.ctrip.framework.apollo.monitor.internal.tracer.MessageProducerComposite.APOLLO_CONFIG_EXCEPTION; + import com.ctrip.framework.apollo.build.ApolloInjector; import com.ctrip.framework.apollo.util.factory.PropertiesFactory; import java.util.List; @@ -41,7 +43,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..741505ca --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/ConfigMonitorInitializer.java @@ -0,0 +1,113 @@ +/* + * 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.ApolloInjector; +import com.ctrip.framework.apollo.core.utils.ClassLoaderUtil; +import com.ctrip.framework.apollo.monitor.api.ConfigMonitor; +import com.ctrip.framework.apollo.monitor.internal.DefaultConfigMonitor; +import com.ctrip.framework.apollo.monitor.internal.collector.MetricsCollector; +import com.ctrip.framework.apollo.monitor.internal.collector.MetricsCollectorManager; +import com.ctrip.framework.apollo.monitor.internal.collector.internal.DefaultApolloExceptionCollector; +import com.ctrip.framework.apollo.monitor.internal.collector.internal.DefaultApolloNamespaceCollector; +import com.ctrip.framework.apollo.monitor.internal.collector.internal.DefaultApolloRunningParamsCollector; +import com.ctrip.framework.apollo.monitor.internal.collector.internal.DefaultApolloThreadPoolCollector; +import com.ctrip.framework.apollo.monitor.internal.collector.internal.DefaultMetricsCollectorManager; +import com.ctrip.framework.apollo.monitor.internal.exporter.MetricsExporter; +import com.ctrip.framework.apollo.monitor.internal.exporter.MetricsExporterFactory; +import com.ctrip.framework.apollo.monitor.internal.tracer.MessageProducerComposite; +import com.ctrip.framework.apollo.monitor.internal.tracer.MonitorMessageProducer; +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; + +/** + * @author Rawven + */ +public class ConfigMonitorInitializer { + + private static ConfigUtil m_configUtil = ApolloInjector.getInstance(ConfigUtil.class); + private static Boolean hasInitialized = false; + + public static void initializeMonitorSystem() { + if (m_configUtil.isClientMonitorEnabled() && !hasInitialized) { + DefaultMetricsCollectorManager manager = initializeMetricsCollectorManager(); + List collectors = initializeCollectors(manager); + MetricsExporter metricsExporter = initializeMetricsExporter(collectors); + initializeConfigMonitor(collectors, metricsExporter); + hasInitialized = true; + } + } + + private static DefaultMetricsCollectorManager initializeMetricsCollectorManager() { + return (DefaultMetricsCollectorManager) ApolloInjector.getInstance(MetricsCollectorManager.class); + } + + private static List initializeCollectors(DefaultMetricsCollectorManager manager) { + DefaultConfigManager configManager = (DefaultConfigManager) ApolloInjector.getInstance(ConfigManager.class); + DefaultApolloExceptionCollector exceptionCollector = new DefaultApolloExceptionCollector(); + DefaultApolloThreadPoolCollector threadPoolCollector = new DefaultApolloThreadPoolCollector( + RemoteConfigRepository.m_executorService, AbstractConfig.m_executorService, AbstractConfigFile.m_executorService); + DefaultApolloNamespaceCollector namespaceCollector = new DefaultApolloNamespaceCollector( + configManager.m_configs, configManager.m_configLocks, configManager.m_configFiles, configManager.m_configFileLocks); + DefaultApolloRunningParamsCollector startupCollector = new DefaultApolloRunningParamsCollector(m_configUtil); + + List collectors = Lists.newArrayList(exceptionCollector, namespaceCollector, threadPoolCollector, startupCollector); + manager.setCollectors(collectors); + return collectors; + } + + private static MetricsExporter initializeMetricsExporter(List collectors) { + MetricsExporterFactory reporterFactory = ApolloInjector.getInstance(MetricsExporterFactory.class); + return reporterFactory.getMetricsReporter(collectors); + } + + private static void initializeConfigMonitor(List collectors, MetricsExporter metricsExporter) { + DefaultConfigMonitor defaultConfigMonitor = (DefaultConfigMonitor) ApolloInjector.getInstance(ConfigMonitor.class); + DefaultApolloExceptionCollector exceptionCollector = (DefaultApolloExceptionCollector) collectors.get(0); + DefaultApolloNamespaceCollector namespaceCollector = (DefaultApolloNamespaceCollector) collectors.get(1); + DefaultApolloThreadPoolCollector threadPoolCollector = (DefaultApolloThreadPoolCollector) collectors.get(2); + DefaultApolloRunningParamsCollector startupCollector = (DefaultApolloRunningParamsCollector) collectors.get(3); + defaultConfigMonitor.init(namespaceCollector, threadPoolCollector, exceptionCollector, startupCollector, metricsExporter); + } + + public static MessageProducerComposite initializeMessageProducerComposite() { + + // Prioritize loading user-defined producers from SPI + List producers = ServiceBootstrap.loadAllOrdered(MessageProducer.class); + + // The producer that comes with the client + if (m_configUtil.isClientMonitorEnabled()) { + producers.add(new MonitorMessageProducer()); + } + + if (ClassLoaderUtil.isClassPresent(CatNames.CAT_CLASS)) { + producers.add(new CatMessageProducer()); + } + + // default logic + if (producers.isEmpty()) { + producers.add(new NullMessageProducer()); + } + return new MessageProducerComposite(producers); + } +} \ 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..281e440e 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,40 +16,42 @@ */ package com.ctrip.framework.apollo.internals; -import com.ctrip.framework.apollo.core.ApolloClientSystemConsts; -import com.ctrip.framework.apollo.core.ServiceNameConsts; -import com.ctrip.framework.apollo.core.utils.DeferredLoggerFactory; -import com.ctrip.framework.apollo.core.utils.DeprecatedPropertyNotifyUtil; -import com.ctrip.framework.foundation.Foundation; -import com.google.common.util.concurrent.RateLimiter; -import java.lang.reflect.Type; -import java.util.List; -import java.util.Map; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; - -import org.slf4j.Logger; +import static com.ctrip.framework.apollo.monitor.internal.tracer.MessageProducerComposite.APOLLO_CONFIG_EXCEPTION; +import static com.ctrip.framework.apollo.monitor.internal.tracer.MessageProducerComposite.APOLLO_CONFIG_SERVICES; +import static com.ctrip.framework.apollo.monitor.internal.tracer.MessageProducerComposite.APOLLO_META_SERVICE; import com.ctrip.framework.apollo.build.ApolloInjector; +import com.ctrip.framework.apollo.core.ApolloClientSystemConsts; +import com.ctrip.framework.apollo.core.ServiceNameConsts; import com.ctrip.framework.apollo.core.dto.ServiceDTO; import com.ctrip.framework.apollo.core.utils.ApolloThreadFactory; +import com.ctrip.framework.apollo.core.utils.DeferredLoggerFactory; +import com.ctrip.framework.apollo.core.utils.DeprecatedPropertyNotifyUtil; import com.ctrip.framework.apollo.exceptions.ApolloConfigException; import com.ctrip.framework.apollo.tracer.Tracer; 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.Foundation; import com.google.common.base.Joiner; import com.google.common.base.Strings; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.escape.Escaper; import com.google.common.net.UrlEscapers; +import com.google.common.util.concurrent.RateLimiter; import com.google.gson.reflect.TypeToken; +import java.lang.reflect.Type; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; +import org.slf4j.Logger; public class ConfigServiceLocator { private static final Logger logger = DeferredLoggerFactory.getLogger(ConfigServiceLocator.class); @@ -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..b859e32e 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,8 @@ */ package com.ctrip.framework.apollo.internals; +import static com.ctrip.framework.apollo.monitor.internal.tracer.MessageProducerComposite.APOLLO_CLIENT_CONFIGCHANGES; + import com.ctrip.framework.apollo.core.utils.DeferredLoggerFactory; import com.ctrip.framework.apollo.enums.ConfigSourceType; import com.google.common.collect.Maps; @@ -236,7 +238,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..54243307 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,35 +16,39 @@ */ package com.ctrip.framework.apollo.internals; -import java.util.Map; +import static com.ctrip.framework.apollo.monitor.internal.collector.internal.DefaultApolloNamespaceCollector.NAMESPACE_MONITOR; +import static com.ctrip.framework.apollo.monitor.internal.collector.internal.DefaultApolloNamespaceCollector.NAMESPACE_USAGE_COUNT; 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.monitor.internal.MonitorConstant; +import com.ctrip.framework.apollo.monitor.internal.model.MetricsEvent; import com.ctrip.framework.apollo.spi.ConfigFactory; import com.ctrip.framework.apollo.spi.ConfigFactoryManager; import com.google.common.collect.Maps; +import java.util.Map; /** * @author Jason Song(song_s@ctrip.com) */ public class DefaultConfigManager implements ConfigManager { - private ConfigFactoryManager m_factoryManager; - private Map m_configs = Maps.newConcurrentMap(); - private Map m_configLocks = Maps.newConcurrentMap(); - private Map m_configFiles = Maps.newConcurrentMap(); - private Map m_configFileLocks = Maps.newConcurrentMap(); + protected Map m_configs = Maps.newConcurrentMap(); + protected Map m_configLocks = Maps.newConcurrentMap(); + protected Map m_configFiles = Maps.newConcurrentMap(); + protected Map m_configFileLocks = Maps.newConcurrentMap(); + private ConfigFactoryManager m_factoryManager; public DefaultConfigManager() { m_factoryManager = ApolloInjector.getInstance(ConfigFactoryManager.class); + } @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) { @@ -59,11 +63,16 @@ public Config getConfig(String namespace) { } } + MetricsEvent.builder().withName(NAMESPACE_USAGE_COUNT) + .putAttachment(MonitorConstant.NAMESPACE, namespace) + .withTag(NAMESPACE_MONITOR).push(); + return config; } @Override - public ConfigFile getConfigFile(String namespace, ConfigFileFormat configFileFormat) { + public ConfigFile getConfigFile(String namespace, + ConfigFileFormat configFileFormat) { String namespaceFileName = String.format("%s.%s", namespace, configFileFormat.getValue()); ConfigFile configFile = m_configFiles.get(namespaceFileName); 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..8aae65e0 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,12 @@ 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.internals.DefaultMetricsExporterFactory; +import com.ctrip.framework.apollo.monitor.internal.collector.MetricsCollectorManager; +import com.ctrip.framework.apollo.monitor.internal.collector.internal.DefaultMetricsCollectorManager; +import com.ctrip.framework.apollo.monitor.internal.exporter.MetricsExporterFactory; import com.ctrip.framework.apollo.spi.ApolloInjectorCustomizer; import com.ctrip.framework.apollo.spi.ConfigFactory; import com.ctrip.framework.apollo.spi.ConfigFactoryManager; @@ -30,7 +36,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; @@ -38,6 +43,8 @@ import com.google.inject.Singleton; import java.util.List; +; + /** * Guice injector * @author Jason Song(song_s@ctrip.com) @@ -105,6 +112,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(MetricsCollectorManager.class).to(DefaultMetricsCollectorManager.class).in(Singleton.class); + bind(MetricsExporterFactory.class).to(DefaultMetricsExporterFactory.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..13ca7929 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,8 @@ */ package com.ctrip.framework.apollo.internals; +import static com.ctrip.framework.apollo.monitor.internal.tracer.MessageProducerComposite.APOLLO_CONFIG_EXCEPTION; + import com.ctrip.framework.apollo.core.utils.DeferredLoggerFactory; import com.ctrip.framework.apollo.enums.ConfigSourceType; import java.io.File; @@ -154,7 +156,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..1ab51080 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,9 @@ */ package com.ctrip.framework.apollo.internals; +import static com.ctrip.framework.apollo.monitor.internal.MonitorConstant.NAMESPACE; +import static com.ctrip.framework.apollo.monitor.internal.tracer.MessageProducerComposite.APOLLO_CONFIG_EXCEPTION; + import com.ctrip.framework.apollo.build.ApolloInjector; import com.ctrip.framework.apollo.core.ConfigConsts; import com.ctrip.framework.apollo.core.dto.ApolloConfigNotification; @@ -28,14 +31,16 @@ import com.ctrip.framework.apollo.core.utils.ApolloThreadFactory; import com.ctrip.framework.apollo.core.utils.StringUtils; import com.ctrip.framework.apollo.exceptions.ApolloConfigException; +import com.ctrip.framework.apollo.monitor.internal.collector.internal.DefaultApolloNamespaceCollector; +import com.ctrip.framework.apollo.monitor.internal.model.MetricsEvent; import com.ctrip.framework.apollo.spi.ConfigServiceLoadBalancerClient; import com.ctrip.framework.apollo.tracer.Tracer; 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 +55,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 +215,14 @@ 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) { + MetricsEvent.builder().withName(DefaultApolloNamespaceCollector.NAMESPACE_TIMEOUT) + .putAttachment(NAMESPACE, assembleNamespaces()) + .withTag(DefaultApolloNamespaceCollector.NAMESPACE_MONITOR).push(); + } 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..6ca75336 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,15 @@ */ package com.ctrip.framework.apollo.internals; +import static com.ctrip.framework.apollo.monitor.internal.MonitorConstant.NAMESPACE; +import static com.ctrip.framework.apollo.monitor.internal.MonitorConstant.TIMESTAMP; +import static com.ctrip.framework.apollo.monitor.internal.collector.internal.DefaultApolloNamespaceCollector.NAMESPACE_MONITOR; +import static com.ctrip.framework.apollo.monitor.internal.tracer.MessageProducerComposite.APOLLO_CLIENT_CONFIGS; +import static com.ctrip.framework.apollo.monitor.internal.tracer.MessageProducerComposite.APOLLO_CLIENT_CONFIGMETA; +import static com.ctrip.framework.apollo.monitor.internal.tracer.MessageProducerComposite.APOLLO_CLIENT_VERSION; +import static com.ctrip.framework.apollo.monitor.internal.tracer.MessageProducerComposite.APOLLO_CONFIGSERVICE; +import static com.ctrip.framework.apollo.monitor.internal.tracer.MessageProducerComposite.APOLLO_CONFIG_EXCEPTION; + import com.ctrip.framework.apollo.Apollo; import com.ctrip.framework.apollo.build.ApolloInjector; import com.ctrip.framework.apollo.core.ConfigConsts; @@ -31,13 +40,15 @@ import com.ctrip.framework.apollo.enums.ConfigSourceType; import com.ctrip.framework.apollo.exceptions.ApolloConfigException; import com.ctrip.framework.apollo.exceptions.ApolloConfigStatusCodeException; +import com.ctrip.framework.apollo.monitor.internal.collector.internal.DefaultApolloNamespaceCollector; +import com.ctrip.framework.apollo.monitor.internal.model.MetricsEvent; import com.ctrip.framework.apollo.tracer.Tracer; 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 +84,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 +122,12 @@ public RemoteConfigRepository(String namespace) { @Override public Properties getConfig() { if (m_configCache.get() == null) { + long start = System.currentTimeMillis(); this.sync(); + MetricsEvent.builder().withName(DefaultApolloNamespaceCollector.NAMESPACE_FIRST_LOAD_SPEND).withTag( + NAMESPACE_MONITOR) + .putAttachment(NAMESPACE, m_namespace) + .putAttachment(TIMESTAMP, System.currentTimeMillis() - start).push(); } return transformApolloConfigToProperties(m_configCache.get()); } @@ -133,10 +149,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()); @@ -147,6 +163,7 @@ protected synchronized void sync() { Transaction transaction = Tracer.newTransaction("Apollo.ConfigService", "syncRemoteConfig"); try { + ApolloConfig previous = m_configCache.get(); ApolloConfig current = loadApolloConfig(); @@ -155,10 +172,11 @@ protected synchronized void sync() { logger.debug("Remote Config refreshed!"); m_configCache.set(current); this.fireRepositoryChange(m_namespace, this.getConfig()); + } 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 +207,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 +278,17 @@ private ApolloConfig loadApolloConfig() { appId, cluster, m_namespace); statusCodeException = new ApolloConfigStatusCodeException(ex.getStatusCode(), message); + MetricsEvent.builder().withName(DefaultApolloNamespaceCollector.NAMESPACE_NOT_FOUND).withTag( + NAMESPACE_MONITOR).putAttachment(NAMESPACE, m_namespace).push(); } - 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..10ba29af 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,8 @@ */ package com.ctrip.framework.apollo.internals; +import static com.ctrip.framework.apollo.monitor.internal.tracer.MessageProducerComposite.APOLLO_CLIENT_CONFIGCHANGES; + import com.ctrip.framework.apollo.enums.ConfigSourceType; import java.util.Collections; import java.util.List; @@ -113,7 +115,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..d7757895 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,8 @@ */ package com.ctrip.framework.apollo.internals; +import static com.ctrip.framework.apollo.monitor.internal.tracer.MessageProducerComposite.APOLLO_CONFIG_EXCEPTION; + import com.ctrip.framework.apollo.util.ExceptionUtil; import java.util.Properties; @@ -65,7 +67,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/ApolloExceptionMonitorApi.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/api/ApolloExceptionMonitorApi.java new file mode 100644 index 00000000..6a826a56 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/api/ApolloExceptionMonitorApi.java @@ -0,0 +1,38 @@ +/* + * 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; +import javax.management.MXBean; + +/** + * @author Rawven + */ +@MXBean +public interface ApolloExceptionMonitorApi { + + + /** + * get the number of exceptions + */ + Integer getExceptionNum(); + + /** + * get exception details + */ + List getExceptionDetails(); +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/api/ApolloNamespaceMonitorApi.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/api/ApolloNamespaceMonitorApi.java new file mode 100644 index 00000000..d9ce8ee9 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/api/ApolloNamespaceMonitorApi.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.api; + +import java.util.List; +import javax.management.MXBean; + +/** + * @author Rawven + */ +@MXBean +public interface ApolloNamespaceMonitorApi { + + String getNamespaceReleaseKey(String namespace); + + long getNamespaceUsageCount(String namespace); + + String getNamespaceLatestUpdateTime(String namespace); + + long getNamespaceFirstLoadSpend(String namespace); + + String getNamespace404(); + + String getNamespaceTimeout(); + + List getNamespaceItemName(String namespace); + + List getAllNamespaceReleaseKey(); + + List getAllNamespaceUsageCount(); + + List getAllNamespacesLatestUpdateTime(); + + List getAllUsedNamespaceName(); + + List getAllNamespaceFirstLoadSpend(); + + List getAllNamespaceItemName(); +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/api/ApolloRunningParamsMonitorApi.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/api/ApolloRunningParamsMonitorApi.java new file mode 100644 index 00000000..ff9e2205 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/api/ApolloRunningParamsMonitorApi.java @@ -0,0 +1,70 @@ +/* + * 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 javax.management.MXBean; + +/** + * @author Rawven + */ +@MXBean +public interface ApolloRunningParamsMonitorApi { + + String getStartupParams(String key); + + String getConfigServiceUrl(); + + String getAccessKeySecret(); + + Boolean getAutoUpdateInjectedSpringProperties(); + + Boolean getBootstrapEnabled(); + + String getBootstrapNamespaces(); + + Boolean getBootstrapEagerLoadEnabled(); + + Boolean getOverrideSystemProperties(); + + String getCacheDir(); + + String getCluster(); + + String getConfigService(); + + Boolean getClientMonitorEnabled(); + + Boolean getClientMonitorJmxEnabled(); + + String getClientMonitorExternalForm(); + + long getClientMonitorExternalExportPeriod(); + + String getMeta(); + + String getMetaLatestFreshTime(); + + Boolean getPropertyNamesCacheEnable(); + + Boolean getPropertyOrderEnable(); + + String getVersion(); + + String getEnv(); + + String getAppId(); +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/api/ApolloThreadPoolMonitorApi.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/api/ApolloThreadPoolMonitorApi.java new file mode 100644 index 00000000..33c09e77 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/api/ApolloThreadPoolMonitorApi.java @@ -0,0 +1,89 @@ +/* + * 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 javax.management.MXBean; + +/** + * @author Rawven + */ +@MXBean +public interface ApolloThreadPoolMonitorApi { + + + int getRemoteConfigRepositoryThreadPoolActiveCount(); + + int getRemoteConfigRepositoryThreadPoolQueueSize(); + + int getRemoteConfigRepositoryThreadPoolCorePoolSize(); + + int getRemoteConfigRepositoryThreadPoolMaximumPoolSize(); + + int getRemoteConfigRepositoryThreadPoolPoolSize(); + + long getRemoteConfigRepositoryThreadPoolTaskCount(); + + long getRemoteConfigRepositoryThreadPoolCompletedTaskCount(); + + int getRemoteConfigRepositoryThreadPoolLargestPoolSize(); + + int getRemoteConfigRepositoryThreadPoolRemainingCapacity(); + + double getRemoteConfigRepositoryThreadPoolCurrentLoad(); + + int getAbstractConfigThreadPoolActiveCount(); + + int getAbstractConfigThreadPoolQueueSize(); + + int getAbstractConfigThreadPoolCorePoolSize(); + + int getAbstractConfigThreadPoolMaximumPoolSize(); + + int getAbstractConfigThreadPoolPoolSize(); + + long getAbstractConfigThreadPoolTaskCount(); + + long getAbstractConfigThreadPoolCompletedTaskCount(); + + int getAbstractConfigThreadPoolLargestPoolSize(); + + int getAbstractConfigThreadPoolRemainingCapacity(); + + double getAbstractConfigThreadPoolCurrentLoad(); + + + int getAbstractConfigFileThreadPoolActiveCount(); + + int getAbstractConfigFileThreadPoolQueueSize(); + + int getAbstractConfigFileThreadPoolCorePoolSize(); + + int getAbstractConfigFileThreadPoolMaximumPoolSize(); + + int getAbstractConfigFileThreadPoolPoolSize(); + + long getAbstractConfigFileThreadPoolTaskCount(); + + long getAbstractConfigFileThreadPoolCompletedTaskCount(); + + int getAbstractConfigFileThreadPoolLargestPoolSize(); + + int getAbstractConfigFileThreadPoolRemainingCapacity(); + + double getAbstractConfigFileThreadPoolCurrentLoad(); + +} 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..898f7739 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/api/ConfigMonitor.java @@ -0,0 +1,33 @@ +/* + * 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 { + + ApolloThreadPoolMonitorApi getThreadPoolMonitorApi(); + + ApolloExceptionMonitorApi getExceptionMonitorApi(); + + ApolloNamespaceMonitorApi getNamespaceMonitorApi(); + + ApolloRunningParamsMonitorApi getRunningParamsMonitorApi(); + + String getDataWithCurrentMonitoringSystemFormat(); +} 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..bb997e4f --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/DefaultConfigMonitor.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; + +import com.ctrip.framework.apollo.monitor.api.ApolloExceptionMonitorApi; +import com.ctrip.framework.apollo.monitor.api.ApolloNamespaceMonitorApi; +import com.ctrip.framework.apollo.monitor.api.ApolloRunningParamsMonitorApi; +import com.ctrip.framework.apollo.monitor.api.ApolloThreadPoolMonitorApi; +import com.ctrip.framework.apollo.monitor.api.ConfigMonitor; +import com.ctrip.framework.apollo.monitor.internal.exporter.MetricsExporter; + +/** + * exposes all collected data through ConfigService + * + * @author Rawven + */ +public class DefaultConfigMonitor implements ConfigMonitor { + + private MetricsExporter reporter; + private ApolloThreadPoolMonitorApi threadPoolMonitorApi; + private ApolloExceptionMonitorApi exceptionMonitorApi; + private ApolloNamespaceMonitorApi apolloNamespaceMonitorApi; + private ApolloRunningParamsMonitorApi apolloRunningParamsMonitorApi; + + @Override + public ApolloThreadPoolMonitorApi getThreadPoolMonitorApi() { + return threadPoolMonitorApi; + } + + @Override + public ApolloExceptionMonitorApi getExceptionMonitorApi() { + return exceptionMonitorApi; + } + + @Override + public ApolloNamespaceMonitorApi getNamespaceMonitorApi() { + return apolloNamespaceMonitorApi; + } + + @Override + public ApolloRunningParamsMonitorApi getRunningParamsMonitorApi() { + return apolloRunningParamsMonitorApi; + } + + @Override + public String getDataWithCurrentMonitoringSystemFormat() { + if (reporter == null) { + return "No MonitoringSystem Use"; + } + return reporter.response(); + } + + public void init(ApolloNamespaceMonitorApi apolloNamespaceMonitorApi, + ApolloThreadPoolMonitorApi threadPoolMonitorApi, + ApolloExceptionMonitorApi exceptionMonitorApi, + ApolloRunningParamsMonitorApi apolloRunningParamsMonitorApi, + MetricsExporter reporter) { + this.apolloNamespaceMonitorApi = apolloNamespaceMonitorApi; + this.threadPoolMonitorApi = threadPoolMonitorApi; + this.exceptionMonitorApi = exceptionMonitorApi; + this.apolloRunningParamsMonitorApi = apolloRunningParamsMonitorApi; + this.reporter = reporter; + } +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/MonitorConstant.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/MonitorConstant.java new file mode 100644 index 00000000..ea289e1f --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/MonitorConstant.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; + +/** + * metrics constant + * + * @author Rawven + */ +public class MonitorConstant { + + public static final String NAMESPACE = "namespace"; + public static final String TIMESTAMP = "timestamp"; + public static final String MBEAN_NAME = "apollo.client.monitor:type="; +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/NullConfigMonitor.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/NullConfigMonitor.java new file mode 100644 index 00000000..84f6d6d8 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/NullConfigMonitor.java @@ -0,0 +1,58 @@ +/* + * 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.ApolloExceptionMonitorApi; +import com.ctrip.framework.apollo.monitor.api.ApolloNamespaceMonitorApi; +import com.ctrip.framework.apollo.monitor.api.ApolloRunningParamsMonitorApi; +import com.ctrip.framework.apollo.monitor.api.ApolloThreadPoolMonitorApi; +import com.ctrip.framework.apollo.monitor.api.ConfigMonitor; + +/** + * null config monitor + */ +public class NullConfigMonitor implements ConfigMonitor { + private ApolloThreadPoolMonitorApi threadPoolMonitorApi = new NullThreadPoolMonitorApi(); + private ApolloExceptionMonitorApi exceptionMonitorApi = new NullExceptionMonitorApi(); + private ApolloNamespaceMonitorApi apolloNamespaceMonitorApi = new NullNamespaceMonitorApi(); + private ApolloRunningParamsMonitorApi apolloRunningParamsMonitorApi = new NullRunningParamsMonitorApi(); + + @Override + public ApolloThreadPoolMonitorApi getThreadPoolMonitorApi() { + return threadPoolMonitorApi; + } + + @Override + public ApolloExceptionMonitorApi getExceptionMonitorApi() { + return exceptionMonitorApi; + } + + @Override + public ApolloNamespaceMonitorApi getNamespaceMonitorApi() { + return apolloNamespaceMonitorApi; + } + + @Override + public ApolloRunningParamsMonitorApi getRunningParamsMonitorApi() { + return apolloRunningParamsMonitorApi; + } + + @Override + public String getDataWithCurrentMonitoringSystemFormat() { + return ""; + } +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/NullExceptionMonitorApi.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/NullExceptionMonitorApi.java new file mode 100644 index 00000000..5480081e --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/NullExceptionMonitorApi.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; + +import com.ctrip.framework.apollo.monitor.api.ApolloExceptionMonitorApi; +import java.util.Collections; +import java.util.List; + +public class NullExceptionMonitorApi implements ApolloExceptionMonitorApi { + + @Override + public Integer getExceptionNum() { + return 0; + } + + @Override + public List getExceptionDetails() { + return Collections.emptyList(); + } +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/NullNamespaceMonitorApi.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/NullNamespaceMonitorApi.java new file mode 100644 index 00000000..5377b6d9 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/NullNamespaceMonitorApi.java @@ -0,0 +1,89 @@ +/* + * 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.ApolloNamespaceMonitorApi; +import java.util.Collections; +import java.util.List; + +public class NullNamespaceMonitorApi implements ApolloNamespaceMonitorApi { + + @Override + public String getNamespaceReleaseKey(String namespace) { + return ""; + } + + @Override + public long getNamespaceUsageCount(String namespace) { + return 0; + } + + @Override + public String getNamespaceLatestUpdateTime(String namespace) { + return ""; + } + + @Override + public long getNamespaceFirstLoadSpend(String namespace) { + return 0; + } + + @Override + public String getNamespace404() { + return ""; + } + + @Override + public String getNamespaceTimeout() { + return ""; + } + + @Override + public List getNamespaceItemName(String namespace) { + return Collections.emptyList(); + } + + @Override + public List getAllNamespaceReleaseKey() { + return Collections.emptyList(); + } + + @Override + public List getAllNamespaceUsageCount() { + return Collections.emptyList(); + } + + @Override + public List getAllNamespacesLatestUpdateTime() { + return Collections.emptyList(); + } + + @Override + public List getAllUsedNamespaceName() { + return Collections.emptyList(); + } + + @Override + public List getAllNamespaceFirstLoadSpend() { + return Collections.emptyList(); + } + + @Override + public List getAllNamespaceItemName() { + return Collections.emptyList(); + } +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/NullRunningParamsMonitorApi.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/NullRunningParamsMonitorApi.java new file mode 100644 index 00000000..d5a019d5 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/NullRunningParamsMonitorApi.java @@ -0,0 +1,132 @@ +/* + * 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.ApolloRunningParamsMonitorApi; + +public class NullRunningParamsMonitorApi implements ApolloRunningParamsMonitorApi { + + @Override + public String getStartupParams(String key) { + return ""; + } + + @Override + public String getConfigServiceUrl() { + return ""; + } + + @Override + public String getAccessKeySecret() { + return ""; + } + + @Override + public Boolean getAutoUpdateInjectedSpringProperties() { + return null; + } + + @Override + public Boolean getBootstrapEnabled() { + return null; + } + + @Override + public String getBootstrapNamespaces() { + return ""; + } + + @Override + public Boolean getBootstrapEagerLoadEnabled() { + return null; + } + + @Override + public Boolean getOverrideSystemProperties() { + return null; + } + + @Override + public String getCacheDir() { + return ""; + } + + @Override + public String getCluster() { + return ""; + } + + @Override + public String getConfigService() { + return ""; + } + + @Override + public Boolean getClientMonitorEnabled() { + return null; + } + + @Override + public Boolean getClientMonitorJmxEnabled() { + return null; + } + + @Override + public String getClientMonitorExternalForm() { + return ""; + } + + @Override + public long getClientMonitorExternalExportPeriod() { + return 0; + } + + @Override + public String getMeta() { + return ""; + } + + @Override + public String getMetaLatestFreshTime() { + return ""; + } + + @Override + public Boolean getPropertyNamesCacheEnable() { + return null; + } + + @Override + public Boolean getPropertyOrderEnable() { + return null; + } + + @Override + public String getVersion() { + return ""; + } + + @Override + public String getEnv() { + return ""; + } + + @Override + public String getAppId() { + return ""; + } +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/NullThreadPoolMonitorApi.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/NullThreadPoolMonitorApi.java new file mode 100644 index 00000000..34384df0 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/NullThreadPoolMonitorApi.java @@ -0,0 +1,172 @@ +/* + * 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.ApolloThreadPoolMonitorApi; + +public class NullThreadPoolMonitorApi implements ApolloThreadPoolMonitorApi { + + @Override + public int getRemoteConfigRepositoryThreadPoolActiveCount() { + return 0; + } + + @Override + public int getRemoteConfigRepositoryThreadPoolQueueSize() { + return 0; + } + + @Override + public int getRemoteConfigRepositoryThreadPoolCorePoolSize() { + return 0; + } + + @Override + public int getRemoteConfigRepositoryThreadPoolMaximumPoolSize() { + return 0; + } + + @Override + public int getRemoteConfigRepositoryThreadPoolPoolSize() { + return 0; + } + + @Override + public long getRemoteConfigRepositoryThreadPoolTaskCount() { + return 0; + } + + @Override + public long getRemoteConfigRepositoryThreadPoolCompletedTaskCount() { + return 0; + } + + @Override + public int getRemoteConfigRepositoryThreadPoolLargestPoolSize() { + return 0; + } + + @Override + public int getRemoteConfigRepositoryThreadPoolRemainingCapacity() { + return 0; + } + + @Override + public double getRemoteConfigRepositoryThreadPoolCurrentLoad() { + return 0; + } + + @Override + public int getAbstractConfigThreadPoolActiveCount() { + return 0; + } + + @Override + public int getAbstractConfigThreadPoolQueueSize() { + return 0; + } + + @Override + public int getAbstractConfigThreadPoolCorePoolSize() { + return 0; + } + + @Override + public int getAbstractConfigThreadPoolMaximumPoolSize() { + return 0; + } + + @Override + public int getAbstractConfigThreadPoolPoolSize() { + return 0; + } + + @Override + public long getAbstractConfigThreadPoolTaskCount() { + return 0; + } + + @Override + public long getAbstractConfigThreadPoolCompletedTaskCount() { + return 0; + } + + @Override + public int getAbstractConfigThreadPoolLargestPoolSize() { + return 0; + } + + @Override + public int getAbstractConfigThreadPoolRemainingCapacity() { + return 0; + } + + @Override + public double getAbstractConfigThreadPoolCurrentLoad() { + return 0; + } + + @Override + public int getAbstractConfigFileThreadPoolActiveCount() { + return 0; + } + + @Override + public int getAbstractConfigFileThreadPoolQueueSize() { + return 0; + } + + @Override + public int getAbstractConfigFileThreadPoolCorePoolSize() { + return 0; + } + + @Override + public int getAbstractConfigFileThreadPoolMaximumPoolSize() { + return 0; + } + + @Override + public int getAbstractConfigFileThreadPoolPoolSize() { + return 0; + } + + @Override + public long getAbstractConfigFileThreadPoolTaskCount() { + return 0; + } + + @Override + public long getAbstractConfigFileThreadPoolCompletedTaskCount() { + return 0; + } + + @Override + public int getAbstractConfigFileThreadPoolLargestPoolSize() { + return 0; + } + + @Override + public int getAbstractConfigFileThreadPoolRemainingCapacity() { + return 0; + } + + @Override + public double getAbstractConfigFileThreadPoolCurrentLoad() { + return 0; + } +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/collector/AbstractMetricsCollector.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/collector/AbstractMetricsCollector.java new file mode 100644 index 00000000..55314f78 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/collector/AbstractMetricsCollector.java @@ -0,0 +1,80 @@ +/* + * 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.collector; + +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.MetricsEvent; +import com.ctrip.framework.apollo.monitor.internal.model.MetricsModel; +import com.google.common.collect.Maps; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * 抽象的 Metrics 收集器 用于收集和导出指标样本 + * + * @author Rawven + */ +public abstract class AbstractMetricsCollector implements MetricsCollector { + + protected final Map counterSamples = Maps.newHashMap(); + protected final Map gaugeSamples = Maps.newHashMap(); + private final AtomicBoolean isUpdated = new AtomicBoolean(); + private final List tags; + private final String name; + + public AbstractMetricsCollector(String name, String... tags) { + this.name = name; + this.tags = Arrays.asList(tags); + } + + @Override + public String name() { + return name; + } + + @Override + public boolean isSupport(MetricsEvent event) { + return tags.contains(event.getTag()); + } + + @Override + public void collect(MetricsEvent event) { + collect0(event); + isUpdated.set(true); + } + + @Override + public boolean isSamplesUpdated() { + return isUpdated.getAndSet(false); + } + + @Override + public List export() { + export0(); + List samples = new ArrayList<>(counterSamples.values()); + samples.addAll(gaugeSamples.values()); + return samples; + } + + protected abstract void collect0(MetricsEvent event); + + protected abstract void export0(); +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/collector/MetricsCollector.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/collector/MetricsCollector.java new file mode 100644 index 00000000..e1efd0d2 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/collector/MetricsCollector.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.collector; + +import com.ctrip.framework.apollo.monitor.internal.model.MetricsEvent; +import com.ctrip.framework.apollo.monitor.internal.model.MetricsModel; +import java.util.List; + +/** + * @author Rawven + */ +public interface MetricsCollector { + + + String name(); + + /** + * is support the event + */ + boolean isSupport(MetricsEvent event); + + /** + * collect metrics from event + */ + void collect(MetricsEvent event); + + /** + * is samples updated + */ + boolean isSamplesUpdated(); + + /** + * 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/collector/MetricsCollectorManager.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/collector/MetricsCollectorManager.java new file mode 100644 index 00000000..75a28aa5 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/collector/MetricsCollectorManager.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.collector; + +import com.ctrip.framework.apollo.core.spi.Ordered; +import java.util.List; + +/** + * @author Rawven + */ +public interface MetricsCollectorManager extends Ordered { + + /** + * get collectors + */ + List getCollectors(); + + @Override + default int getOrder() { + return 0; + } +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/collector/internal/DefaultApolloExceptionCollector.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/collector/internal/DefaultApolloExceptionCollector.java new file mode 100644 index 00000000..aad5783f --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/collector/internal/DefaultApolloExceptionCollector.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.collector.internal; + +import static com.ctrip.framework.apollo.monitor.internal.tracer.MessageProducerComposite.ERROR_METRICS; +import static com.ctrip.framework.apollo.monitor.internal.tracer.MessageProducerComposite.THROWABLE; + +import com.ctrip.framework.apollo.exceptions.ApolloConfigException; +import com.ctrip.framework.apollo.monitor.api.ApolloExceptionMonitorApi; +import com.ctrip.framework.apollo.monitor.internal.collector.AbstractMetricsCollector; +import com.ctrip.framework.apollo.monitor.internal.model.CounterModel; +import com.ctrip.framework.apollo.monitor.internal.model.MetricsEvent; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * @author Rawven + */ +public class DefaultApolloExceptionCollector extends AbstractMetricsCollector implements + ApolloExceptionMonitorApi { + + public static final String EXCEPTION_NUM = "exception_num"; + + private static final int MAX_EXCEPTIONS_SIZE = 25; + private final BlockingQueue exceptions = new ArrayBlockingQueue<>( + MAX_EXCEPTIONS_SIZE); + + private final AtomicInteger exceptionNum = new AtomicInteger(0); + + public DefaultApolloExceptionCollector() { + super(ERROR_METRICS, ERROR_METRICS); + } + + @Override + public Integer getExceptionNum() { + return exceptionNum.get(); + } + + @Override + public List getExceptionDetails() { + List exceptionDetails = new ArrayList<>(); + for (ApolloConfigException exception : exceptions) { + exceptionDetails.add(exception.getMessage()); + } + return exceptionDetails; + } + + @Override + public void collect0(MetricsEvent event) { + ApolloConfigException exception = event.getAttachmentValue(THROWABLE); + if (exceptions.size() >= MAX_EXCEPTIONS_SIZE) { + exceptions.poll(); + } + exceptions.add(exception); + exceptionNum.incrementAndGet(); + } + + @Override + public void export0() { + if (!counterSamples.containsKey(EXCEPTION_NUM)) { + counterSamples.put(EXCEPTION_NUM, CounterModel.builder().name(EXCEPTION_NUM).value(0) + .build()); + } + counterSamples.get(EXCEPTION_NUM).updateValue(exceptionNum.get()); + } + +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/collector/internal/DefaultApolloNamespaceCollector.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/collector/internal/DefaultApolloNamespaceCollector.java new file mode 100644 index 00000000..e7a81ffb --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/collector/internal/DefaultApolloNamespaceCollector.java @@ -0,0 +1,296 @@ +/* + * 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.collector.internal; + + +import static com.ctrip.framework.apollo.monitor.internal.MonitorConstant.NAMESPACE; +import static com.ctrip.framework.apollo.monitor.internal.model.GaugeModel.intConverter; +import static com.ctrip.framework.apollo.monitor.internal.model.GaugeModel.longConverter; + +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.monitor.api.ApolloNamespaceMonitorApi; +import com.ctrip.framework.apollo.monitor.internal.MonitorConstant; +import com.ctrip.framework.apollo.monitor.internal.collector.AbstractMetricsCollector; +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.MetricsEvent; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.ToDoubleFunction; +import org.slf4j.Logger; + +/** + * @author Rawven + */ +public class DefaultApolloNamespaceCollector extends AbstractMetricsCollector implements + ApolloNamespaceMonitorApi { + + public static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern( + "yyyy-MM-dd HH:mm:ss").withZone(ZoneId.systemDefault()); + public static final String NAMESPACE_MONITOR = "namespace_monitor"; + public static final String NAMESPACE_LATEST_UPDATE_TIME = "namespace_latest_update_time"; + public static final String NAMESPACE_FIRST_LOAD_SPEND = "namespace_first_load_spend_time"; + public static final String NAMESPACE_USAGE_COUNT = "namespace_usage_count"; + public static final String NAMESPACE_RELEASE_KEY = "namespace_release_key"; + public static final String NAMESPACE_ITEM_NUM = "namespace_item_num"; + public static final String CONFIG_FILE_NUM = "config_file_num"; + public static final String NAMESPACE_NOT_FOUND = "namespace_not_found"; + public static final String NAMESPACE_TIMEOUT = "namespace_timeout"; + private static final Logger logger = DeferredLoggerFactory.getLogger( + DefaultApolloNamespaceCollector.class); + private final Map m_configs; + private final Map m_configLocks; + private final Map m_configFiles; + private final Map m_configFileLocks; + private final Map namespaces = Maps.newConcurrentMap(); + private final List namespace404 = Lists.newCopyOnWriteArrayList(); + private final List namespaceTimeout = Lists.newCopyOnWriteArrayList(); + + public DefaultApolloNamespaceCollector(Map m_configs, + Map m_configLocks, + Map m_configFiles, + Map m_configFileLocks) { + super(NAMESPACE_MONITOR, NAMESPACE_MONITOR); + this.m_configs = m_configs; + this.m_configLocks = m_configLocks; + this.m_configFiles = m_configFiles; + this.m_configFileLocks = m_configFileLocks; + } + + + @Override + public void collect0(MetricsEvent event) { + String namespace = event.getAttachmentValue(NAMESPACE); + NamespaceMetrics namespaceMetrics = namespaces.computeIfAbsent(namespace, + k -> new NamespaceMetrics()); + switch (event.getName()) { + case NAMESPACE_USAGE_COUNT: + namespaceMetrics.incrementUsageCount(); + break; + case NAMESPACE_LATEST_UPDATE_TIME: + long updateTime = event.getAttachmentValue(MonitorConstant.TIMESTAMP); + namespaceMetrics.setLatestUpdateTime(updateTime); + break; + case NAMESPACE_FIRST_LOAD_SPEND: + long firstLoadSpendTime = event.getAttachmentValue(MonitorConstant.TIMESTAMP); + namespaceMetrics.setFirstLoadSpend(firstLoadSpendTime); + break; + case NAMESPACE_RELEASE_KEY: + String releaseKey = event.getAttachmentValue(NAMESPACE_RELEASE_KEY); + namespaceMetrics.setReleaseKey(releaseKey); + break; + case NAMESPACE_TIMEOUT: + namespaceTimeout.add(namespace); + break; + case NAMESPACE_NOT_FOUND: + namespace404.add(namespace); + break; + default: + logger.warn("Unknown event: {}", event); + break; + } + } + + @Override + public void export0() { + namespaces.forEach((k, v) -> { + updateCounterSample(NAMESPACE_USAGE_COUNT, k, v.getUsageCount()); + updateGaugeSample(NAMESPACE_FIRST_LOAD_SPEND, k, v.getFirstLoadSpend(), + longConverter); + updateGaugeSample(NAMESPACE_LATEST_UPDATE_TIME, k, v.getLatestUpdateTime(), + longConverter); + updateGaugeSample(NAMESPACE_ITEM_NUM, k, m_configs.get(k).getPropertyNames().size(), + intConverter); + updateGaugeSample(CONFIG_FILE_NUM, k, m_configFiles.size(), intConverter); + }); + updateGaugeSample(NAMESPACE_NOT_FOUND, "", namespace404.size(), intConverter); + updateGaugeSample(NAMESPACE_TIMEOUT, "", namespaceTimeout.size(), intConverter); + } + + private void updateCounterSample(String key, String namespace, double value) { + String mapKey = namespace + key; + if (!counterSamples.containsKey(mapKey)) { + CounterModel.CounterBuilder builder = CounterModel.builder().name(key).value(0); + if (!namespace.isEmpty()) { + builder.putTag(NAMESPACE, namespace); + } + counterSamples.put(mapKey, builder.build()); + } + counterSamples.get(mapKey).updateValue(value); + } + + @SuppressWarnings("unchecked") + private void updateGaugeSample(String key, String namespace, Object value, + ToDoubleFunction applyFunction) { + String mapKey = namespace + key; + if (!gaugeSamples.containsKey(mapKey)) { + GaugeModel.GaugeBuilder builder = GaugeModel.builder().name(key).value(0) + .apply(applyFunction); + if (!namespace.isEmpty()) { + builder.putTag(NAMESPACE, namespace); + } + gaugeSamples.put(mapKey, builder.build()); + } + gaugeSamples.get(mapKey).updateValue(value); + } + + + @Override + public String getNamespaceReleaseKey(String namespace) { + NamespaceMetrics namespaceMetrics = namespaces.get(namespace); + return namespaceMetrics == null ? null : namespaceMetrics.getReleaseKey(); + } + + @Override + public long getNamespaceUsageCount(String namespace) { + NamespaceMetrics namespaceMetrics = namespaces.get(namespace); + return namespaceMetrics == null ? 0 : namespaceMetrics.getUsageCount(); + } + + @Override + public String getNamespaceLatestUpdateTime(String namespace) { + NamespaceMetrics namespaceMetrics = namespaces.get(namespace); + return namespaceMetrics == null ? null + : DATE_FORMATTER.format(Instant.ofEpochMilli(namespaceMetrics.getLatestUpdateTime())); + } + + @Override + public long getNamespaceFirstLoadSpend(String namespace) { + NamespaceMetrics namespaceMetrics = namespaces.get(namespace); + return namespaceMetrics == null ? 0 : namespaceMetrics.getFirstLoadSpend(); + } + + @Override + public String getNamespace404() { + return namespace404.toString(); + } + + @Override + public String getNamespaceTimeout() { + return namespaceTimeout.toString(); + } + + @Override + public List getNamespaceItemName(String namespace) { + Config config = m_configs.get(namespace); + return config == null ? Collections.emptyList() : new ArrayList<>(config.getPropertyNames()); + } + + @Override + public List getAllNamespaceReleaseKey() { + List releaseKeys = Lists.newArrayList(); + namespaces.forEach((k, v) -> releaseKeys.add(k + ":" + v.getReleaseKey())); + return releaseKeys; + } + + @Override + public List getAllNamespaceUsageCount() { + List usedTimes = Lists.newArrayList(); + namespaces.forEach((k, v) -> usedTimes.add(k + ":" + v.getUsageCount())); + return usedTimes; + } + + @Override + public List getAllNamespacesLatestUpdateTime() { + List latestUpdateTimes = Lists.newArrayList(); + namespaces.forEach((k, v) -> latestUpdateTimes.add( + k + ":" + DATE_FORMATTER.format(Instant.ofEpochMilli(v.getLatestUpdateTime())))); + return latestUpdateTimes; + } + + @Override + public List getAllUsedNamespaceName() { + ArrayList namespaces = Lists.newArrayList(); + m_configs.forEach((k, v) -> namespaces.add(k)); + return namespaces; + } + + @Override + public List getAllNamespaceFirstLoadSpend() { + List firstLoadSpends = Lists.newArrayList(); + namespaces.forEach((k, v) -> firstLoadSpends.add( + k + ":" + v.getFirstLoadSpend())); + return firstLoadSpends; + } + + @Override + public List getAllNamespaceItemName() { + List namespaceItems = Lists.newArrayList(); + m_configs.forEach((k, v) -> namespaceItems.add(v.getPropertyNames().toString())); + return namespaceItems; + } + + public static class NamespaceMetrics { + + private int usageCount; + private long firstLoadSpend; + private long latestUpdateTime = System.currentTimeMillis(); + private String releaseKey = "default"; + + public String getReleaseKey() { + return releaseKey; + } + + public void setReleaseKey(String releaseKey) { + this.releaseKey = releaseKey; + } + + @Override + public String toString() { + return "NamespaceMetrics{" + + "usageCount=" + usageCount + + ", firstLoadSpend=" + firstLoadSpend + + ", latestUpdateTime=" + latestUpdateTime + + ", releaseKey='" + releaseKey + '\'' + + '}'; + } + + public int getUsageCount() { + return usageCount; + } + + public void incrementUsageCount() { + this.usageCount++; + } + + public long getFirstLoadSpend() { + return firstLoadSpend; + } + + public void setFirstLoadSpend(long firstLoadSpend) { + this.firstLoadSpend = firstLoadSpend; + } + + public long getLatestUpdateTime() { + return latestUpdateTime; + } + + public void setLatestUpdateTime(long latestUpdateTime) { + this.latestUpdateTime = latestUpdateTime; + } + } + +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/collector/internal/DefaultApolloRunningParamsCollector.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/collector/internal/DefaultApolloRunningParamsCollector.java new file mode 100644 index 00000000..a5133af5 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/collector/internal/DefaultApolloRunningParamsCollector.java @@ -0,0 +1,230 @@ +/* + * 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.collector.internal; + +import static com.ctrip.framework.apollo.core.ApolloClientSystemConsts.APOLLO_ACCESS_KEY_SECRET; +import static com.ctrip.framework.apollo.core.ApolloClientSystemConsts.APOLLO_CACHE_DIR; +import static com.ctrip.framework.apollo.core.ApolloClientSystemConsts.APOLLO_CLIENT_MONITOR_ENABLED; +import static com.ctrip.framework.apollo.core.ApolloClientSystemConsts.APOLLO_CLIENT_MONITOR_EXTERNAL_EXPORT_PERIOD; +import static com.ctrip.framework.apollo.core.ApolloClientSystemConsts.APOLLO_CLIENT_MONITOR_EXTERNAL_TYPE; +import static com.ctrip.framework.apollo.core.ApolloClientSystemConsts.APOLLO_CLIENT_MONITOR_JMX_ENABLED; +import static com.ctrip.framework.apollo.core.ApolloClientSystemConsts.APOLLO_CLUSTER; +import static com.ctrip.framework.apollo.core.ApolloClientSystemConsts.APOLLO_CONFIG_SERVICE; +import static com.ctrip.framework.apollo.core.ApolloClientSystemConsts.APOLLO_META; +import static com.ctrip.framework.apollo.core.ApolloClientSystemConsts.APOLLO_OVERRIDE_SYSTEM_PROPERTIES; +import static com.ctrip.framework.apollo.core.ApolloClientSystemConsts.APOLLO_PROPERTY_NAMES_CACHE_ENABLE; +import static com.ctrip.framework.apollo.core.ApolloClientSystemConsts.APOLLO_PROPERTY_ORDER_ENABLE; +import static com.ctrip.framework.apollo.core.ApolloClientSystemConsts.APP_ID; +import static com.ctrip.framework.apollo.core.ConfigConsts.APOLLO_AUTO_UPDATE_INJECTED_SPRING_PROPERTIES; +import static com.ctrip.framework.apollo.spring.config.PropertySourcesConstants.APOLLO_BOOTSTRAP_EAGER_LOAD_ENABLED; +import static com.ctrip.framework.apollo.spring.config.PropertySourcesConstants.APOLLO_BOOTSTRAP_ENABLED; +import static com.ctrip.framework.apollo.spring.config.PropertySourcesConstants.APOLLO_BOOTSTRAP_NAMESPACES; + +import com.ctrip.framework.apollo.Apollo; +import com.ctrip.framework.apollo.monitor.api.ApolloRunningParamsMonitorApi; +import com.ctrip.framework.apollo.monitor.internal.collector.AbstractMetricsCollector; +import com.ctrip.framework.apollo.monitor.internal.model.MetricsEvent; +import com.ctrip.framework.apollo.util.ConfigUtil; +import com.google.common.collect.Maps; +import java.util.Map; + +/** + * @author Rawven + */ +public class DefaultApolloRunningParamsCollector extends AbstractMetricsCollector implements + ApolloRunningParamsMonitorApi { + + public static final String ENV = "env"; + public static final String VERSION = "version"; + public static final String RUNNING_PARAMS = "RunningParams"; + public static final String META_FRESH = "metaFreshTime"; + public static final String CONFIG_SERVICE_URL = "configServiceUrl"; + private final Map map = Maps.newHashMap(); + + public DefaultApolloRunningParamsCollector(ConfigUtil configUtil) { + super(RUNNING_PARAMS, RUNNING_PARAMS); + map.put(APOLLO_ACCESS_KEY_SECRET, configUtil.getAccessKeySecret()); + map.put(APOLLO_AUTO_UPDATE_INJECTED_SPRING_PROPERTIES, + configUtil.isAutoUpdateInjectedSpringPropertiesEnabled()); + map.put(APOLLO_BOOTSTRAP_ENABLED, + Boolean.parseBoolean(System.getProperty(APOLLO_BOOTSTRAP_ENABLED))); + map.put(APOLLO_BOOTSTRAP_NAMESPACES, + System.getProperty(APOLLO_BOOTSTRAP_NAMESPACES)); + map.put(APOLLO_BOOTSTRAP_EAGER_LOAD_ENABLED, + Boolean.parseBoolean(System.getProperty(APOLLO_BOOTSTRAP_EAGER_LOAD_ENABLED))); + map.put(APOLLO_OVERRIDE_SYSTEM_PROPERTIES, configUtil.isOverrideSystemProperties()); + map.put(APOLLO_CACHE_DIR, configUtil.getDefaultLocalCacheDir()); + map.put(APOLLO_CLUSTER, configUtil.getCluster()); + map.put(APOLLO_CONFIG_SERVICE, + System.getProperty(APOLLO_CONFIG_SERVICE)); + map.put(APOLLO_CLIENT_MONITOR_EXTERNAL_TYPE, configUtil.getMonitorExternalType()); + map.put(APOLLO_CLIENT_MONITOR_ENABLED, configUtil.isClientMonitorEnabled()); + map.put(APOLLO_CLIENT_MONITOR_EXTERNAL_EXPORT_PERIOD, + configUtil.getMonitorExternalExportPeriod()); + map.put(APOLLO_META, configUtil.getMetaServerDomainName()); + map.put(APOLLO_PROPERTY_NAMES_CACHE_ENABLE, configUtil.isPropertyNamesCacheEnabled()); + map.put(APOLLO_PROPERTY_ORDER_ENABLE, configUtil.isPropertiesOrderEnabled()); + map.put(APOLLO_CLIENT_MONITOR_JMX_ENABLED, configUtil.isClientMonitorJmxEnabled()); + map.put(APP_ID, configUtil.getAppId()); + map.put(ENV, configUtil.getApolloEnv()); + map.put(VERSION, Apollo.VERSION); + } + + @Override + public String name() { + return RUNNING_PARAMS; + } + + @Override + public void collect0(MetricsEvent event) { + switch (event.getName()) { + case VERSION: + map.put(VERSION, event.getAttachmentValue(VERSION)); + break; + case META_FRESH: + map.put(META_FRESH, event.getAttachmentValue(META_FRESH)); + break; + case CONFIG_SERVICE_URL: + map.put(CONFIG_SERVICE_URL, event.getAttachmentValue(CONFIG_SERVICE_URL)); + break; + default: + break; + } + } + + @Override + public boolean isSamplesUpdated() { + return false; + } + + @Override + public void export0() { + } + + @Override + public String getStartupParams(String key) { + return map.getOrDefault(key, "").toString(); + } + + @Override + public String getConfigServiceUrl() { + return map.get(CONFIG_SERVICE_URL).toString(); + } + + + @Override + public String getAccessKeySecret() { + return map.getOrDefault(APOLLO_ACCESS_KEY_SECRET, "").toString(); + } + + @Override + public Boolean getAutoUpdateInjectedSpringProperties() { + return (Boolean) map.get(APOLLO_AUTO_UPDATE_INJECTED_SPRING_PROPERTIES); + } + + @Override + public Boolean getBootstrapEnabled() { + return (Boolean) map.get(APOLLO_BOOTSTRAP_ENABLED); + } + + @Override + public String getBootstrapNamespaces() { + return (String) map.get(APOLLO_BOOTSTRAP_NAMESPACES); + } + + @Override + public Boolean getBootstrapEagerLoadEnabled() { + return (Boolean) map.get(APOLLO_BOOTSTRAP_EAGER_LOAD_ENABLED); + } + + @Override + public Boolean getOverrideSystemProperties() { + return (Boolean) map.get(APOLLO_OVERRIDE_SYSTEM_PROPERTIES); + } + + @Override + public String getCacheDir() { + return map.get(APOLLO_CACHE_DIR).toString(); + } + + @Override + public String getCluster() { + return map.get( + APOLLO_CLUSTER).toString(); + } + + @Override + public String getConfigService() { + return map.get(APOLLO_CONFIG_SERVICE).toString(); + } + + @Override + public String getClientMonitorExternalForm() { + return map.get(APOLLO_CLIENT_MONITOR_EXTERNAL_TYPE).toString(); + } + + @Override + public Boolean getClientMonitorEnabled() { + return (Boolean) map.get(APOLLO_CLIENT_MONITOR_ENABLED); + } + + @Override + public Boolean getClientMonitorJmxEnabled() { + return (Boolean) map.get(APOLLO_CLIENT_MONITOR_JMX_ENABLED); + } + + @Override + public long getClientMonitorExternalExportPeriod() { + return (Long) map.get(APOLLO_CLIENT_MONITOR_EXTERNAL_EXPORT_PERIOD); + } + + @Override + public String getMeta() { + return map.get(APOLLO_META).toString(); + } + + @Override + public Boolean getPropertyNamesCacheEnable() { + return (Boolean) map.get(APOLLO_PROPERTY_NAMES_CACHE_ENABLE); + } + + @Override + public Boolean getPropertyOrderEnable() { + return (Boolean) map.get(APOLLO_PROPERTY_ORDER_ENABLE); + } + + @Override + public String getMetaLatestFreshTime() { + return map.get(META_FRESH).toString(); + } + + @Override + public String getVersion() { + return map.get(VERSION).toString(); + } + + @Override + public String getEnv() { + return map.get(ENV).toString(); + } + + @Override + public String getAppId() { + return map.get(APP_ID).toString(); + } + +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/collector/internal/DefaultApolloThreadPoolCollector.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/collector/internal/DefaultApolloThreadPoolCollector.java new file mode 100644 index 00000000..1c1b53d4 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/collector/internal/DefaultApolloThreadPoolCollector.java @@ -0,0 +1,257 @@ +/* + * 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.collector.internal; + +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.ApolloThreadPoolMonitorApi; +import com.ctrip.framework.apollo.monitor.internal.collector.AbstractMetricsCollector; +import com.ctrip.framework.apollo.monitor.internal.model.GaugeModel; +import com.ctrip.framework.apollo.monitor.internal.model.MetricsEvent; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.ThreadPoolExecutor; + +/** + * @author Rawven + */ +public class DefaultApolloThreadPoolCollector extends AbstractMetricsCollector implements + ApolloThreadPoolMonitorApi { + + public static final String THREAD_POOL_METRICS = "ThreadPoolMetrics"; + public static final String[] THREAD_POOL_PARAMS = new String[]{"ThreadPoolName", + "activeTaskCount", "queueSize", + "completedTaskCount", + "poolSize", "totalTaskCount", "corePoolSize", "maximumPoolSize", "largestPoolSize", + "queueCapacity", "queueRemainingCapacity", "currentLoad"}; + + private final ScheduledThreadPoolExecutor remoteConfigRepositoryExecutorService; + private final ThreadPoolExecutor abstractConfigExecutorService; + private final ThreadPoolExecutor abstractConfigFileExecutorService; + + public DefaultApolloThreadPoolCollector( + ScheduledExecutorService remoteConfigRepositoryExecutorService, + ExecutorService abstractConfigExecutorService, + ExecutorService abstractConfigFileExecutorService) { + super(THREAD_POOL_METRICS, "Nop"); + this.remoteConfigRepositoryExecutorService = (ScheduledThreadPoolExecutor) remoteConfigRepositoryExecutorService; + this.abstractConfigExecutorService = (ThreadPoolExecutor) abstractConfigExecutorService; + this.abstractConfigFileExecutorService = (ThreadPoolExecutor) abstractConfigFileExecutorService; + } + + @Override + public void collect0(MetricsEvent event) { + } + + @Override + public void export0() { + exportThreadPoolMetrics(abstractConfigExecutorService, + AbstractConfig.class.getSimpleName()); + exportThreadPoolMetrics(abstractConfigFileExecutorService, + AbstractConfigFile.class.getSimpleName()); + exportThreadPoolMetrics(remoteConfigRepositoryExecutorService, + RemoteConfigRepository.class.getSimpleName()); + } + + @Override + public boolean isSamplesUpdated() { + // memory status special + return true; + } + + + @SuppressWarnings("unchecked") + public void exportThreadPoolMetrics(ThreadPoolExecutor executor, + String name) { + List list = Arrays.asList((double) executor.getActiveCount(), + (double) executor.getQueue().size(), + (double) executor.getCompletedTaskCount(), (double) executor.getPoolSize(), + (double) executor.getTaskCount(), (double) executor.getCorePoolSize(), + (double) executor.getMaximumPoolSize(), (double) executor.getLargestPoolSize(), + (double) (executor.getQueue().remainingCapacity() + executor.getQueue().size()), + (double) executor.getQueue().remainingCapacity(), + (double) executor.getPoolSize() / executor.getMaximumPoolSize()); + for (int i = 0; i < list.size(); i++) { + if (!gaugeSamples.containsKey(name + THREAD_POOL_PARAMS[i + 1])) { + gaugeSamples.put(name + THREAD_POOL_PARAMS[i + 1], + GaugeModel.builder().putTag(THREAD_POOL_PARAMS[0], name) + .name(THREAD_POOL_PARAMS[i + 1]) + .value(0).apply(GaugeModel.doubleConverter).build()); + } + gaugeSamples.get(name + THREAD_POOL_PARAMS[i + 1]).updateValue(list.get(i)); + } + } + + + @Override + public int getRemoteConfigRepositoryThreadPoolActiveCount() { + return remoteConfigRepositoryExecutorService.getActiveCount(); + } + + @Override + public int getRemoteConfigRepositoryThreadPoolQueueSize() { + return remoteConfigRepositoryExecutorService.getQueue().size(); + } + + @Override + public int getRemoteConfigRepositoryThreadPoolCorePoolSize() { + return remoteConfigRepositoryExecutorService.getCorePoolSize(); + } + + @Override + public int getRemoteConfigRepositoryThreadPoolMaximumPoolSize() { + return remoteConfigRepositoryExecutorService.getMaximumPoolSize(); + } + + @Override + public int getRemoteConfigRepositoryThreadPoolPoolSize() { + return remoteConfigRepositoryExecutorService.getPoolSize(); + } + + @Override + public long getRemoteConfigRepositoryThreadPoolTaskCount() { + return remoteConfigRepositoryExecutorService.getTaskCount(); + } + + @Override + public long getRemoteConfigRepositoryThreadPoolCompletedTaskCount() { + return remoteConfigRepositoryExecutorService.getCompletedTaskCount(); + } + + @Override + public int getRemoteConfigRepositoryThreadPoolLargestPoolSize() { + return remoteConfigRepositoryExecutorService.getLargestPoolSize(); + } + + @Override + public int getRemoteConfigRepositoryThreadPoolRemainingCapacity() { + return remoteConfigRepositoryExecutorService.getQueue().remainingCapacity(); + } + + @Override + public double getRemoteConfigRepositoryThreadPoolCurrentLoad() { + return (double) remoteConfigRepositoryExecutorService.getPoolSize() + / remoteConfigRepositoryExecutorService.getMaximumPoolSize(); + } + + @Override + public int getAbstractConfigThreadPoolActiveCount() { + return abstractConfigExecutorService.getActiveCount(); + } + + @Override + public int getAbstractConfigThreadPoolQueueSize() { + return abstractConfigExecutorService.getQueue().size(); + } + + @Override + public int getAbstractConfigThreadPoolCorePoolSize() { + return abstractConfigExecutorService.getCorePoolSize(); + } + + @Override + public int getAbstractConfigThreadPoolMaximumPoolSize() { + return abstractConfigExecutorService.getMaximumPoolSize(); + } + + @Override + public int getAbstractConfigThreadPoolPoolSize() { + return abstractConfigExecutorService.getPoolSize(); + } + + @Override + public long getAbstractConfigThreadPoolTaskCount() { + return abstractConfigExecutorService.getTaskCount(); + } + + @Override + public long getAbstractConfigThreadPoolCompletedTaskCount() { + return abstractConfigExecutorService.getCompletedTaskCount(); + } + + @Override + public int getAbstractConfigThreadPoolLargestPoolSize() { + return abstractConfigExecutorService.getLargestPoolSize(); + } + + @Override + public int getAbstractConfigThreadPoolRemainingCapacity() { + return abstractConfigExecutorService.getQueue().remainingCapacity(); + } + + @Override + public double getAbstractConfigThreadPoolCurrentLoad() { + return (double) abstractConfigExecutorService.getPoolSize() + / abstractConfigExecutorService.getMaximumPoolSize(); + } + + @Override + public int getAbstractConfigFileThreadPoolActiveCount() { + return abstractConfigFileExecutorService.getActiveCount(); + } + + @Override + public int getAbstractConfigFileThreadPoolQueueSize() { + return abstractConfigFileExecutorService.getQueue().size(); + } + + @Override + public int getAbstractConfigFileThreadPoolCorePoolSize() { + return abstractConfigFileExecutorService.getCorePoolSize(); + } + + @Override + public int getAbstractConfigFileThreadPoolMaximumPoolSize() { + return abstractConfigFileExecutorService.getMaximumPoolSize(); + } + + @Override + public int getAbstractConfigFileThreadPoolPoolSize() { + return abstractConfigFileExecutorService.getPoolSize(); + } + + @Override + public long getAbstractConfigFileThreadPoolTaskCount() { + return abstractConfigFileExecutorService.getTaskCount(); + } + + @Override + public long getAbstractConfigFileThreadPoolCompletedTaskCount() { + return abstractConfigFileExecutorService.getCompletedTaskCount(); + } + + @Override + public int getAbstractConfigFileThreadPoolLargestPoolSize() { + return abstractConfigFileExecutorService.getLargestPoolSize(); + } + + @Override + public int getAbstractConfigFileThreadPoolRemainingCapacity() { + return abstractConfigFileExecutorService.getQueue().remainingCapacity(); + } + + @Override + public double getAbstractConfigFileThreadPoolCurrentLoad() { + return (double) abstractConfigFileExecutorService.getPoolSize() + / abstractConfigFileExecutorService.getMaximumPoolSize(); + } + +} \ No newline at end of file diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/collector/internal/DefaultMetricsCollectorManager.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/collector/internal/DefaultMetricsCollectorManager.java new file mode 100644 index 00000000..972b4da0 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/collector/internal/DefaultMetricsCollectorManager.java @@ -0,0 +1,42 @@ +/* + * 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.collector.internal; + +import com.ctrip.framework.apollo.monitor.internal.collector.MetricsCollector; +import com.ctrip.framework.apollo.monitor.internal.collector.MetricsCollectorManager; +import java.util.List; + +/** + * @author Rawven + */ +public class DefaultMetricsCollectorManager implements MetricsCollectorManager { + + private List collectors; + + public DefaultMetricsCollectorManager() { + } + + @Override + public List getCollectors() { + return collectors; + } + + public void setCollectors(List collectors) { + this.collectors = collectors; + } + +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/exporter/AbstractMetricsExporter.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/exporter/AbstractMetricsExporter.java new file mode 100644 index 00000000..49b1083f --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/exporter/AbstractMetricsExporter.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.exporter; + +import com.ctrip.framework.apollo.core.utils.ApolloThreadFactory; +import com.ctrip.framework.apollo.core.utils.DeferredLoggerFactory; +import com.ctrip.framework.apollo.monitor.internal.collector.MetricsCollector; +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.MetricsModel; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import org.slf4j.Logger; + +/** + * General framework for access monitoring systems + *

+ * 作者:Rawven + */ +public abstract class AbstractMetricsExporter implements MetricsExporter { + + protected static final Logger log = DeferredLoggerFactory.getLogger( + AbstractMetricsExporter.class); + protected static final ScheduledExecutorService m_executorService; + 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("MetricsReporter", true)); + } + + protected List collectors; + + @Override + public void init(List collectors, long collectPeriod) { + doInit(); + this.collectors = collectors; + initScheduleMetricsCollectSync(collectPeriod); + } + + protected abstract void doInit(); + + private void initScheduleMetricsCollectSync(long collectPeriod) { + m_executorService.scheduleAtFixedRate(() -> { + try { + updateMetricsData(); + } catch (Throwable ex) { + //ignore + } + }, INITIAL_DELAY, collectPeriod, TimeUnit.SECONDS); + } + + protected void updateMetricsData() { + log.debug("Start to update metrics data job"); + collectors.forEach(collector -> { + if (collector.isSamplesUpdated()) { + collector.export().forEach(this::registerSample); + } + }); + } + + protected void registerSample(MetricsModel sample) { + try { + switch (sample.getType()) { + case GAUGE: + registerGaugeSample((GaugeModel) sample); + break; + case COUNTER: + registerCounterSample((CounterModel) sample); + break; + default: + log.warn("Unsupported sample type: {}", sample.getType()); + break; + } + } catch (Exception e) { + log.error("Register sample error", e); + } + } + + protected String[][] getTags(MetricsModel sample) { + Map tags = sample.getTags(); + if (tags == null || tags.isEmpty()) { + return new String[][]{new String[0], new String[0]}; + } + String[] labelNames = tags.keySet().toArray(new String[0]); + String[] labelValues = tags.values().toArray(new String[0]); + return new String[][]{labelNames, labelValues}; + } + +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/exporter/MetricsExporter.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/exporter/MetricsExporter.java new file mode 100644 index 00000000..bfe095e9 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/exporter/MetricsExporter.java @@ -0,0 +1,62 @@ +/* + * 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.collector.MetricsCollector; +import com.ctrip.framework.apollo.monitor.internal.model.CounterModel; +import com.ctrip.framework.apollo.monitor.internal.model.GaugeModel; +import java.util.List; + +/** + * @author Rawven + */ +public interface MetricsExporter extends Ordered { + + /** + * init method + */ + void init(List collectors, long collectPeriod); + + /** + * is support + * + * @param form form + */ + boolean isSupport(String form); + + /** + * used to register Counter type metrics + */ + void registerCounterSample(CounterModel sample); + + /** + * used to register Gauge type metrics + */ + void registerGaugeSample(GaugeModel sample); + + /** + * TODO 放入api + * 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/MetricsExporterFactory.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/exporter/MetricsExporterFactory.java new file mode 100644 index 00000000..178c5f27 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/exporter/MetricsExporterFactory.java @@ -0,0 +1,28 @@ +/* + * 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.collector.MetricsCollector; +import java.util.List; + +/** + * @author Rawven + */ +public interface MetricsExporterFactory { + + MetricsExporter getMetricsReporter(List collectors); +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/exporter/internals/DefaultMetricsExporterFactory.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/exporter/internals/DefaultMetricsExporterFactory.java new file mode 100644 index 00000000..23a773ac --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/exporter/internals/DefaultMetricsExporterFactory.java @@ -0,0 +1,77 @@ +/* + * 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.internals; + +import static com.ctrip.framework.apollo.monitor.internal.MonitorConstant.MBEAN_NAME; + +import com.ctrip.framework.apollo.build.ApolloInjector; +import com.ctrip.framework.apollo.core.utils.DeferredLoggerFactory; +import com.ctrip.framework.apollo.exceptions.ApolloConfigException; +import com.ctrip.framework.apollo.monitor.internal.collector.MetricsCollector; +import com.ctrip.framework.apollo.monitor.internal.collector.internal.DefaultMetricsCollectorManager; +import com.ctrip.framework.apollo.monitor.internal.exporter.MetricsExporter; +import com.ctrip.framework.apollo.monitor.internal.exporter.MetricsExporterFactory; +import com.ctrip.framework.apollo.monitor.internal.util.JMXUtil; +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; + +public class DefaultMetricsExporterFactory implements MetricsExporterFactory { + + private static final Logger logger = DeferredLoggerFactory.getLogger( + DefaultMetricsCollectorManager.class); + private final ConfigUtil m_configUtil; + + public DefaultMetricsExporterFactory() { + m_configUtil = ApolloInjector.getInstance(ConfigUtil.class); + } + + @Override + public MetricsExporter getMetricsReporter(List collectors) { + //initializeMonitorSystem reporter + if (m_configUtil.isClientMonitorJmxEnabled()) { + collectors.forEach(metricsCollector -> + JMXUtil.register(MBEAN_NAME + metricsCollector.name(), + metricsCollector)); + } + String externalSystemType = m_configUtil.getMonitorExternalType(); + MetricsExporter reporter = null; + if (externalSystemType != null) { + List metricsExporters = ServiceBootstrap.loadAllOrdered( + MetricsExporter.class); + for (MetricsExporter metricsExporter : metricsExporters) { + if (metricsExporter.isSupport(externalSystemType)) { + reporter = metricsExporter; + reporter.init(collectors, m_configUtil.getMonitorExternalExportPeriod()); + break; + } + } + if (reporter == null) { + ApolloConfigException exception = new ApolloConfigException( + "No matching exporter found with monitor-external-type " + externalSystemType + ); + 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/model/CounterModel.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/model/CounterModel.java new file mode 100644 index 00000000..2e36088f --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/model/CounterModel.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.model; + +import com.ctrip.framework.apollo.monitor.internal.util.MeterType; +import java.util.HashMap; +import java.util.Map; + +/** + * @author Rawven + */ +public class CounterModel extends MetricsModel { + + private double nowValue; + private double increaseValue; + + public CounterModel(String name, double num) { + this.name = name; + this.nowValue = num; + this.increaseValue = num; + this.type = MeterType.COUNTER; + } + + public static CounterBuilder builder() { + return new CounterBuilder(); + } + + public void updateValue(double value) { + increaseValue = value - nowValue; + nowValue = value; + } + + public Double getIncreaseValue() { + return increaseValue; + } + + public void setValue(Double value) { + this.nowValue = value; + } + + public static class CounterBuilder { + + private final Map tags = new HashMap<>(); + private String name; + private double value; + + public CounterBuilder name(String name) { + this.name = name; + return this; + } + + public CounterBuilder value(double value) { + this.value = value; + return this; + } + + public CounterBuilder putTag(String key, String value) { + this.tags.put(key, value); + return this; + } + + public CounterModel build() { + CounterModel sample = new CounterModel(name, value); + sample.tags.putAll(tags); + return sample; + } + } +} 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..04f6baf8 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/model/GaugeModel.java @@ -0,0 +1,98 @@ +/* + * 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.util.MeterType; +import java.util.HashMap; +import java.util.Map; +import java.util.function.ToDoubleFunction; + +public class GaugeModel extends MetricsModel { + + public static final ToDoubleFunction intConverter = v -> (int) v; + public static final ToDoubleFunction longConverter = v -> (long) v; + public static final ToDoubleFunction doubleConverter = v -> (double) v; + + private T value; + private ToDoubleFunction apply; + + public GaugeModel(String name, T value, ToDoubleFunction apply) { + this.name = name; + this.value = value; + this.apply = apply; + this.type = MeterType.GAUGE; + } + + public static GaugeBuilder builder() { + return new GaugeBuilder<>(); + } + + public T getValue() { + return value; + } + + public void updateValue(T value) { + this.value = value; + } + + public ToDoubleFunction getApply() { + return this.apply; + } + + public void setApply(ToDoubleFunction apply) { + this.apply = apply; + } + + public double getApplyValue() { + return getApply().applyAsDouble(getValue()); + } + + public static class GaugeBuilder { + + private final Map tags = new HashMap<>(1); + private String name; + private T value; + private ToDoubleFunction apply; + + public GaugeBuilder name(String name) { + this.name = name; + return this; + } + + public GaugeBuilder value(T value) { + this.value = value; + return this; + } + + public GaugeBuilder apply(ToDoubleFunction apply) { + this.apply = apply; + return this; + } + + public GaugeBuilder putTag(String key, String value) { + this.tags.put(key, value); + return this; + } + + public GaugeModel build() { + GaugeModel sample = new GaugeModel<>(name, value, apply); + sample.tags.putAll(tags); + return sample; + } + } +} + diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/model/MetricsEvent.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/model/MetricsEvent.java new file mode 100644 index 00000000..f4ad7fd3 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/model/MetricsEvent.java @@ -0,0 +1,94 @@ +/* + * 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 java.util.HashMap; +import java.util.Map; + +/** + * metrics event model + * + * @author Rawven + */ +public class MetricsEvent { + + private final String name; + private final String tag; + private final Map attachments; + + private MetricsEvent(Builder builder) { + this.name = builder.name; + this.attachments = builder.attachment; + this.tag = builder.tag; + } + + public static Builder builder() { + return new Builder(); + } + + public String getName() { + return name; + } + + @SuppressWarnings("unchecked") + public T getAttachmentValue(String key) { + return (T) attachments.get(key); + } + + public String getTag() { + return tag; + } + + @Override + public String toString() { + return "MetricsEvent{" + + "name='" + name + '\'' + + ", attachments=" + attachments + + ", tag='" + tag + '\'' + + '}'; + } + + public static class Builder { + + private final Map attachment = new HashMap<>(3); + private String name; + private String tag; + + public Builder withName(String name) { + this.name = name; + return this; + } + + public Builder putAttachment(String k, Object v) { + this.attachment.put(k, v); + return this; + } + + public Builder withTag(String tag) { + this.tag = tag; + return this; + } + + public void push() { + MetricsEventPusher.push(this.build()); + } + + public MetricsEvent build() { + return new MetricsEvent(this); + } + } +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/model/MetricsEventPusher.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/model/MetricsEventPusher.java new file mode 100644 index 00000000..0334a863 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/model/MetricsEventPusher.java @@ -0,0 +1,45 @@ +/* + * 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.build.ApolloInjector; +import com.ctrip.framework.apollo.monitor.internal.collector.MetricsCollector; +import com.ctrip.framework.apollo.monitor.internal.collector.MetricsCollectorManager; +import com.ctrip.framework.apollo.util.ConfigUtil; + +/** + * @author Rawven + */ +public abstract class MetricsEventPusher { + + private static final MetricsCollectorManager COLLECTOR_MANAGER = ApolloInjector.getInstance( + MetricsCollectorManager.class); + private static final ConfigUtil m_configUtil = ApolloInjector.getInstance(ConfigUtil.class); + + public static void push(MetricsEvent event) { + if (m_configUtil.isClientMonitorEnabled()) { + for (MetricsCollector collector : COLLECTOR_MANAGER.getCollectors()) { + if (collector.isSupport(event)) { + collector.collect(event); + return; + } + } + } + } +} + + diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/model/MetricsModel.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/model/MetricsModel.java new file mode 100644 index 00000000..e293ce6f --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/model/MetricsModel.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.model; + +import com.ctrip.framework.apollo.monitor.internal.util.MeterType; +import java.util.HashMap; +import java.util.Map; + +/** + * @author Rawven + */ +public class MetricsModel { + + protected final Map tags = new HashMap<>(); + protected String name; + protected MeterType type; + + public String getName() { + return "Apollo_Client_" + name; + } + + public void setName(String name) { + this.name = name; + } + + public MeterType getType() { + return type; + } + + public Map getTags() { + return tags; + } +} + diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/tracer/ClientMessageProducerManager.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/tracer/ClientMessageProducerManager.java new file mode 100644 index 00000000..9fc9290b --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/tracer/ClientMessageProducerManager.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 ClientMessageProducerManager implements MessageProducerManager { + + private static MessageProducer producer; + + public ClientMessageProducerManager() { + 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/MessageProducerComposite.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/tracer/MessageProducerComposite.java new file mode 100644 index 00000000..e2685950 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/tracer/MessageProducerComposite.java @@ -0,0 +1,85 @@ +/* + * 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 MessageProducerComposite implements MessageProducer { + + public static final String ERROR_METRICS = "errorMetrics"; + public static final String THROWABLE = ERROR_METRICS + ".throwable"; + 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_CLIENT_CONFIGS = "Apollo.Client.Configs."; + public static final String APOLLO_CLIENT_CONFIGMETA = "Apollo.Client.ConfigMeta"; + public static final String HELP_STR = "periodicRefresh: "; + private static final NullTransaction NULL_TRANSACTION = new NullTransaction(); + private List producers; + + public MessageProducerComposite(List producers) { + this.producers = producers; + } + + + @Override + public void logError(Throwable cause) { + producers.forEach(producer -> producer.logError(cause)); + } + + @Override + public void logError(String message, Throwable cause) { + producers.forEach(producer -> producer.logError(message, cause)); + } + + @Override + public void logEvent(String type, String name) { + producers.forEach(producer -> producer.logEvent(type, name)); + } + + @Override + public void logEvent(String type, String name, String status, + String nameValuePairs) { + producers.forEach(producer -> producer.logEvent(type, name, status, nameValuePairs)); + } + + @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; + } + + public List getProducers() { + return producers; + } +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/tracer/MonitorMessageProducer.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/tracer/MonitorMessageProducer.java new file mode 100644 index 00000000..4242dace --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/tracer/MonitorMessageProducer.java @@ -0,0 +1,152 @@ +/* + * 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.MonitorConstant.*; +import static com.ctrip.framework.apollo.monitor.internal.collector.internal.DefaultApolloNamespaceCollector.*; +import static com.ctrip.framework.apollo.monitor.internal.collector.internal.DefaultApolloRunningParamsCollector.*; +import static com.ctrip.framework.apollo.monitor.internal.tracer.MessageProducerComposite.*; + +import com.ctrip.framework.apollo.exceptions.ApolloConfigException; +import com.ctrip.framework.apollo.monitor.internal.model.MetricsEvent; +import com.ctrip.framework.apollo.tracer.spi.MessageProducer; +import com.ctrip.framework.apollo.tracer.spi.Transaction; +import java.time.Instant; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * metrics message producer + * + * @author Rawven + */ +public class MonitorMessageProducer 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 + ) + ); + + @Override + public void logError(Throwable cause) { + MetricsEvent.builder().withName(ERROR_METRICS) + .withTag(ERROR_METRICS) + .putAttachment(THROWABLE, cause) + .push(); + } + + @Override + public void logError(String message, Throwable cause) { + MetricsEvent.builder().withName(ERROR_METRICS) + .withTag(ERROR_METRICS) + .putAttachment(THROWABLE, cause).push(); + } + + @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); + } + } + + private void handleTaggedEvent(String type, String name) { + String namespace; + switch (type) { + case APOLLO_CONFIGSERVICE: { + name = name.substring(HELP_STR.length()); + } + case APOLLO_CLIENT_CONFIGCHANGES: { + namespace = name; + MetricsEvent.builder() + .withName(NAMESPACE_LATEST_UPDATE_TIME) + .putAttachment(NAMESPACE, namespace) + .putAttachment(TIMESTAMP, System.currentTimeMillis()) + .withTag(NAMESPACE_MONITOR) + .push(); + break; + } + case APOLLO_CONFIG_EXCEPTION: { + logError(new ApolloConfigException(name)); + break; + } + case APOLLO_META_SERVICE: { + MetricsEvent.builder() + .withName(META_FRESH) + .withTag(RUNNING_PARAMS) + .putAttachment(META_FRESH, + DATE_FORMATTER.format(Instant.ofEpochMilli(System.currentTimeMillis()))) + .push(); + break; + } + case APOLLO_CONFIG_SERVICES: { + MetricsEvent.builder() + .withName(CONFIG_SERVICE_URL) + .withTag(RUNNING_PARAMS) + .putAttachment(CONFIG_SERVICE_URL, name) + .push(); + break; + } + case APOLLO_CLIENT_VERSION: { + MetricsEvent.builder() + .withName(VERSION) + .withTag(RUNNING_PARAMS) + .putAttachment(VERSION, name) + .push(); + break; + } + case APOLLO_CLIENT_CONFIGMETA: + // 不需要收集 + break; + default: + break; + } + } + + private void handleClientConfigEvent(String type, String name) { + int len = APOLLO_CLIENT_CONFIGS.length(); + String namespace = type.substring(len); + String releaseKey = name; + MetricsEvent.builder() + .withName(NAMESPACE_RELEASE_KEY) + .withTag(NAMESPACE_MONITOR) + .putAttachment(NAMESPACE_RELEASE_KEY, releaseKey) + .putAttachment(NAMESPACE, namespace) + .push(); + } + + @Override + public void logEvent(String type, String name, String status, + String nameValuePairs) { + // + } + + @Override + public Transaction newTransaction(String type, String name) { + return null; + } + +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/util/JMXUtil.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/util/JMXUtil.java new file mode 100644 index 00000000..35d2c60a --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/util/JMXUtil.java @@ -0,0 +1,63 @@ +/* + * 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.util; + +import java.lang.management.ManagementFactory; +import javax.management.InstanceAlreadyExistsException; +import javax.management.JMException; +import javax.management.MBeanServer; +import javax.management.ObjectName; + +/** + * @author Rawven + */ +public final class JMXUtil { + + //TODO 自定义MBeanServer + public static MBeanServer mbeanServer; + + public static ObjectName register(String name, Object mbean) { + try { + ObjectName objectName = new ObjectName(name); + + //TODO + if (mbeanServer == null) { + mbeanServer = ManagementFactory.getPlatformMBeanServer(); + } + + try { + mbeanServer.registerMBean(mbean, objectName); + } catch (InstanceAlreadyExistsException ex) { + mbeanServer.registerMBean(mbean, objectName); + mbeanServer.unregisterMBean(objectName); + } + + return objectName; + } catch (JMException e) { + throw new IllegalArgumentException(name, e); + } + } + + public static void unregister(String name) { + try { + MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer(); + mbeanServer.unregisterMBean(new ObjectName(name)); + } catch (JMException e) { + throw new IllegalArgumentException(name, e); + } + } +} diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/util/MeterType.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/util/MeterType.java new file mode 100644 index 00000000..f200e262 --- /dev/null +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/monitor/internal/util/MeterType.java @@ -0,0 +1,25 @@ +/* + * 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.util; + +/** + * @author Rawven + */ +public enum MeterType { + COUNTER, + GAUGE +} \ 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..af3e347e 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,11 @@ 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,}; private final ConfigPropertySourceFactory configPropertySourceFactory = SpringInjector .getInstance(ConfigPropertySourceFactory.class); @@ -132,6 +136,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 +202,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..731c7513 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 @@ -38,18 +38,21 @@ public class ConfigUtil { private static final Logger logger = LoggerFactory.getLogger(ConfigUtil.class); - + private final RateLimiter warnLogRateLimiter; /** * qps limit: discovery config service from meta *

* 1 times per second */ private int discoveryQPS = 1; - /** 1 second */ + /** + * 1 second + */ private int discoveryConnectTimeout = 1000; - /** 1 second */ + /** + * 1 second + */ private int discoveryReadTimeout = 1000; - private int refreshInterval = 5; private TimeUnit refreshIntervalTimeUnit = TimeUnit.MINUTES; private int connectTimeout = 1000; //1 second @@ -66,11 +69,14 @@ public class ConfigUtil { private TimeUnit configCacheExpireTimeUnit = TimeUnit.MINUTES;//1 minute private long longPollingInitialDelayInMills = 2000;//2 seconds private boolean autoUpdateInjectedSpringProperties = true; - private final RateLimiter warnLogRateLimiter; private boolean propertiesOrdered = false; private boolean propertyNamesCacheEnabled = false; private boolean propertyFileCacheEnabled = true; private boolean overrideSystemProperties = true; + private boolean isClientMonitorEnabled = false; + private boolean isClientMonitorJmxEnabled = false; + private String monitorExternalType = null; + private long monitorExternalExportPeriod = 10; public ConfigUtil() { warnLogRateLimiter = RateLimiter.create(0.017); // 1 warning log output per minute @@ -86,6 +92,23 @@ public ConfigUtil() { initPropertyNamesCacheEnabled(); initPropertyFileCacheEnabled(); initOverrideSystemProperties(); + initMonitorExternalType(); + initMonitorExternalCollectPeriod(); + initClientMonitorEnabled(); + initClientMonitorJmxEnabled(); + } + + + static Integer getCustomizedIntegerValue(String systemKey) { + String customizedValue = System.getProperty(systemKey); + if (!Strings.isNullOrEmpty(customizedValue)) { + try { + return Integer.parseInt(customizedValue); + } catch (Throwable ex) { + logger.error("Config for {} is invalid: {}", systemKey, customizedValue); + } + } + return null; } /** @@ -222,18 +245,6 @@ public TimeUnit getRefreshIntervalTimeUnit() { return refreshIntervalTimeUnit; } - static Integer getCustomizedIntegerValue(String systemKey) { - String customizedValue = System.getProperty(systemKey); - if (!Strings.isNullOrEmpty(customizedValue)) { - try { - return Integer.parseInt(customizedValue); - } catch (Throwable ex) { - logger.error("Config for {} is invalid: {}", systemKey, customizedValue); - } - } - return null; - } - private void initQPS() { { Integer value = getCustomizedIntegerValue("apollo.discoveryConnectTimeout"); @@ -340,7 +351,8 @@ private String getDeprecatedCustomizedCacheRoot() { } if (Strings.isNullOrEmpty(cacheRoot)) { // 2. Get from OS environment variable - cacheRoot = System.getenv(ApolloClientSystemConsts.DEPRECATED_APOLLO_CACHE_DIR_ENVIRONMENT_VARIABLES); + cacheRoot = System.getenv( + ApolloClientSystemConsts.DEPRECATED_APOLLO_CACHE_DIR_ENVIRONMENT_VARIABLES); if (!Strings.isNullOrEmpty(cacheRoot)) { DeprecatedPropertyNotifyUtil .warn(ApolloClientSystemConsts.DEPRECATED_APOLLO_CACHE_DIR_ENVIRONMENT_VARIABLES, @@ -349,7 +361,8 @@ private String getDeprecatedCustomizedCacheRoot() { } if (Strings.isNullOrEmpty(cacheRoot)) { // 3. Get from server.properties - cacheRoot = Foundation.server().getProperty(ApolloClientSystemConsts.DEPRECATED_APOLLO_CACHE_DIR, null); + cacheRoot = Foundation.server() + .getProperty(ApolloClientSystemConsts.DEPRECATED_APOLLO_CACHE_DIR, null); if (!Strings.isNullOrEmpty(cacheRoot)) { DeprecatedPropertyNotifyUtil.warn(ApolloClientSystemConsts.DEPRECATED_APOLLO_CACHE_DIR, ApolloClientSystemConsts.APOLLO_CACHE_DIR); @@ -357,7 +370,8 @@ private String getDeprecatedCustomizedCacheRoot() { } if (Strings.isNullOrEmpty(cacheRoot)) { // 4. Get from app.properties - cacheRoot = Foundation.app().getProperty(ApolloClientSystemConsts.DEPRECATED_APOLLO_CACHE_DIR, null); + cacheRoot = Foundation.app() + .getProperty(ApolloClientSystemConsts.DEPRECATED_APOLLO_CACHE_DIR, null); if (!Strings.isNullOrEmpty(cacheRoot)) { DeprecatedPropertyNotifyUtil.warn(ApolloClientSystemConsts.DEPRECATED_APOLLO_CACHE_DIR, ApolloClientSystemConsts.APOLLO_CACHE_DIR); @@ -474,23 +488,85 @@ public boolean isOverrideSystemProperties() { } private void initPropertyNamesCacheEnabled() { - propertyNamesCacheEnabled = getPropertyBoolean(ApolloClientSystemConsts.APOLLO_PROPERTY_NAMES_CACHE_ENABLE, - ApolloClientSystemConsts.APOLLO_PROPERTY_NAMES_CACHE_ENABLE_ENVIRONMENT_VARIABLES, - propertyNamesCacheEnabled); + propertyNamesCacheEnabled = getPropertyBoolean( + ApolloClientSystemConsts.APOLLO_PROPERTY_NAMES_CACHE_ENABLE, + ApolloClientSystemConsts.APOLLO_PROPERTY_NAMES_CACHE_ENABLE_ENVIRONMENT_VARIABLES, + propertyNamesCacheEnabled); } private void initPropertyFileCacheEnabled() { propertyFileCacheEnabled = getPropertyBoolean(ApolloClientSystemConsts.APOLLO_CACHE_FILE_ENABLE, - ApolloClientSystemConsts.APOLLO_CACHE_FILE_ENABLE_ENVIRONMENT_VARIABLES, - propertyFileCacheEnabled); + ApolloClientSystemConsts.APOLLO_CACHE_FILE_ENABLE_ENVIRONMENT_VARIABLES, + propertyFileCacheEnabled); } private void initOverrideSystemProperties() { - overrideSystemProperties = getPropertyBoolean(ApolloClientSystemConsts.APOLLO_OVERRIDE_SYSTEM_PROPERTIES, - ApolloClientSystemConsts.APOLLO_OVERRIDE_SYSTEM_PROPERTIES, - overrideSystemProperties); + overrideSystemProperties = getPropertyBoolean( + ApolloClientSystemConsts.APOLLO_OVERRIDE_SYSTEM_PROPERTIES, + ApolloClientSystemConsts.APOLLO_OVERRIDE_SYSTEM_PROPERTIES, + overrideSystemProperties); } + private void initMonitorExternalType() { + monitorExternalType = System.getProperty(ApolloClientSystemConsts.APOLLO_CLIENT_MONITOR_EXTERNAL_TYPE); + if (Strings.isNullOrEmpty(monitorExternalType)) { + monitorExternalType = Foundation.app() + .getProperty(ApolloClientSystemConsts.APOLLO_CLIENT_MONITOR_EXTERNAL_TYPE, null); + } + } + + public String getMonitorExternalType() { + return monitorExternalType; + } + + private void initMonitorExternalCollectPeriod() { + String collectPeriod = System.getProperty( + ApolloClientSystemConsts.APOLLO_CLIENT_MONITOR_EXTERNAL_EXPORT_PERIOD); + if (Strings.isNullOrEmpty(collectPeriod)) { + collectPeriod = Foundation.app() + .getProperty(ApolloClientSystemConsts.APOLLO_CLIENT_MONITOR_EXTERNAL_EXPORT_PERIOD, null); + } + if (!Strings.isNullOrEmpty(collectPeriod)) { + try { + monitorExternalExportPeriod = Long.parseLong(collectPeriod); + } catch (Throwable ex) { + logger.error("Config for {} is invalid: {}", + ApolloClientSystemConsts.APOLLO_CLIENT_MONITOR_EXTERNAL_EXPORT_PERIOD, collectPeriod); + } + } + } + + public long getMonitorExternalExportPeriod() { + return monitorExternalExportPeriod; + } + + + private void initClientMonitorEnabled() { + String enabled = System.getProperty(ApolloClientSystemConsts.APOLLO_CLIENT_MONITOR_ENABLED); + if (enabled == null) { + enabled = Foundation.app() + .getProperty(ApolloClientSystemConsts.APOLLO_CLIENT_MONITOR_ENABLED, "false"); + } + isClientMonitorEnabled = Boolean.parseBoolean(enabled); + } + + public boolean isClientMonitorEnabled() { + return isClientMonitorEnabled; + } + + private void initClientMonitorJmxEnabled() { + String enabled = System.getProperty(ApolloClientSystemConsts.APOLLO_CLIENT_MONITOR_JMX_ENABLED); + if (enabled == null) { + enabled = Foundation.app() + .getProperty(ApolloClientSystemConsts.APOLLO_CLIENT_MONITOR_JMX_ENABLED, "false"); + } + isClientMonitorJmxEnabled = Boolean.parseBoolean(enabled); + } + public boolean isClientMonitorJmxEnabled() { + return isClientMonitorJmxEnabled; + } + + private boolean getPropertyBoolean(String propertyName, String envName, boolean defaultVal) { String enablePropertyNamesCache = System.getProperty(propertyName); if (Strings.isNullOrEmpty(enablePropertyNamesCache)) { @@ -504,7 +580,7 @@ private boolean getPropertyBoolean(String propertyName, String envName, boolean return Boolean.parseBoolean(enablePropertyNamesCache); } catch (Throwable ex) { logger.warn("Config for {} is invalid: {}, set default value: {}", - propertyName, enablePropertyNamesCache, defaultVal); + propertyName, enablePropertyNamesCache, defaultVal); } } return defaultVal; 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..cb9deb74 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,35 @@ "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.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..fbae9d1c --- /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.ClientMessageProducerManager \ No newline at end of file diff --git a/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/collector/AbstractApolloMetricsCollectorTest.java b/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/collector/AbstractApolloMetricsCollectorTest.java new file mode 100644 index 00000000..4a3da10c --- /dev/null +++ b/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/collector/AbstractApolloMetricsCollectorTest.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.collector; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.when; + +import com.ctrip.framework.apollo.monitor.internal.model.MetricsEvent; +import com.ctrip.framework.apollo.monitor.internal.model.MetricsModel; +import java.util.List; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; +public class AbstractApolloMetricsCollectorTest { + + private AbstractMetricsCollector metricsCollector; + + @Before + public void setUp() { + metricsCollector = new AbstractMetricsCollector("mock","tag1", "tag2") { + @Override + public String name() { + return "MockMetricsCollector"; + } + + @Override + public void collect0(MetricsEvent event) { + // 模拟实现 + } + + @Override + public void export0() { + // 模拟实现 + } + }; + } + + @Test + public void testConstructorInitialization() { + assertNotNull(metricsCollector); + } + + @Test + public void testIsSupport() { + MetricsEvent event = Mockito.mock(MetricsEvent.class); + + when(event.getTag()).thenReturn("tag1"); + assertTrue(metricsCollector.isSupport(event)); + + when(event.getTag()).thenReturn("tag3"); + assertFalse(metricsCollector.isSupport(event)); + } + + @Test + public void testCollect() { + MetricsEvent event = Mockito.mock(MetricsEvent.class); + metricsCollector.collect(event); + assertTrue(metricsCollector.isSamplesUpdated()); + } + + @Test + public void testIsSamplesUpdated() { + MetricsEvent event = Mockito.mock(MetricsEvent.class); + metricsCollector.collect(event); + assertTrue(metricsCollector.isSamplesUpdated()); + assertFalse(metricsCollector.isSamplesUpdated()); + } + + @Test + public void testExport() { + List samples = metricsCollector.export(); + assertNotNull(samples); + } +} diff --git a/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/exporter/AbstractApolloMetricsExporterTest.java b/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/exporter/AbstractApolloMetricsExporterTest.java new file mode 100644 index 00000000..e7122eb4 --- /dev/null +++ b/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/exporter/AbstractApolloMetricsExporterTest.java @@ -0,0 +1,123 @@ +/* + * 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.assertArrayEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.ctrip.framework.apollo.monitor.internal.collector.MetricsCollector; +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.MetricsModel; +import com.ctrip.framework.apollo.monitor.internal.util.MeterType; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class AbstractApolloMetricsExporterTest { + + @Mock + private MetricsCollector mockCollector; + + @InjectMocks + private final AbstractMetricsExporter reporter = new AbstractMetricsExporter() { + @Override + protected void doInit() { + // Do nothing for test purposes + } + + @Override + public void registerGaugeSample(GaugeModel sample) { + // Mock implementation for test purposes + } + + @Override + public String response() { + return "test"; + } + + @Override + public boolean isSupport(String form) { + return "mock".equals(form); + } + + @Override + public void registerCounterSample(CounterModel sample) { + // Mock implementation for test purposes + } + }; + + + + @Test + public void testInit() { + List collectors = Collections.singletonList(mockCollector); + long collectPeriod = 10L; + + reporter.init(collectors, collectPeriod); + + assertNotNull(reporter.m_executorService); + } + @Test + public void testIsSupport(){ + assertTrue(reporter.isSupport("mock")); + assertFalse(reporter.isSupport("mock1")); + } + + @Test + public void testUpdateMetricsData() { + MetricsModel mockSample = mock(MetricsModel.class); + when(mockSample.getType()).thenReturn(MeterType.GAUGE); + when(mockCollector.isSamplesUpdated()).thenReturn(true); + when(mockCollector.export()).thenReturn(Collections.singletonList(mockSample)); + + reporter.init(Collections.singletonList(mockCollector), 10L); + reporter.updateMetricsData(); + + verify(mockCollector, times(1)).isSamplesUpdated(); + verify(mockCollector, times(1)).export(); + verify(mockSample, times(1)).getType(); + } + + @Test + public void testGetTags() { + MetricsModel sample = mock(MetricsModel.class); + Map tags = new HashMap<>(); + tags.put("key1", "value1"); + tags.put("key2", "value2"); + + when(sample.getTags()).thenReturn(tags); + + String[][] result = reporter.getTags(sample); + + assertArrayEquals(new String[]{"key1", "key2"}, result[0]); + assertArrayEquals(new String[]{"value1", "value2"}, result[1]); + } +} diff --git a/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/exporter/DefaultApolloMetricsExporterFactoryTest.java b/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/exporter/DefaultApolloMetricsExporterFactoryTest.java new file mode 100644 index 00000000..dcded68e --- /dev/null +++ b/apollo-client/src/test/java/com/ctrip/framework/apollo/monitor/internal/exporter/DefaultApolloMetricsExporterFactoryTest.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; + +import static org.junit.Assert.assertNull; + +import com.ctrip.framework.apollo.build.MockInjector; +import com.ctrip.framework.apollo.core.ApolloClientSystemConsts; +import com.ctrip.framework.apollo.monitor.internal.collector.MetricsCollector; +import com.ctrip.framework.apollo.monitor.internal.exporter.internals.DefaultMetricsExporterFactory; +import com.ctrip.framework.apollo.util.ConfigUtil; +import java.util.ArrayList; +import java.util.List; +import org.junit.Test; + +public class DefaultApolloMetricsExporterFactoryTest { + + private DefaultMetricsExporterFactory defaultMetricsReporterFactory; + + public void setUp(String form, String period) { + if (form!=null){ + System.setProperty(ApolloClientSystemConsts.APOLLO_CLIENT_MONITOR_EXTERNAL_TYPE,form); + } + if (period!=null){ + System.setProperty(ApolloClientSystemConsts.APOLLO_CLIENT_MONITOR_EXTERNAL_EXPORT_PERIOD,period); + } + ConfigUtil mockConfigUtil = new ConfigUtil(); + defaultMetricsReporterFactory = new DefaultMetricsExporterFactory(); + MockInjector.setInstance(ConfigUtil.class, mockConfigUtil); + } + + @Test + public void testGetMetricsReporter_NoSupportedReporter() { + setUp("prometheus","300"); + List collectors = new ArrayList<>(); + assertNull(defaultMetricsReporterFactory.getMetricsReporter(collectors)); + } + + @Test + public void testGetMetricsReporter_NullForm() { + setUp(null,null); + List collectors = new ArrayList<>(); + MetricsExporter reporter = defaultMetricsReporterFactory.getMetricsReporter(collectors); + assertNull(reporter); + } +} 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..b28f7883 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,24 @@ 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 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/internals/DefaultMessageProducerManager.java b/apollo-core/src/main/java/com/ctrip/framework/apollo/tracer/internals/DefaultMessageProducerManager.java index 2490abdb..53204d89 100644 --- a/apollo-core/src/main/java/com/ctrip/framework/apollo/tracer/internals/DefaultMessageProducerManager.java +++ b/apollo-core/src/main/java/com/ctrip/framework/apollo/tracer/internals/DefaultMessageProducerManager.java @@ -26,18 +26,18 @@ * @author Jason Song(song_s@ctrip.com) */ public class DefaultMessageProducerManager implements MessageProducerManager { - private static MessageProducer producer; + private static MessageProducer producer; - public DefaultMessageProducerManager() { - if (ClassLoaderUtil.isClassPresent(CatNames.CAT_CLASS)) { - producer = new CatMessageProducer(); - } else { - producer = new NullMessageProducerManager().getProducer(); + public DefaultMessageProducerManager() { + if (ClassLoaderUtil.isClassPresent(CatNames.CAT_CLASS)) { + producer = new CatMessageProducer(); + } else { + producer = new NullMessageProducerManager().getProducer(); + } } - } - @Override - public MessageProducer getProducer() { - return producer; - } + @Override + public MessageProducer getProducer() { + return producer; + } } 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..b556b8ab 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. * @@ -59,4 +61,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..860c5f08 --- /dev/null +++ b/apollo-plugin/apollo-plugin-client-prometheus/pom.xml @@ -0,0 +1,46 @@ + + + + 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 + provided + + + + \ No newline at end of file diff --git a/apollo-plugin/apollo-plugin-client-prometheus/src/main/java/com/ctrip/framework/apollo/plugin/prometheus/PrometheusMetricExporter.java b/apollo-plugin/apollo-plugin-client-prometheus/src/main/java/com/ctrip/framework/apollo/plugin/prometheus/PrometheusMetricExporter.java new file mode 100644 index 00000000..76c921b5 --- /dev/null +++ b/apollo-plugin/apollo-plugin-client-prometheus/src/main/java/com/ctrip/framework/apollo/plugin/prometheus/PrometheusMetricExporter.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.plugin.prometheus; + +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.exporter.AbstractMetricsExporter; +import com.ctrip.framework.apollo.monitor.internal.exporter.MetricsExporter; +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; +import org.slf4j.LoggerFactory; + +/** + * @author Rawven + */ +public class PrometheusMetricExporter extends AbstractMetricsExporter implements MetricsExporter { + + private static final Logger logger = LoggerFactory.getLogger( + PrometheusMetricExporter.class); + private final CollectorRegistry registry; + private final Map map = new HashMap<>(); + private final String PROMETHEUS = "prometheus"; + + public PrometheusMetricExporter() { + this.registry = new CollectorRegistry(); + } + + @Override + public void doInit() { + + } + + @Override + public boolean isSupport(String form) { + return PROMETHEUS.equals(form); + } + + @Override + public void registerCounterSample(CounterModel sample) { + String[][] tags = getTags(sample); + Counter counter; + if (!map.containsKey(sample.getName())) { + counter = Counter.build() + .name(sample.getName()) + .help("apollo") + .labelNames(tags[0]) + .register(registry); + map.put(sample.getName(), counter); + } else { + counter = (Counter) map.get(sample.getName()); + } + counter.labels(tags[1]).inc(sample.getIncreaseValue()); + } + + @Override + public void registerGaugeSample(GaugeModel sample) { + String[][] tags = getTags(sample); + Gauge gauge; + if (!map.containsKey(sample.getName())) { + gauge = Gauge.build() + .name(sample.getName()) + .help("apollo") + .labelNames(tags[0]) + .register(registry); + map.put(sample.getName(), gauge); + } else { + gauge = (Gauge) map.get(sample.getName()); + } + gauge.labels(tags[1]).set(sample.getApplyValue()); + } + + + @Override + public String response() { + StringWriter writer = new StringWriter(); + try { + TextFormat.writeFormat(TextFormat.CONTENT_TYPE_OPENMETRICS_100, writer, + registry.metricFamilySamples()); + } catch (IOException e) { + logger.error("Write metrics to Prometheus format failed", e); + } + return writer.toString(); + } +} \ 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.MetricsExporter b/apollo-plugin/apollo-plugin-client-prometheus/src/main/resources/META-INF/services/com.ctrip.framework.apollo.monitor.internal.exporter.MetricsExporter new file mode 100644 index 00000000..51289143 --- /dev/null +++ b/apollo-plugin/apollo-plugin-client-prometheus/src/main/resources/META-INF/services/com.ctrip.framework.apollo.monitor.internal.exporter.MetricsExporter @@ -0,0 +1 @@ +com.ctrip.framework.apollo.plugin.prometheus.PrometheusMetricExporter \ 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