package fr.openwide.core.spring.util;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.support.AbstractApplicationContext;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import fr.openwide.core.spring.property.model.PropertyId;
import fr.openwide.core.spring.property.service.IConfigurablePropertyService;
import fr.openwide.core.spring.property.service.IPropertyService;
/**
* <p>Ce listener Spring permet de logguer la configuration Spring lors de l'émission
* de l'événement REFRESH.</p>
*
* <p>Ce listener n'est déclenché que pour les événements émis par un contexte racine.</p>
*
* <p>La propriété <i>propertyNamesForInfoLogLevel</i> permet de spécifier, par une liste
* de noms de propriétés, quels sont les éléments de configuration à logguer au
* niveau INFO. De plus, elle permet de forcer le logging de propriétés ne
* possédant pas d'accesseur (tels que les informations d'accès à la base de données.</p>
*
* <p>Les propriétés listées dans <i>propertyNamesForInfoLogLevel</i> sont affichées
* dans l'ordre de déclaration, avec un log level INFO, puis l'ensemble des
* propriétés possédant un accesseur sont logguées avec un log level TRACE.</p>
*
* <p>Les autres éléments sont loggués au niveau TRACE.</p>
*
* <p>La propriété <i>logPattern</i> permet de spécifier le formattage des messages
* de log émis pour chaque item de configuration. Deux arguments, le nom de la propriété
* et sa valeur, sont passés en paramètre de String.format sur ce pattern.</p>
*/
public class ConfigurationLogger implements ApplicationListener<ContextRefreshedEvent> {
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigurationLogger.class);
private String logPattern = "%1$30s : %2$s";
private List<String> propertyIdsKeysForInfoLogLevel = Lists.newArrayList();
public void setPropertyNamesForInfoLogLevel(String propertyIds) {
propertyIdsKeysForInfoLogLevel.addAll(StringUtils.splitAsList(propertyIds, ","));
}
public void setLogPattern(String logPattern) {
this.logPattern = logPattern;
}
@Override
public void onApplicationEvent(ContextRefreshedEvent refresh) {
if (refresh.getSource() instanceof AbstractApplicationContext &&
((AbstractApplicationContext) refresh.getSource()).getParent() == null) {
LOGGER.info("Configuration logging");
ApplicationContext context = refresh.getApplicationContext();
String[] propertyServiceNames = context.getBeanNamesForType(IConfigurablePropertyService.class);
if (propertyServiceNames.length > 0) {
String propertyServiceName = propertyServiceNames[0];
if (propertyServiceNames.length > 1) {
LOGGER.warn(String.format("Multiple %1$s found. We only log the configuration of the first instance.", IPropertyService.class.getSimpleName()));
}
LOGGER.info("Configuration found, start logging");
IConfigurablePropertyService propertyService = (IConfigurablePropertyService) context.getBean(propertyServiceName);
List<String> loggedProperties = Lists.newArrayList();
@SuppressWarnings("unchecked")
Iterable<PropertyId<?>> registeredPropertyIds =
(Iterable<PropertyId<?>>) (Object) Iterables.filter(propertyService.listRegistered(), PropertyId.class);
/* On logge les informations qu'on a configurées dans le contexte Spring */
for (String propertyIdKey : propertyIdsKeysForInfoLogLevel) {
if (loggedProperties.contains(propertyIdKey)) {
continue;
}
for (PropertyId<?> propertyId : registeredPropertyIds) {
if (propertyId.getKey().equals(propertyIdKey)) {
logPropertyAsInfo(propertyIdKey, propertyService.get(propertyId));
loggedProperties.add(propertyIdKey);
break;
}
}
}
/* Si jamais on est en mode TRACE, on logge aussi les autres propriétés */
if (LOGGER.isTraceEnabled()) {
for (PropertyId<?> propertyId : registeredPropertyIds) {
if (!propertyIdsKeysForInfoLogLevel.contains(propertyId.getKey())) {
logPropertyAsTrace(propertyId.getKey(), propertyService.get(propertyId));
}
}
}
} else {
LOGGER.warn(String.format("No %1$s found. Unable to log the configuration.", IConfigurablePropertyService.class.getSimpleName()));
}
LOGGER.info("Configuration logging end");
}
}
private void logPropertyAsInfo(String propertyName, Object value) {
LOGGER.info(String.format(logPattern, propertyName, value));
}
private void logPropertyAsTrace(String propertyName, Object value) {
LOGGER.trace(String.format(logPattern, propertyName, value));
}
}