All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.mina.filter.logging.MdcInjectionFilter Maven / Gradle / Ivy

/*
 *  Licensed to the Apache Software Foundation (ASF) under one
 *  or more contributor license agreements.  See the NOTICE file
 *  distributed with this work for additional information
 *  regarding copyright ownership.  The ASF licenses this file
 *  to you 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.apache.mina.filter.logging;

import java.net.InetSocketAddress;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.Arrays;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.mina.core.filterchain.IoFilterEvent;
import org.apache.mina.core.session.AttributeKey;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.util.CommonEventFilter;
import org.slf4j.MDC;

/**
 * This filter will inject some key IoSession properties into the Mapped Diagnostic Context (MDC)
 * 

* These properties will be set in the MDC for all logging events that are generated * down the call stack, even in code that is not aware of MINA. * * By default, the following properties will be set for all transports: *

    *
  • "handlerClass"
  • *
  • "remoteAddress"
  • *
  • "localAddress"
  • *
* * When session.getTransportMetadata().getAddressType() == InetSocketAddress.class * the following properties will also be set: *
    *
  • "remoteIp"
  • *
  • "remotePort"
  • *
  • "localIp"
  • *
  • "localPort"
  • *
* * User code can also add custom properties to the context, via {@link #setProperty(IoSession, String, String)} * * If you only want the MDC to be set for the IoHandler code, it's enough to add * one MdcInjectionFilter at the end of the filter chain. * * If you want the MDC to be set for ALL code, you should * add an MdcInjectionFilter to the start of the chain * and add that same MdcInjectionFilter instance after EVERY ExecutorFilter in the chain * * Thus it's ok to have one instance of the MdcInjectionFilter and add it multiple times to the chain * but you should avoid adding multiple instances to the chain. * * @author Apache MINA Project */ public class MdcInjectionFilter extends CommonEventFilter { /** * This enum lists all the possible keys this filter will process */ public enum MdcKey { /** Tha class handling the requests */ handlerClass, /** The remote peer address */ remoteAddress, /** The local address */ localAddress, /** The remote peer IP address */ remoteIp, /** The remote peer port */ remotePort, /** The local IP address */ localIp, /** The local port */ localPort } /** key used for storing the context map in the IoSession */ private static final AttributeKey CONTEXT_KEY = new AttributeKey(MdcInjectionFilter.class, "context"); private ThreadLocal callDepth = new ThreadLocal() { @Override protected Integer initialValue() { return 0; } }; private EnumSet mdcKeys; /** * Use this constructor when you want to specify which keys to add to the MDC. * You could still add custom keys via {@link #setProperty(IoSession, String, String)} * @param keys set of keys that should be added to the MDC * * @see #setProperty(org.apache.mina.core.session.IoSession, String, String) */ public MdcInjectionFilter(EnumSet keys) { this.mdcKeys = keys.clone(); } /** * Use this constructor when you want to specify which keys to add to the MDC * You could still add custom keys via {@link #setProperty(IoSession, String, String)} * @param keys list of keys that should be added to the MDC * * @see #setProperty(org.apache.mina.core.session.IoSession, String, String) */ public MdcInjectionFilter(MdcKey... keys) { Set keySet = new HashSet<>(Arrays.asList(keys)); this.mdcKeys = EnumSet.copyOf(keySet); } /** * Create a new MdcInjectionFilter instance */ public MdcInjectionFilter() { this.mdcKeys = EnumSet.allOf(MdcKey.class); } /** * {@inheritDoc} */ @Override protected void filter(IoFilterEvent event) throws Exception { // since this method can potentially call into itself // we need to check the call depth before clearing the MDC int currentCallDepth = callDepth.get(); callDepth.set(currentCallDepth + 1); Map context = getAndFillContext(event.getSession()); if (currentCallDepth == 0) { /* copy context to the MDC when necessary. */ for (Map.Entry e : context.entrySet()) { MDC.put(e.getKey(), e.getValue()); } } try { /* propagate event down the filter chain */ event.fire(); } finally { if (currentCallDepth == 0) { /* remove context from the MDC */ for (String key : context.keySet()) { MDC.remove(key); } callDepth.remove(); } else { callDepth.set(currentCallDepth); } } } private Map getAndFillContext(final IoSession session) { Map context = getContext(session); if (context.isEmpty()) { fillContext(session, context); } return context; } @SuppressWarnings("unchecked") private static Map getContext(final IoSession session) { Map context = (Map) session.getAttribute(CONTEXT_KEY); if (context == null) { context = new ConcurrentHashMap<>(); session.setAttribute(CONTEXT_KEY, context); } return context; } /** * write key properties of the session to the Mapped Diagnostic Context * sub-classes could override this method to map more/other attributes * @param session the session to map * @param context key properties will be added to this map */ protected void fillContext(final IoSession session, final Map context) { if (mdcKeys.contains(MdcKey.handlerClass)) { context.put(MdcKey.handlerClass.name(), session.getHandler().getClass().getName()); } if (mdcKeys.contains(MdcKey.remoteAddress)) { context.put(MdcKey.remoteAddress.name(), session.getRemoteAddress().toString()); } if (mdcKeys.contains(MdcKey.localAddress)) { context.put(MdcKey.localAddress.name(), session.getLocalAddress().toString()); } if (session.getTransportMetadata().getAddressType() == InetSocketAddress.class) { InetSocketAddress remoteAddress = (InetSocketAddress) session.getRemoteAddress(); InetSocketAddress localAddress = (InetSocketAddress) session.getLocalAddress(); if (mdcKeys.contains(MdcKey.remoteIp)) { context.put(MdcKey.remoteIp.name(), remoteAddress.getAddress().getHostAddress()); } if (mdcKeys.contains(MdcKey.remotePort)) { context.put(MdcKey.remotePort.name(), String.valueOf(remoteAddress.getPort())); } if (mdcKeys.contains(MdcKey.localIp)) { context.put(MdcKey.localIp.name(), localAddress.getAddress().getHostAddress()); } if (mdcKeys.contains(MdcKey.localPort)) { context.put(MdcKey.localPort.name(), String.valueOf(localAddress.getPort())); } } } /** * Get the property associated with a given key * * @param session The {@link IoSession} * @param key The key we are looking at * @return The associated property */ public static String getProperty(IoSession session, String key) { if (key == null) { throw new IllegalArgumentException("key should not be null"); } Map context = getContext(session); String answer = context.get(key); if (answer != null) { return answer; } return MDC.get(key); } /** * Add a property to the context for the given session * This property will be added to the MDC for all subsequent events * @param session The session for which you want to set a property * @param key The name of the property (should not be null) * @param value The value of the property */ public static void setProperty(IoSession session, String key, String value) { if (key == null) { throw new IllegalArgumentException("key should not be null"); } if (value == null) { removeProperty(session, key); } Map context = getContext(session); context.put(key, value); MDC.put(key, value); } /** * Remove a property from the context for the given session * This property will be removed from the MDC for all subsequent events * @param session The session for which you want to remove a property * @param key The name of the property (should not be null) */ public static void removeProperty(IoSession session, String key) { if (key == null) { throw new IllegalArgumentException("key should not be null"); } Map context = getContext(session); context.remove(key); MDC.remove(key); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy