Commit 055d0519 authored by Jason Song's avatar Jason Song

Refactor logging and add meta service refresh

parent 24db89d0
...@@ -31,8 +31,8 @@ public class ComponentConfigurator extends AbstractResourceConfigurator { ...@@ -31,8 +31,8 @@ public class ComponentConfigurator extends AbstractResourceConfigurator {
all.add(A(DefaultConfigRegistry.class)); all.add(A(DefaultConfigRegistry.class));
all.add(A(DefaultConfigFactoryManager.class)); all.add(A(DefaultConfigFactoryManager.class));
all.add(A(ConfigUtil.class)); all.add(A(ConfigUtil.class));
all.add(A(ConfigServiceLocator.class));
all.add(A(HttpUtil.class)); all.add(A(HttpUtil.class));
all.add(A(ConfigServiceLocator.class));
return all; return all;
} }
......
...@@ -9,6 +9,7 @@ import com.ctrip.apollo.ConfigChangeListener; ...@@ -9,6 +9,7 @@ import com.ctrip.apollo.ConfigChangeListener;
import com.ctrip.apollo.enums.PropertyChangeType; import com.ctrip.apollo.enums.PropertyChangeType;
import com.ctrip.apollo.model.ConfigChange; import com.ctrip.apollo.model.ConfigChange;
import com.ctrip.apollo.model.ConfigChangeEvent; import com.ctrip.apollo.model.ConfigChangeEvent;
import com.ctrip.apollo.util.ExceptionUtil;
import com.dianping.cat.Cat; import com.dianping.cat.Cat;
import org.slf4j.Logger; import org.slf4j.Logger;
...@@ -38,7 +39,8 @@ public abstract class AbstractConfig implements Config { ...@@ -38,7 +39,8 @@ public abstract class AbstractConfig implements Config {
listener.onChange(changeEvent); listener.onChange(changeEvent);
} catch (Throwable ex) { } catch (Throwable ex) {
Cat.logError(ex); Cat.logError(ex);
logger.error("Failed to invoke config change listener {}", listener.getClass(), ex); logger.error("Failed to invoke config change listener {}", listener.getClass(), ExceptionUtil
.getDetailMessage(ex));
} }
} }
} }
......
...@@ -2,6 +2,7 @@ package com.ctrip.apollo.internals; ...@@ -2,6 +2,7 @@ package com.ctrip.apollo.internals;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.ctrip.apollo.util.ExceptionUtil;
import com.dianping.cat.Cat; import com.dianping.cat.Cat;
import org.slf4j.Logger; import org.slf4j.Logger;
...@@ -22,7 +23,9 @@ public abstract class AbstractConfigRepository implements ConfigRepository { ...@@ -22,7 +23,9 @@ public abstract class AbstractConfigRepository implements ConfigRepository {
sync(); sync();
} catch (Throwable ex) { } catch (Throwable ex) {
Cat.logError(ex); Cat.logError(ex);
logger.warn("Sync config failed with repository {}, reason: {}", this.getClass(), ex); logger
.warn("Sync config failed with repository {}, reason: {}", this.getClass(), ExceptionUtil
.getDetailMessage(ex));
} }
} }
...@@ -46,7 +49,9 @@ public abstract class AbstractConfigRepository implements ConfigRepository { ...@@ -46,7 +49,9 @@ public abstract class AbstractConfigRepository implements ConfigRepository {
listener.onRepositoryChange(namespace, newProperties); listener.onRepositoryChange(namespace, newProperties);
} catch (Throwable ex) { } catch (Throwable ex) {
Cat.logError(ex); Cat.logError(ex);
logger.error("Failed to invoke repository change listener {}", listener.getClass(), ex); logger.error("Failed to invoke repository change listener {}", listener.getClass(),
ExceptionUtil
.getDetailMessage(ex));
} }
} }
} }
......
...@@ -4,6 +4,7 @@ import com.google.common.collect.Lists; ...@@ -4,6 +4,7 @@ import com.google.common.collect.Lists;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
import com.ctrip.apollo.core.dto.ServiceDTO; import com.ctrip.apollo.core.dto.ServiceDTO;
import com.ctrip.apollo.core.utils.ApolloThreadFactory;
import com.ctrip.apollo.util.ConfigUtil; import com.ctrip.apollo.util.ConfigUtil;
import com.ctrip.apollo.util.http.HttpRequest; import com.ctrip.apollo.util.http.HttpRequest;
import com.ctrip.apollo.util.http.HttpResponse; import com.ctrip.apollo.util.http.HttpResponse;
...@@ -12,22 +13,30 @@ import com.dianping.cat.Cat; ...@@ -12,22 +13,30 @@ import com.dianping.cat.Cat;
import com.dianping.cat.message.Message; import com.dianping.cat.message.Message;
import com.dianping.cat.message.Transaction; import com.dianping.cat.message.Transaction;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.unidal.lookup.annotation.Inject; import org.unidal.lookup.annotation.Inject;
import org.unidal.lookup.annotation.Named; import org.unidal.lookup.annotation.Named;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.List; import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
@Named(type = ConfigServiceLocator.class) @Named(type = ConfigServiceLocator.class)
public class ConfigServiceLocator { public class ConfigServiceLocator implements Initializable{
private static final Logger logger = LoggerFactory.getLogger(ConfigServiceLocator.class);
@Inject @Inject
private HttpUtil m_httpUtil; private HttpUtil m_httpUtil;
@Inject @Inject
private ConfigUtil m_configUtil; private ConfigUtil m_configUtil;
private AtomicReference<List<ServiceDTO>> m_configServices; private AtomicReference<List<ServiceDTO>> m_configServices;
private Type m_responseType; private Type m_responseType;
private ScheduledExecutorService m_executorService;
/** /**
* Create a config service locator. * Create a config service locator.
...@@ -37,6 +46,14 @@ public class ConfigServiceLocator { ...@@ -37,6 +46,14 @@ public class ConfigServiceLocator {
m_configServices = new AtomicReference<>(initial); m_configServices = new AtomicReference<>(initial);
m_responseType = new TypeToken<List<ServiceDTO>>() { m_responseType = new TypeToken<List<ServiceDTO>>() {
}.getType(); }.getType();
this.m_executorService = Executors.newScheduledThreadPool(1,
ApolloThreadFactory.create("ConfigServiceLocator", true));
}
@Override
public void initialize() throws InitializationException {
this.tryUpdateConfigServices();
this.schedulePeriodicRefresh();
} }
/** /**
...@@ -52,8 +69,31 @@ public class ConfigServiceLocator { ...@@ -52,8 +69,31 @@ public class ConfigServiceLocator {
return m_configServices.get(); return m_configServices.get();
} }
private void tryUpdateConfigServices() {
try {
updateConfigServices();
} catch (Throwable ex) {
//ignore
}
}
private void schedulePeriodicRefresh() {
this.m_executorService.scheduleAtFixedRate(
new Runnable() {
@Override
public void run() {
logger.debug("refresh config services");
Transaction transaction = Cat.newTransaction("Apollo.MetaService", "periodicRefresh");
tryUpdateConfigServices();
transaction.setStatus(Message.SUCCESS);
transaction.complete();
}
}, m_configUtil.getRefreshInterval(), m_configUtil.getRefreshInterval(),
m_configUtil.getRefreshTimeUnit());
}
//TODO periodically update config services //TODO periodically update config services
private void updateConfigServices() { private synchronized void updateConfigServices() {
String domainName = m_configUtil.getMetaServerDomainName(); String domainName = m_configUtil.getMetaServerDomainName();
String url = domainName + "/services/config"; String url = domainName + "/services/config";
......
...@@ -6,6 +6,7 @@ import com.ctrip.apollo.core.utils.ClassLoaderUtil; ...@@ -6,6 +6,7 @@ import com.ctrip.apollo.core.utils.ClassLoaderUtil;
import com.ctrip.apollo.enums.PropertyChangeType; import com.ctrip.apollo.enums.PropertyChangeType;
import com.ctrip.apollo.model.ConfigChange; import com.ctrip.apollo.model.ConfigChange;
import com.ctrip.apollo.model.ConfigChangeEvent; import com.ctrip.apollo.model.ConfigChangeEvent;
import com.ctrip.apollo.util.ExceptionUtil;
import com.dianping.cat.Cat; import com.dianping.cat.Cat;
import org.slf4j.Logger; import org.slf4j.Logger;
...@@ -50,7 +51,7 @@ public class DefaultConfig extends AbstractConfig implements RepositoryChangeLis ...@@ -50,7 +51,7 @@ public class DefaultConfig extends AbstractConfig implements RepositoryChangeLis
} catch (Throwable ex) { } catch (Throwable ex) {
Cat.logError(ex); Cat.logError(ex);
logger.warn("Init Apollo Local Config failed - namespace: {}, reason: {}.", logger.warn("Init Apollo Local Config failed - namespace: {}, reason: {}.",
m_namespace, ex); m_namespace, ExceptionUtil.getDetailMessage(ex));
} }
} }
......
...@@ -3,6 +3,7 @@ package com.ctrip.apollo.internals; ...@@ -3,6 +3,7 @@ package com.ctrip.apollo.internals;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.ctrip.apollo.util.ConfigUtil; import com.ctrip.apollo.util.ConfigUtil;
import com.ctrip.apollo.util.ExceptionUtil;
import com.dianping.cat.Cat; import com.dianping.cat.Cat;
import com.dianping.cat.message.Message; import com.dianping.cat.message.Message;
import com.dianping.cat.message.Transaction; import com.dianping.cat.message.Transaction;
...@@ -122,7 +123,7 @@ public class LocalFileConfigRepository extends AbstractConfigRepository ...@@ -122,7 +123,7 @@ public class LocalFileConfigRepository extends AbstractConfigRepository
Cat.logError(ex); Cat.logError(ex);
logger logger
.warn("Sync config from fallback repository {} failed, reason: {}", m_fallback.getClass(), .warn("Sync config from fallback repository {} failed, reason: {}", m_fallback.getClass(),
ex); ExceptionUtil.getDetailMessage(ex));
} }
} }
...@@ -186,7 +187,8 @@ public class LocalFileConfigRepository extends AbstractConfigRepository ...@@ -186,7 +187,8 @@ public class LocalFileConfigRepository extends AbstractConfigRepository
} catch (IOException ex) { } catch (IOException ex) {
Cat.logError(ex); Cat.logError(ex);
transaction.setStatus(ex); transaction.setStatus(ex);
logger.warn("Persist local cache file {} failed, reason: {}.", file.getAbsolutePath(), ex); logger.warn("Persist local cache file {} failed, reason: {}.", file.getAbsolutePath(),
ExceptionUtil.getDetailMessage(ex));
} finally { } finally {
if (out != null) { if (out != null) {
try { try {
......
...@@ -12,6 +12,7 @@ import com.ctrip.apollo.core.dto.ApolloConfigNotification; ...@@ -12,6 +12,7 @@ import com.ctrip.apollo.core.dto.ApolloConfigNotification;
import com.ctrip.apollo.core.dto.ServiceDTO; import com.ctrip.apollo.core.dto.ServiceDTO;
import com.ctrip.apollo.core.utils.ApolloThreadFactory; import com.ctrip.apollo.core.utils.ApolloThreadFactory;
import com.ctrip.apollo.util.ConfigUtil; import com.ctrip.apollo.util.ConfigUtil;
import com.ctrip.apollo.util.ExceptionUtil;
import com.ctrip.apollo.util.http.HttpRequest; import com.ctrip.apollo.util.http.HttpRequest;
import com.ctrip.apollo.util.http.HttpResponse; import com.ctrip.apollo.util.http.HttpResponse;
import com.ctrip.apollo.util.http.HttpUtil; import com.ctrip.apollo.util.http.HttpUtil;
...@@ -96,6 +97,7 @@ public class RemoteConfigRepository extends AbstractConfigRepository { ...@@ -96,6 +97,7 @@ public class RemoteConfigRepository extends AbstractConfigRepository {
new Runnable() { new Runnable() {
@Override @Override
public void run() { public void run() {
logger.debug("refresh config for namespace: {}", m_namespace);
Transaction transaction = Cat.newTransaction("Apollo.ConfigService", "periodicRefresh"); Transaction transaction = Cat.newTransaction("Apollo.ConfigService", "periodicRefresh");
trySync(); trySync();
transaction.setStatus(Message.SUCCESS); transaction.setStatus(Message.SUCCESS);
...@@ -262,8 +264,8 @@ public class RemoteConfigRepository extends AbstractConfigRepository { ...@@ -262,8 +264,8 @@ public class RemoteConfigRepository extends AbstractConfigRepository {
transaction.addData("StatusCode", response.getStatusCode()); transaction.addData("StatusCode", response.getStatusCode());
transaction.setStatus(Message.SUCCESS); transaction.setStatus(Message.SUCCESS);
} catch (Throwable ex) { } catch (Throwable ex) {
logger.warn("Long polling failed for appId: {}, cluster: {}, namespace: {}, reason: {}", logger.warn("Long polling failed for appId: {}, cluster: {}, namespace: {}",
appId, cluster, m_namespace, ex); appId, cluster, m_namespace, ExceptionUtil.getDetailMessage(ex));
lastServiceDto = null; lastServiceDto = null;
Cat.logError(ex); Cat.logError(ex);
if (transaction != null) { if (transaction != null) {
......
...@@ -5,6 +5,7 @@ import com.google.common.collect.Maps; ...@@ -5,6 +5,7 @@ import com.google.common.collect.Maps;
import com.ctrip.apollo.model.ConfigChange; import com.ctrip.apollo.model.ConfigChange;
import com.ctrip.apollo.model.ConfigChangeEvent; import com.ctrip.apollo.model.ConfigChangeEvent;
import com.ctrip.apollo.util.ExceptionUtil;
import com.dianping.cat.Cat; import com.dianping.cat.Cat;
import org.slf4j.Logger; import org.slf4j.Logger;
...@@ -41,7 +42,8 @@ public class SimpleConfig extends AbstractConfig implements RepositoryChangeList ...@@ -41,7 +42,8 @@ public class SimpleConfig extends AbstractConfig implements RepositoryChangeList
m_configRepository.addChangeListener(this); m_configRepository.addChangeListener(this);
} catch (Throwable ex) { } catch (Throwable ex) {
Cat.logError(ex); Cat.logError(ex);
logger.warn("Init Apollo Simple Config failed - namespace: {}, reason: {}", m_namespace, ex); logger.warn("Init Apollo Simple Config failed - namespace: {}, reason: {}", m_namespace,
ExceptionUtil.getDetailMessage(ex));
} }
} }
......
...@@ -5,6 +5,7 @@ import com.ctrip.apollo.core.utils.ClassLoaderUtil; ...@@ -5,6 +5,7 @@ import com.ctrip.apollo.core.utils.ClassLoaderUtil;
import com.ctrip.apollo.internals.DefaultConfig; import com.ctrip.apollo.internals.DefaultConfig;
import com.ctrip.apollo.internals.LocalFileConfigRepository; import com.ctrip.apollo.internals.LocalFileConfigRepository;
import com.ctrip.apollo.internals.RemoteConfigRepository; import com.ctrip.apollo.internals.RemoteConfigRepository;
import com.ctrip.apollo.util.ExceptionUtil;
import com.dianping.cat.Cat; import com.dianping.cat.Cat;
import com.dianping.cat.message.Message; import com.dianping.cat.message.Message;
import com.dianping.cat.message.Transaction; import com.dianping.cat.message.Transaction;
...@@ -48,7 +49,7 @@ public class DefaultConfigFactory implements ConfigFactory { ...@@ -48,7 +49,7 @@ public class DefaultConfigFactory implements ConfigFactory {
transaction.setStatus(ex); transaction.setStatus(ex);
logger.warn( logger.warn(
"Unable to create local config cache directory {}, reason: {}. Will not able to cache config file.", "Unable to create local config cache directory {}, reason: {}. Will not able to cache config file.",
baseDir, ex); baseDir, ExceptionUtil.getDetailMessage(ex));
} finally { } finally {
transaction.complete(); transaction.complete();
} }
......
package com.ctrip.apollo.util;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public class ExceptionUtil {
public static String getDetailMessage(Throwable ex) {
if (ex == null) {
return "";
}
if (ex.getCause() != null) {
return String.format("%s [Cause: %s]", ex.getMessage(), getDetailMessage(ex.getCause()));
}
return ex.getMessage();
}
}
...@@ -228,12 +228,13 @@ public class ConfigIntegrationTest extends BaseIntegrationTest { ...@@ -228,12 +228,13 @@ public class ConfigIntegrationTest extends BaseIntegrationTest {
final String someValue = "someValue"; final String someValue = "someValue";
final String anotherValue = "anotherValue"; final String anotherValue = "anotherValue";
long pollTimeoutInMS = 50;
Map<String, String> configurations = Maps.newHashMap(); Map<String, String> configurations = Maps.newHashMap();
configurations.put(someKey, someValue); configurations.put(someKey, someValue);
ApolloConfig apolloConfig = assembleApolloConfig(configurations); ApolloConfig apolloConfig = assembleApolloConfig(configurations);
ContextHandler configHandler = mockConfigServerHandler(HttpServletResponse.SC_OK, apolloConfig); ContextHandler configHandler = mockConfigServerHandler(HttpServletResponse.SC_OK, apolloConfig);
ContextHandler pollHandler = ContextHandler pollHandler =
mockPollNotificationHandler(50, HttpServletResponse.SC_OK, mockPollNotificationHandler(pollTimeoutInMS, HttpServletResponse.SC_OK,
new ApolloConfigNotification(apolloConfig.getAppId(), apolloConfig.getCluster(), new ApolloConfigNotification(apolloConfig.getAppId(), apolloConfig.getCluster(),
apolloConfig.getNamespace()), false); apolloConfig.getNamespace()), false);
...@@ -244,7 +245,7 @@ public class ConfigIntegrationTest extends BaseIntegrationTest { ...@@ -244,7 +245,7 @@ public class ConfigIntegrationTest extends BaseIntegrationTest {
apolloConfig.getConfigurations().put(someKey, anotherValue); apolloConfig.getConfigurations().put(someKey, anotherValue);
TimeUnit.MILLISECONDS.sleep(60); TimeUnit.MILLISECONDS.sleep(pollTimeoutInMS * 3);
assertEquals(anotherValue, config.getProperty(someKey, null)); assertEquals(anotherValue, config.getProperty(someKey, null));
......
...@@ -12,6 +12,7 @@ import com.ctrip.apollo.util.http.HttpRequest; ...@@ -12,6 +12,7 @@ import com.ctrip.apollo.util.http.HttpRequest;
import com.ctrip.apollo.util.http.HttpResponse; import com.ctrip.apollo.util.http.HttpResponse;
import com.ctrip.apollo.util.http.HttpUtil; import com.ctrip.apollo.util.http.HttpUtil;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
...@@ -181,6 +182,11 @@ public class RemoteConfigRepositoryTest extends ComponentTestCase { ...@@ -181,6 +182,11 @@ public class RemoteConfigRepositoryTest extends ComponentTestCase {
when(serviceDTO.getHomepageUrl()).thenReturn(someServerUrl); when(serviceDTO.getHomepageUrl()).thenReturn(someServerUrl);
return Lists.newArrayList(serviceDTO); return Lists.newArrayList(serviceDTO);
} }
@Override
public void initialize() throws InitializationException {
//do nothing
}
} }
public static class MockHttpUtil extends HttpUtil { public static class MockHttpUtil extends HttpUtil {
......
...@@ -30,9 +30,11 @@ import javax.servlet.http.HttpServletResponse; ...@@ -30,9 +30,11 @@ import javax.servlet.http.HttpServletResponse;
@RequestMapping("/notifications") @RequestMapping("/notifications")
public class NotificationController { public class NotificationController {
private static final Logger logger = LoggerFactory.getLogger(NotificationController.class); private static final Logger logger = LoggerFactory.getLogger(NotificationController.class);
private final static long TIMEOUT = 60 * 60 * 1000;//60 MINUTES private final static long TIMEOUT = 120 * 60 * 1000;//120 MINUTES
private final Multimap<String, DeferredResult<ApolloConfigNotification>> deferredResults = private final Multimap<String, DeferredResult<ApolloConfigNotification>> deferredResults =
Multimaps.synchronizedSetMultimap(HashMultimap.create()); Multimaps.synchronizedSetMultimap(HashMultimap.create());
private final Multimap<DeferredResult<ApolloConfigNotification>, String> deferredResultReversed =
Multimaps.synchronizedSetMultimap(HashMultimap.create());
{ {
startRandomChange(); startRandomChange();
...@@ -43,12 +45,15 @@ public class NotificationController { ...@@ -43,12 +45,15 @@ public class NotificationController {
@RequestParam(value = "appId") String appId, @RequestParam(value = "appId") String appId,
@RequestParam(value = "cluster") String cluster, @RequestParam(value = "cluster") String cluster,
@RequestParam(value = "namespace", defaultValue = ConfigConsts.NAMESPACE_APPLICATION) String namespace, @RequestParam(value = "namespace", defaultValue = ConfigConsts.NAMESPACE_APPLICATION) String namespace,
@RequestParam(value = "datacenter", required = false) String datacenter,
@RequestParam(value = "releaseId", defaultValue = "-1") String clientSideReleaseId, @RequestParam(value = "releaseId", defaultValue = "-1") String clientSideReleaseId,
HttpServletResponse response) { HttpServletResponse response) {
DeferredResult<ApolloConfigNotification> deferredResult = DeferredResult<ApolloConfigNotification> deferredResult =
new DeferredResult<>(TIMEOUT); new DeferredResult<>(TIMEOUT);
String key = assembleKey(appId, cluster, namespace); String key = assembleKey(appId, cluster, namespace);
this.deferredResults.put(key, deferredResult); this.deferredResults.put(key, deferredResult);
//to record all the keys related to deferredResult
this.deferredResultReversed.put(deferredResult, key);
deferredResult.onCompletion(() -> { deferredResult.onCompletion(() -> {
logger.info("deferred result for {} {} {} completed", appId, cluster, namespace); logger.info("deferred result for {} {} {} completed", appId, cluster, namespace);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment