Skip to content

Commit e43ddf5

Browse files
authored
[OSPP]Add more observability in apollo config client (#74)
* feat(client): Add more observability in apollo config client * feat(client): add unit test * refactor: rollback meaningless change * docs: add CHANGES.md
1 parent 5fbfd0c commit e43ddf5

File tree

94 files changed

+5295
-34
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

94 files changed

+5295
-34
lines changed

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Apollo Java 2.4.0
77
------------------
88
* [Fix the Cannot enhance @Configuration bean definition issue](https://github.com/apolloconfig/apollo-java/pull/82)
99
* [Feature openapi query namespace support not fill item](https://github.com/apolloconfig/apollo-java/pull/83)
10+
* [Add more observability in apollo config client](https://github.com/apolloconfig/apollo-java/pull/74)
1011

1112
------------------
1213
All issues and pull requests are [here](https://github.com/apolloconfig/apollo-java/milestone/4?closed=1)

apollo-client/pom.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,17 @@
9797
<artifactId>mockserver-netty</artifactId>
9898
<scope>test</scope>
9999
</dependency>
100+
<dependency>
101+
<groupId>com.github.noconnor</groupId>
102+
<artifactId>junitperf</artifactId>
103+
<scope>test</scope>
104+
<exclusions>
105+
<exclusion>
106+
<groupId>ch.qos.logback</groupId>
107+
<artifactId>logback-classic</artifactId>
108+
</exclusion>
109+
</exclusions>
110+
</dependency>
100111
<!-- end of test -->
101112
</dependencies>
102113
</project>

apollo-client/src/main/java/com/ctrip/framework/apollo/ConfigService.java

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
import com.ctrip.framework.apollo.core.ConfigConsts;
2121
import com.ctrip.framework.apollo.core.enums.ConfigFileFormat;
2222
import com.ctrip.framework.apollo.internals.ConfigManager;
23+
import com.ctrip.framework.apollo.internals.ConfigMonitorInitializer;
24+
import com.ctrip.framework.apollo.monitor.api.ConfigMonitor;
2325
import com.ctrip.framework.apollo.spi.ConfigFactory;
2426
import com.ctrip.framework.apollo.spi.ConfigRegistry;
2527

@@ -30,19 +32,31 @@
3032
*/
3133
public class ConfigService {
3234
private static final ConfigService s_instance = new ConfigService();
33-
35+
private volatile ConfigMonitor m_configMonitor;
3436
private volatile ConfigManager m_configManager;
3537
private volatile ConfigRegistry m_configRegistry;
36-
38+
39+
private ConfigMonitor getMonitor() {
40+
getManager();
41+
if (m_configMonitor == null) {
42+
synchronized (this) {
43+
if (m_configMonitor == null) {
44+
m_configMonitor = ApolloInjector.getInstance(ConfigMonitor.class);
45+
}
46+
}
47+
}
48+
return m_configMonitor;
49+
}
50+
3751
private ConfigManager getManager() {
3852
if (m_configManager == null) {
3953
synchronized (this) {
4054
if (m_configManager == null) {
4155
m_configManager = ApolloInjector.getInstance(ConfigManager.class);
56+
ConfigMonitorInitializer.initialize();
4257
}
4358
}
4459
}
45-
4660
return m_configManager;
4761
}
4862

@@ -81,6 +95,10 @@ public static ConfigFile getConfigFile(String namespace, ConfigFileFormat config
8195
return s_instance.getManager().getConfigFile(namespace, configFileFormat);
8296
}
8397

98+
public static ConfigMonitor getConfigMonitor(){
99+
return s_instance.getMonitor();
100+
}
101+
84102
static void setConfig(Config config) {
85103
setConfig(ConfigConsts.NAMESPACE_APPLICATION, config);
86104
}

apollo-client/src/main/java/com/ctrip/framework/apollo/internals/AbstractConfig.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
public abstract class AbstractConfig implements Config {
5454
private static final Logger logger = LoggerFactory.getLogger(AbstractConfig.class);
5555

56-
private static final ExecutorService m_executorService;
56+
protected static final ExecutorService m_executorService;
5757

5858
private final List<ConfigChangeListener> m_listeners = Lists.newCopyOnWriteArrayList();
5959
private final Map<ConfigChangeListener, Set<String>> m_interestedKeys = Maps.newConcurrentMap();

apollo-client/src/main/java/com/ctrip/framework/apollo/internals/AbstractConfigFile.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
*/
1717
package com.ctrip.framework.apollo.internals;
1818

19+
20+
import static com.ctrip.framework.apollo.monitor.internal.ApolloClientMonitorConstant.*;
1921
import com.ctrip.framework.apollo.build.ApolloInjector;
2022
import com.ctrip.framework.apollo.core.utils.DeferredLoggerFactory;
2123
import com.ctrip.framework.apollo.enums.ConfigSourceType;
@@ -43,7 +45,7 @@
4345
*/
4446
public abstract class AbstractConfigFile implements ConfigFile, RepositoryChangeListener {
4547
private static final Logger logger = DeferredLoggerFactory.getLogger(AbstractConfigFile.class);
46-
private static ExecutorService m_executorService;
48+
protected static ExecutorService m_executorService;
4749
protected final ConfigRepository m_configRepository;
4850
protected final String m_namespace;
4951
protected final AtomicReference<Properties> m_configProperties;
@@ -112,7 +114,7 @@ public synchronized void onRepositoryChange(String namespace, Properties newProp
112114

113115
this.fireConfigChange(new ConfigFileChangeEvent(m_namespace, oldValue, newValue, changeType));
114116

115-
Tracer.logEvent("Apollo.Client.ConfigChanges", m_namespace);
117+
Tracer.logEvent(APOLLO_CLIENT_CONFIGCHANGES, m_namespace);
116118
}
117119

118120
@Override

apollo-client/src/main/java/com/ctrip/framework/apollo/internals/AbstractConfigRepository.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
*/
1717
package com.ctrip.framework.apollo.internals;
1818

19+
import static com.ctrip.framework.apollo.monitor.internal.ApolloClientMonitorConstant.*;
1920
import com.ctrip.framework.apollo.build.ApolloInjector;
2021
import com.ctrip.framework.apollo.util.factory.PropertiesFactory;
2122
import java.util.List;
@@ -41,7 +42,7 @@ protected boolean trySync() {
4142
sync();
4243
return true;
4344
} catch (Throwable ex) {
44-
Tracer.logEvent("ApolloConfigException", ExceptionUtil.getDetailMessage(ex));
45+
Tracer.logEvent(APOLLO_CONFIG_EXCEPTION, ExceptionUtil.getDetailMessage(ex));
4546
logger
4647
.warn("Sync config failed, will retry. Repository {}, reason: {}", this.getClass(), ExceptionUtil
4748
.getDetailMessage(ex));
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
/*
2+
* Copyright 2022 Apollo Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
*/
17+
package com.ctrip.framework.apollo.internals;
18+
19+
import static com.ctrip.framework.apollo.monitor.internal.ApolloClientMonitorConstant.MBEAN_NAME;
20+
21+
import com.ctrip.framework.apollo.build.ApolloInjector;
22+
import com.ctrip.framework.apollo.core.utils.ClassLoaderUtil;
23+
import com.ctrip.framework.apollo.monitor.internal.exporter.AbstractApolloClientMetricsExporter;
24+
import com.ctrip.framework.apollo.monitor.internal.exporter.ApolloClientMetricsExporter;
25+
import com.ctrip.framework.apollo.monitor.internal.jmx.ApolloClientJmxMBeanRegister;
26+
import com.ctrip.framework.apollo.monitor.internal.ApolloClientMonitorContext;
27+
import com.ctrip.framework.apollo.monitor.internal.listener.impl.DefaultApolloClientBootstrapArgsApi;
28+
import com.ctrip.framework.apollo.monitor.internal.listener.impl.DefaultApolloClientExceptionApi;
29+
import com.ctrip.framework.apollo.monitor.internal.listener.impl.DefaultApolloClientNamespaceApi;
30+
import com.ctrip.framework.apollo.monitor.internal.listener.impl.DefaultApolloClientThreadPoolApi;
31+
import com.ctrip.framework.apollo.monitor.internal.exporter.ApolloClientMetricsExporterFactory;
32+
import com.ctrip.framework.apollo.monitor.internal.tracer.ApolloClientMonitorMessageProducer;
33+
import com.ctrip.framework.apollo.monitor.internal.tracer.ApolloClientMessageProducerComposite;
34+
import com.ctrip.framework.apollo.tracer.internals.NullMessageProducer;
35+
import com.ctrip.framework.apollo.tracer.internals.cat.CatMessageProducer;
36+
import com.ctrip.framework.apollo.tracer.internals.cat.CatNames;
37+
import com.ctrip.framework.apollo.tracer.spi.MessageProducer;
38+
import com.ctrip.framework.apollo.util.ConfigUtil;
39+
import com.ctrip.framework.foundation.internals.ServiceBootstrap;
40+
import com.google.common.collect.Lists;
41+
import java.util.List;
42+
43+
/**
44+
* ConfigMonitorInitializer initializes the Apollo Config Monitor.
45+
*/
46+
public class ConfigMonitorInitializer {
47+
48+
private static final ApolloClientMonitorContext MONITOR_CONTEXT = ApolloInjector.getInstance(
49+
ApolloClientMonitorContext.class);
50+
protected static volatile boolean hasInitialized = false;
51+
private static ConfigUtil m_configUtil = ApolloInjector.getInstance(ConfigUtil.class);
52+
53+
public static void initialize() {
54+
if (m_configUtil.isClientMonitorEnabled() && !hasInitialized) {
55+
synchronized (ConfigMonitorInitializer.class) {
56+
if (!hasInitialized) {
57+
doInit();
58+
hasInitialized = true;
59+
}
60+
}
61+
}
62+
}
63+
64+
private static void doInit() {
65+
initializeMetricsEventListener();
66+
initializeMetricsExporter();
67+
initializeJmxMonitoring();
68+
}
69+
70+
71+
private static void initializeJmxMonitoring() {
72+
if (m_configUtil.isClientMonitorJmxEnabled()) {
73+
MONITOR_CONTEXT.getApolloClientMonitorEventListeners().forEach(metricsListener ->
74+
ApolloClientJmxMBeanRegister.register(
75+
MBEAN_NAME + metricsListener.getName(), metricsListener)
76+
);
77+
}
78+
}
79+
80+
private static void initializeMetricsEventListener() {
81+
ConfigManager configManager = ApolloInjector.getInstance(
82+
ConfigManager.class);
83+
DefaultApolloClientBootstrapArgsApi defaultApolloClientBootstrapArgsApi = new DefaultApolloClientBootstrapArgsApi(
84+
m_configUtil);
85+
DefaultApolloClientExceptionApi defaultApolloClientExceptionApi = new DefaultApolloClientExceptionApi(m_configUtil);
86+
DefaultApolloClientNamespaceApi defaultApolloClientNamespaceApi = new DefaultApolloClientNamespaceApi(
87+
configManager);
88+
DefaultApolloClientThreadPoolApi defaultApolloClientThreadPoolApi = new DefaultApolloClientThreadPoolApi(
89+
RemoteConfigRepository.m_executorService,
90+
AbstractConfig.m_executorService, AbstractConfigFile.m_executorService,
91+
AbstractApolloClientMetricsExporter.m_executorService);
92+
93+
MONITOR_CONTEXT.setApolloClientBootstrapArgsMonitorApi(defaultApolloClientBootstrapArgsApi);
94+
MONITOR_CONTEXT.setApolloClientExceptionMonitorApi(defaultApolloClientExceptionApi);
95+
MONITOR_CONTEXT.setApolloClientNamespaceMonitorApi(defaultApolloClientNamespaceApi);
96+
MONITOR_CONTEXT.setApolloClientThreadPoolMonitorApi(defaultApolloClientThreadPoolApi);
97+
MONITOR_CONTEXT.setApolloClientMonitorEventListeners(
98+
Lists.newArrayList(defaultApolloClientBootstrapArgsApi,
99+
defaultApolloClientNamespaceApi, defaultApolloClientThreadPoolApi,
100+
defaultApolloClientExceptionApi));
101+
}
102+
103+
private static void initializeMetricsExporter(
104+
) {
105+
ApolloClientMetricsExporterFactory exporterFactory = ApolloInjector.getInstance(
106+
ApolloClientMetricsExporterFactory.class);
107+
ApolloClientMetricsExporter metricsReporter = exporterFactory.getMetricsReporter(
108+
MONITOR_CONTEXT.getApolloClientMonitorEventListeners());
109+
if (metricsReporter != null) {
110+
MONITOR_CONTEXT.setApolloClientMetricsExporter(metricsReporter);
111+
}
112+
}
113+
114+
public static ApolloClientMessageProducerComposite initializeMessageProducerComposite() {
115+
List<MessageProducer> producers = ServiceBootstrap.loadAllOrdered(MessageProducer.class);
116+
117+
if (m_configUtil.isClientMonitorEnabled()) {
118+
producers.add(new ApolloClientMonitorMessageProducer());
119+
}
120+
121+
if (ClassLoaderUtil.isClassPresent(CatNames.CAT_CLASS)) {
122+
producers.add(new CatMessageProducer());
123+
}
124+
125+
if (producers.isEmpty()) {
126+
producers.add(new NullMessageProducer());
127+
}
128+
129+
return new ApolloClientMessageProducerComposite(producers);
130+
}
131+
132+
// for test only
133+
protected static void reset() {
134+
hasInitialized = false;
135+
m_configUtil = ApolloInjector.getInstance(ConfigUtil.class);
136+
137+
}
138+
}

apollo-client/src/main/java/com/ctrip/framework/apollo/internals/ConfigServiceLocator.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
*/
1717
package com.ctrip.framework.apollo.internals;
1818

19+
import static com.ctrip.framework.apollo.monitor.internal.ApolloClientMonitorConstant.*;
20+
1921
import com.ctrip.framework.apollo.core.ApolloClientSystemConsts;
2022
import com.ctrip.framework.apollo.core.ServiceNameConsts;
2123
import com.ctrip.framework.apollo.core.utils.DeferredLoggerFactory;
@@ -218,7 +220,7 @@ private void schedulePeriodicRefresh() {
218220
@Override
219221
public void run() {
220222
logger.debug("refresh config services");
221-
Tracer.logEvent("Apollo.MetaService", "periodicRefresh");
223+
Tracer.logEvent(APOLLO_META_SERVICE, "periodicRefresh");
222224
tryUpdateConfigServices();
223225
}
224226
}, m_configUtil.getRefreshInterval(), m_configUtil.getRefreshInterval(),
@@ -258,7 +260,7 @@ private synchronized void updateConfigServices() {
258260
setConfigServices(services);
259261
return;
260262
} catch (Throwable ex) {
261-
Tracer.logEvent("ApolloConfigException", ExceptionUtil.getDetailMessage(ex));
263+
Tracer.logEvent(APOLLO_CONFIG_EXCEPTION, ExceptionUtil.getDetailMessage(ex));
262264
transaction.setStatus(ex);
263265
exception = ex;
264266
} finally {
@@ -302,6 +304,6 @@ private void logConfigServices(List<ServiceDTO> serviceDtos) {
302304
}
303305

304306
private void logConfigService(String serviceUrl) {
305-
Tracer.logEvent("Apollo.Config.Services", serviceUrl);
307+
Tracer.logEvent(APOLLO_CONFIG_SERVICES, serviceUrl);
306308
}
307309
}

apollo-client/src/main/java/com/ctrip/framework/apollo/internals/DefaultConfig.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
*/
1717
package com.ctrip.framework.apollo.internals;
1818

19+
import static com.ctrip.framework.apollo.monitor.internal.ApolloClientMonitorConstant.*;
1920
import com.ctrip.framework.apollo.core.utils.DeferredLoggerFactory;
2021
import com.ctrip.framework.apollo.enums.ConfigSourceType;
2122
import com.google.common.collect.Maps;
@@ -236,7 +237,7 @@ public synchronized void onRepositoryChange(String namespace, Properties newProp
236237

237238
this.fireConfigChange(m_namespace, actualChanges);
238239

239-
Tracer.logEvent("Apollo.Client.ConfigChanges", m_namespace);
240+
Tracer.logEvent(APOLLO_CLIENT_CONFIGCHANGES, m_namespace);
240241
}
241242

242243
private void updateConfig(Properties newConfigProperties, ConfigSourceType sourceType) {

apollo-client/src/main/java/com/ctrip/framework/apollo/internals/DefaultConfigManager.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,18 @@
1616
*/
1717
package com.ctrip.framework.apollo.internals;
1818

19-
import java.util.Map;
19+
import static com.ctrip.framework.apollo.monitor.internal.ApolloClientMonitorConstant.APOLLO_CLIENT_NAMESPACE_USAGE;
2020

2121
import com.ctrip.framework.apollo.Config;
2222
import com.ctrip.framework.apollo.ConfigFile;
2323
import com.ctrip.framework.apollo.build.ApolloInjector;
2424
import com.ctrip.framework.apollo.core.enums.ConfigFileFormat;
25+
import com.ctrip.framework.apollo.enums.ConfigSourceType;
2526
import com.ctrip.framework.apollo.spi.ConfigFactory;
2627
import com.ctrip.framework.apollo.spi.ConfigFactoryManager;
28+
import com.ctrip.framework.apollo.tracer.Tracer;
2729
import com.google.common.collect.Maps;
30+
import java.util.Map;
2831

2932
/**
3033
* @author Jason Song(song_s@ctrip.com)
@@ -44,7 +47,7 @@ public DefaultConfigManager() {
4447
@Override
4548
public Config getConfig(String namespace) {
4649
Config config = m_configs.get(namespace);
47-
50+
4851
if (config == null) {
4952
Object lock = m_configLocks.computeIfAbsent(namespace, key -> new Object());
5053
synchronized (lock) {
@@ -58,6 +61,9 @@ public Config getConfig(String namespace) {
5861
}
5962
}
6063
}
64+
if (!ConfigSourceType.NONE.equals(config.getSourceType())) {
65+
Tracer.logMetricsForCount(APOLLO_CLIENT_NAMESPACE_USAGE + ":" + namespace);
66+
}
6167

6268
return config;
6369
}

0 commit comments

Comments
 (0)