/*
* Copyright 2013-2014 the original author or 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 org.springframework.xd.dirt.util;
import java.util.Arrays;
import java.util.Set;
import java.util.TreeSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationListener;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.EnumerablePropertySource;
import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertySource;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import org.springframework.xd.dirt.cluster.ContainerAttributes;
import org.springframework.xd.dirt.server.SharedServerContextConfiguration;
/**
* Initializer that can print useful stuff about an XD context on startup.
*
* @author Dave Syer
* @author David Turanski
* @author Ilayaperumal Gopinathan
* @author Gunnar Hillert
*
*/
public class XdConfigLoggingInitializer implements ApplicationListener<ContextRefreshedEvent>, EnvironmentAware {
private static Logger logger = LoggerFactory.getLogger(XdConfigLoggingInitializer.class);
protected ConfigurableEnvironment environment;
private final boolean isContainer;
private static final String HADOOP_DISTRO_OPTION = "${HADOOP_DISTRO}";
private static final String ADMIN_PORT = "${server.port}";
private static final String XD_CONFIG_LOCATION = "${xd.config.home}";
private static final String XD_CONFIG_NAME = "${spring.config.name:servers}";
private static final String XD_MODULE_CONFIG_LOCATION = "${xd.module.config.location:${xd.config.home}/modules/}";
private static final String XD_MODULE_CONFIG_NAME = "${xd.module.config.name:modules}";
private static final String XD_ZK_NAMESPACE = "${zk.namespace}";
private ContainerAttributes containerAttributes;
public XdConfigLoggingInitializer(boolean isContainer) {
this.isContainer = isContainer;
}
@Override
public void setEnvironment(Environment environment) {
this.environment = (ConfigurableEnvironment) environment;
}
/**
* If not set, this property will default to {@code null}.
*
* @param containerAttributes Must not be null
*/
public void setContainerAttributes(ContainerAttributes containerAttributes) {
Assert.notNull(containerAttributes);
this.containerAttributes = containerAttributes;
}
/**
* Logger config info upon admin or container server context refresh.
*/
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
logger.info("XD Home: " + environment.resolvePlaceholders("${XD_HOME}"));
logger.info("Transport: " + environment.resolvePlaceholders("${XD_TRANSPORT}"));
logHadoopDistro();
logConfigLocations();
if (isContainer) {
logContainerInfo();
}
else {
logAdminUI();
}
logZkConnectString();
logZkNamespace();
logger.info("Analytics: " + environment.resolvePlaceholders("${XD_ANALYTICS}"));
if ("true".equals(environment.getProperty("verbose"))) {
logAllProperties();
}
}
private void logHadoopDistro() {
if (ClassUtils.isPresent("org.apache.hadoop.util.VersionInfo", this.getClass().getClassLoader())) {
logger.info("Hadoop version detected from classpath " + org.apache.hadoop.util.VersionInfo.getVersion());
}
else {
logger.info("Hadoop version not detected from classpath");
}
}
private void logContainerInfo() {
final String containerIp;
final String containerHostname;
if (this.containerAttributes != null) {
containerIp = containerAttributes.getIp();
containerHostname = containerAttributes.getHost();
}
else {
containerIp = "N/A";
containerHostname = "N/A";
}
logger.info("Container IP address: " + containerIp);
logger.info("Container hostname: " + containerHostname);
}
/**
* Logger server/module config locations and names.
*/
private void logConfigLocations() {
logger.info("XD config location: " + environment.resolvePlaceholders(XD_CONFIG_LOCATION));
logger.info("XD config names: " + environment.resolvePlaceholders(XD_CONFIG_NAME));
logger.info("XD module config location: " + environment.resolvePlaceholders(XD_MODULE_CONFIG_LOCATION));
logger.info("XD module config name: " + environment.resolvePlaceholders(XD_MODULE_CONFIG_NAME));
}
/**
* Logger admin web UI URL
*/
private void logAdminUI() {
String httpPort = environment.resolvePlaceholders(ADMIN_PORT);
Assert.notNull(httpPort, "Admin server port is not set.");
logger.info("Admin web UI: "
+ String.format("http://%s:%s/%s", RuntimeUtils.getHost(), httpPort,
ConfigLocations.XD_ADMIN_UI_BASE_PATH));
}
private void logZkConnectString() {
PropertySource<?> zkPropertySource = environment.getPropertySources().get(
SharedServerContextConfiguration.ZK_PROPERTIES_SOURCE);
if (zkPropertySource != null) {
String zkConnectString = (String) zkPropertySource.getProperty(SharedServerContextConfiguration.ZK_CONNECT);
String embeddedZkConnectString = (String) zkPropertySource.getProperty(SharedServerContextConfiguration.EMBEDDED_ZK_CONNECT);
String connectString = (!StringUtils.hasText(zkConnectString) && StringUtils.hasText(embeddedZkConnectString)) ? embeddedZkConnectString
: zkConnectString;
logger.info("Zookeeper at: " + connectString);
}
}
private void logZkNamespace() {
logger.info("Zookeeper namespace: " + environment.resolvePlaceholders(XD_ZK_NAMESPACE));
}
private void logAllProperties() {
Set<String> propertyNames = new TreeSet<String>();
for (PropertySource<?> ps : this.environment.getPropertySources()) {
if (ps instanceof EnumerablePropertySource) {
EnumerablePropertySource<?> eps = (EnumerablePropertySource<?>) ps;
propertyNames.addAll(Arrays.asList(eps.getPropertyNames()));
}
}
StringBuffer sb = new StringBuffer("\n");
for (String key : propertyNames) {
sb.append(String.format("\t%s=%s\n", key,
environment.resolvePlaceholders(environment.getProperty(key).toString())));
}
logger.info(sb.toString());
}
}