/******************************************************************************* * Copyright (c) 2007, 2014 compeople AG and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * compeople AG - initial API and implementation *******************************************************************************/ package org.eclipse.riena.core.logging.log4j; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import org.apache.log4j.MDC; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExecutableExtension; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.riena.core.exception.Failure; import org.eclipse.riena.core.util.PropertiesUtils; import org.eclipse.riena.core.util.VariableManagerUtil; import org.eclipse.riena.internal.core.Activator; /** * The {@code Log4jMDCDiagnosticContext} is a log4j diagnostic context that uses * log4j {@code MDC} class. * <p> * This diagnostic context can be configured like this: * * <pre> * <extension point="org.eclipse.riena.core.log4jDiagnosticContext"> * <diagnosticContext class="org.eclipse.riena.core.logging.log4j.Log4jMDCDiagnosticContext:user=${java.system.property:riena.user.name}@${java.system.property:riena.host.name}" /> * </extension> * </pre> * * The {@code Log4jMDCDiagnosticContext} is a configurable * {@code IExecutableExtension}. The configuration data (the data after the * colon ':' in the class attribute) defines the key(s) and value(s) that get * pushed to the {@code MDC}. If multiple keys/values should be pushed to the * {@code MDC} than they have to be separated by commas. * <p> * The values can contain variable substitutions which will be resolved by the * {@code IStringVariableManager}.<br> * If a key is preceded with an asterisk '*' the key will be evaluated each time * the diagnostic context will be set; otherwise only once when this class gets * instantiated. */ public class Log4jMDCDiagnosticContext implements ILog4jDiagnosticContext, IExecutableExtension { private final Map<String, String> staticContextInfo = new HashMap<String, String>(); private final Map<String, String> dynamicContextInfo = new HashMap<String, String>(); public void push() { for (final Entry<String, String> entry : staticContextInfo.entrySet()) { MDC.put(entry.getKey(), entry.getValue()); } for (final Entry<String, String> entry : dynamicContextInfo.entrySet()) { try { MDC.put(entry.getKey(), VariableManagerUtil.substitute(entry.getValue())); } catch (final CoreException e) { throw new Log4jMDCDiagnosticContextFailure("Could not perform string substitution for: " //$NON-NLS-1$ + entry.getValue(), e); } } } public void pop() { for (final String key : staticContextInfo.keySet()) { MDC.remove(key); } for (final String key : dynamicContextInfo.keySet()) { MDC.remove(key); } } public void setInitializationData(final IConfigurationElement config, final String propertyName, final Object data) throws CoreException { try { for (final Entry<String, String> entry : PropertiesUtils.asMap(data, new String[] {}).entrySet()) { final String key = entry.getKey(); if (key.startsWith("*") && key.length() > 1) { //$NON-NLS-1$ dynamicContextInfo.put(key.substring(1), entry.getValue()); } else { staticContextInfo.put(key, VariableManagerUtil.substitute(entry.getValue())); } } } catch (final IllegalArgumentException e) { throw configurationException("Bad configuration.", e); //$NON-NLS-1$ } } private CoreException configurationException(final String message, final Exception e) { return new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, message, e)); } private static class Log4jMDCDiagnosticContextFailure extends Failure { private static final long serialVersionUID = 6386788702002693828L; public Log4jMDCDiagnosticContextFailure(final String msg, final Throwable cause) { super(msg, cause); } } }