You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by bt...@apache.org on 2017/08/24 03:46:35 UTC

[10/38] james-project git commit: JAMES-2114 MDC logging context for IMAP

http://git-wip-us.apache.org/repos/asf/james-project/blob/56974b95/server/protocols/protocols-imap4/pom.xml
----------------------------------------------------------------------
diff --git a/server/protocols/protocols-imap4/pom.xml b/server/protocols/protocols-imap4/pom.xml
index c38e647..68ca0cf 100644
--- a/server/protocols/protocols-imap4/pom.xml
+++ b/server/protocols/protocols-imap4/pom.xml
@@ -43,6 +43,10 @@
         </dependency>
         <dependency>
             <groupId>org.apache.james</groupId>
+            <artifactId>james-server-util-java8</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.james</groupId>
             <artifactId>metrics-api</artifactId>
         </dependency>
         <dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/56974b95/server/protocols/protocols-imap4/src/main/java/org/apache/james/imapserver/netty/IMAPMDCContext.java
----------------------------------------------------------------------
diff --git a/server/protocols/protocols-imap4/src/main/java/org/apache/james/imapserver/netty/IMAPMDCContext.java b/server/protocols/protocols-imap4/src/main/java/org/apache/james/imapserver/netty/IMAPMDCContext.java
new file mode 100644
index 0000000..35ccf32
--- /dev/null
+++ b/server/protocols/protocols-imap4/src/main/java/org/apache/james/imapserver/netty/IMAPMDCContext.java
@@ -0,0 +1,78 @@
+/****************************************************************
+ * 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.james.imapserver.netty;
+
+import java.io.Closeable;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.util.Optional;
+
+import org.apache.james.imap.api.process.SelectedMailbox;
+import org.apache.james.protocols.imap.IMAPSession;
+import org.apache.james.util.MDCBuilder;
+import org.jboss.netty.channel.ChannelHandlerContext;
+import org.jboss.netty.channel.ChannelLocal;
+
+public class IMAPMDCContext {
+    public static Closeable from(ChannelHandlerContext ctx, ChannelLocal<Object> attributes) {
+        return MDCBuilder.create()
+            .addContext(from(attributes.get(ctx.getChannel())))
+            .addContext(MDCBuilder.PROTOCOL, "IMAP")
+            .addContext(MDCBuilder.IP, retrieveIp(ctx))
+            .addContext(MDCBuilder.HOST, retrieveHost(ctx))
+            .build();
+    }
+
+    private static String retrieveIp(ChannelHandlerContext ctx) {
+        SocketAddress remoteAddress = ctx.getChannel().getRemoteAddress();
+        if (remoteAddress instanceof InetSocketAddress) {
+            InetSocketAddress address = (InetSocketAddress) remoteAddress;
+            return address.getAddress().getHostAddress();
+        }
+        return remoteAddress.toString();
+    }
+
+    private static String retrieveHost(ChannelHandlerContext ctx) {
+        SocketAddress remoteAddress = ctx.getChannel().getRemoteAddress();
+        if (remoteAddress instanceof InetSocketAddress) {
+            InetSocketAddress address = (InetSocketAddress) remoteAddress;
+            return address.getHostName();
+        }
+        return remoteAddress.toString();
+    }
+
+    private static MDCBuilder from(Object o) {
+        return Optional.ofNullable(o)
+            .filter(object -> object instanceof IMAPSession)
+            .map(object -> (IMAPSession) object)
+            .map(imapSession -> MDCBuilder.create()
+                .addContext(MDCBuilder.SESSION_ID, imapSession.getSessionID())
+                .addContext(MDCBuilder.USER, imapSession.getUser())
+                .addContext(from(Optional.ofNullable(imapSession.getSelected()))))
+            .orElse(MDCBuilder.create());
+    }
+
+    private static MDCBuilder from(Optional<SelectedMailbox> selectedMailbox) {
+        return selectedMailbox
+            .map(value -> MDCBuilder.create()
+                .addContext("selectedMailbox", value.getPath().asString()))
+            .orElse(MDCBuilder.create());
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/56974b95/server/protocols/protocols-imap4/src/main/java/org/apache/james/imapserver/netty/ImapChannelUpstreamHandler.java
----------------------------------------------------------------------
diff --git a/server/protocols/protocols-imap4/src/main/java/org/apache/james/imapserver/netty/ImapChannelUpstreamHandler.java b/server/protocols/protocols-imap4/src/main/java/org/apache/james/imapserver/netty/ImapChannelUpstreamHandler.java
index 48b522e..14d1a20 100644
--- a/server/protocols/protocols-imap4/src/main/java/org/apache/james/imapserver/netty/ImapChannelUpstreamHandler.java
+++ b/server/protocols/protocols-imap4/src/main/java/org/apache/james/imapserver/netty/ImapChannelUpstreamHandler.java
@@ -18,6 +18,7 @@
  ****************************************************************/
 package org.apache.james.imapserver.netty;
 
+import java.io.Closeable;
 import java.io.IOException;
 import java.net.InetSocketAddress;
 import java.util.function.Supplier;
@@ -34,8 +35,6 @@ import org.apache.james.imap.encode.ImapResponseComposer;
 import org.apache.james.imap.encode.base.ImapResponseComposerImpl;
 import org.apache.james.imap.main.ResponseEncoder;
 import org.apache.james.metrics.api.Metric;
-import org.apache.james.protocols.api.logger.ContextualLogger;
-import org.apache.james.protocols.imap.IMAPSession;
 import org.jboss.netty.buffer.ChannelBuffers;
 import org.jboss.netty.channel.Channel;
 import org.jboss.netty.channel.ChannelFutureListener;
@@ -95,28 +94,16 @@ public class ImapChannelUpstreamHandler extends SimpleChannelUpstreamHandler imp
     }
 
     private Logger getLogger(final ChannelHandlerContext ctx) {
-        return new ContextualLogger(
-                getUserSupplier(ctx),
-                String.valueOf(ctx.getChannel().getId()),
-                logger);
-    }
-
-    private Supplier<String> getUserSupplier(final ChannelHandlerContext ctx) {
-        return () -> {
-            Object o = attributes.get(ctx.getChannel());
-            if (o instanceof IMAPSession) {
-                IMAPSession session = (IMAPSession) o;
-                return session.getUser();
-            }
-            return null;
-        };
+        return logger;
     }
 
     @Override
     public void channelBound(final ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
-        ImapSession imapsession = new NettyImapSession(ctx.getChannel(), toLogSupplier(ctx), context, enabledCipherSuites, compress, plainAuthDisallowed);
-        attributes.set(ctx.getChannel(), imapsession);
-        super.channelBound(ctx, e);
+        try (Closeable closeable = IMAPMDCContext.from(ctx, attributes)) {
+            ImapSession imapsession = new NettyImapSession(ctx.getChannel(), () -> getLogger(ctx), context, enabledCipherSuites, compress, plainAuthDisallowed);
+            attributes.set(ctx.getChannel(), imapsession);
+            super.channelBound(ctx, e);
+        }
     }
 
     private Supplier<Logger> toLogSupplier(final ChannelHandlerContext ctx) {
@@ -125,119 +112,120 @@ public class ImapChannelUpstreamHandler extends SimpleChannelUpstreamHandler imp
 
     @Override
     public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
-        
-        InetSocketAddress address = (InetSocketAddress) ctx.getChannel().getRemoteAddress();
-        getLogger(ctx).info("Connection closed for " + address.getAddress().getHostAddress());
-
-        // remove the stored attribute for the channel to free up resources
-        // See JAMES-1195
-        ImapSession imapSession = (ImapSession) attributes.remove(ctx.getChannel());
-        if (imapSession != null)
-            imapSession.logout();
-        imapConnectionsMetric.decrement();
-
-        super.channelClosed(ctx, e);
-    }
-
-    @Override
-    public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
-        
-        InetSocketAddress address = (InetSocketAddress) ctx.getChannel().getRemoteAddress();
-        getLogger(ctx).info("Connection established from " + address.getAddress().getHostAddress());
-        imapConnectionsMetric.increment();
-
-        ImapResponseComposer response = new ImapResponseComposerImpl(new ChannelImapResponseWriter(ctx.getChannel()));
-        ctx.setAttachment(response);
+        try (Closeable closeable = IMAPMDCContext.from(ctx, attributes)) {
+            InetSocketAddress address = (InetSocketAddress) ctx.getChannel().getRemoteAddress();
+            getLogger(ctx).info("Connection closed for " + address.getAddress().getHostAddress());
 
-        // write hello to client
-        response.untagged().message("OK").message(hello).end();
-        super.channelConnected(ctx, e);
+            // remove the stored attribute for the channel to free up resources
+            // See JAMES-1195
+            ImapSession imapSession = (ImapSession) attributes.remove(ctx.getChannel());
+            if (imapSession != null)
+                imapSession.logout();
+            imapConnectionsMetric.decrement();
 
+            super.channelClosed(ctx, e);
+        }
     }
 
     @Override
-    public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
-        
-        getLogger(ctx).warn("Error while processing imap request", e.getCause());
-
-        if (e.getCause() instanceof TooLongFrameException) {
-
-            // Max line length exceeded
-            // See RFC 2683 section 3.2.1
-            //
-            // "For its part, a server should allow for a command line of at
-            // least
-            // 8000 octets. This provides plenty of leeway for accepting
-            // reasonable
-            // length commands from clients. The server should send a BAD
-            // response
-            // to a command that does not end within the server's maximum
-            // accepted
-            // command length."
-            //
-            // See also JAMES-1190
-            ImapResponseComposer composer = (ImapResponseComposer) ctx.getAttachment();
-            composer.untaggedResponse(ImapConstants.BAD + " failed. Maximum command line length exceeded");
-            
-        } else {
-
-            // logout on error not sure if that is the best way to handle it
-            final ImapSession imapSession = (ImapSession) attributes.get(ctx.getChannel());
-            if (imapSession != null)
-                imapSession.logout();
+    public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
+        try (Closeable closeable = IMAPMDCContext.from(ctx, attributes)) {
+            InetSocketAddress address = (InetSocketAddress) ctx.getChannel().getRemoteAddress();
+            getLogger(ctx).info("Connection established from " + address.getAddress().getHostAddress());
+            imapConnectionsMetric.increment();
 
-            // Make sure we close the channel after all the buffers were flushed out
-            Channel channel = ctx.getChannel();
-            if (channel.isConnected()) {
-                channel.write(ChannelBuffers.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
-            }
+            ImapResponseComposer response = new ImapResponseComposerImpl(new ChannelImapResponseWriter(ctx.getChannel()));
+            ctx.setAttachment(response);
 
+            // write hello to client
+            response.untagged().message("OK").message(hello).end();
+            super.channelConnected(ctx, e);
         }
-
     }
 
     @Override
-    public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
-
-        imapCommandsMetric.increment();
-        ImapSession session = (ImapSession) attributes.get(ctx.getChannel());
-        ImapResponseComposer response = (ImapResponseComposer) ctx.getAttachment();
-        ImapMessage message = (ImapMessage) e.getMessage();
-        ChannelPipeline cp = ctx.getPipeline();
+    public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
+        try (Closeable closeable = IMAPMDCContext.from(ctx, attributes)) {
+            getLogger(ctx).warn("Error while processing imap request", e.getCause());
+
+            if (e.getCause() instanceof TooLongFrameException) {
+
+                // Max line length exceeded
+                // See RFC 2683 section 3.2.1
+                //
+                // "For its part, a server should allow for a command line of at
+                // least
+                // 8000 octets. This provides plenty of leeway for accepting
+                // reasonable
+                // length commands from clients. The server should send a BAD
+                // response
+                // to a command that does not end within the server's maximum
+                // accepted
+                // command length."
+                //
+                // See also JAMES-1190
+                ImapResponseComposer composer = (ImapResponseComposer) ctx.getAttachment();
+                composer.untaggedResponse(ImapConstants.BAD + " failed. Maximum command line length exceeded");
 
-        try {
-            if (cp.get(NettyConstants.EXECUTION_HANDLER) != null) {
-                cp.addBefore(NettyConstants.EXECUTION_HANDLER, NettyConstants.HEARTBEAT_HANDLER, heartbeatHandler);
             } else {
-                cp.addBefore(NettyConstants.CORE_HANDLER, NettyConstants.HEARTBEAT_HANDLER, heartbeatHandler);
 
-            }
-            final ResponseEncoder responseEncoder = new ResponseEncoder(encoder, response, session);
-            processor.process(message, responseEncoder, session);
+                // logout on error not sure if that is the best way to handle it
+                final ImapSession imapSession = (ImapSession) attributes.get(ctx.getChannel());
+                if (imapSession != null)
+                    imapSession.logout();
 
-            if (session.getState() == ImapSessionState.LOGOUT) {
                 // Make sure we close the channel after all the buffers were flushed out
                 Channel channel = ctx.getChannel();
                 if (channel.isConnected()) {
                     channel.write(ChannelBuffers.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
                 }
-            }
-            final IOException failure = responseEncoder.getFailure();
 
-            if (failure != null) {
-                final Logger logger = session.getLog();
-                logger.info(failure.getMessage());
-                if (logger.isDebugEnabled()) {
-                    logger.debug("Failed to write " + message, failure);
-                }
-                throw failure;
             }
-        } finally {
-            ctx.getPipeline().remove(NettyConstants.HEARTBEAT_HANDLER);
         }
+    }
 
-        super.messageReceived(ctx, e);
+    @Override
+    public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
+        try (Closeable closeable = IMAPMDCContext.from(ctx, attributes)) {
+            imapCommandsMetric.increment();
+            ImapSession session = (ImapSession) attributes.get(ctx.getChannel());
+            ImapResponseComposer response = (ImapResponseComposer) ctx.getAttachment();
+            ImapMessage message = (ImapMessage) e.getMessage();
+            ChannelPipeline cp = ctx.getPipeline();
+
+            try {
+                if (cp.get(NettyConstants.EXECUTION_HANDLER) != null) {
+                    cp.addBefore(NettyConstants.EXECUTION_HANDLER, NettyConstants.HEARTBEAT_HANDLER, heartbeatHandler);
+                } else {
+                    cp.addBefore(NettyConstants.CORE_HANDLER, NettyConstants.HEARTBEAT_HANDLER, heartbeatHandler);
+
+                }
+                final ResponseEncoder responseEncoder = new ResponseEncoder(encoder, response, session);
+                processor.process(message, responseEncoder, session);
+
+                if (session.getState() == ImapSessionState.LOGOUT) {
+                    // Make sure we close the channel after all the buffers were flushed out
+                    Channel channel = ctx.getChannel();
+                    if (channel.isConnected()) {
+                        channel.write(ChannelBuffers.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
+                    }
+                }
+                final IOException failure = responseEncoder.getFailure();
+
+                if (failure != null) {
+                    final Logger logger = session.getLog();
+                    logger.info(failure.getMessage());
+                    if (logger.isDebugEnabled()) {
+                        logger.debug("Failed to write " + message, failure);
+                    }
+                    throw failure;
+                }
+            } finally {
+                ctx.getPipeline().remove(NettyConstants.HEARTBEAT_HANDLER);
+            }
 
+            super.messageReceived(ctx, e);
+        }
     }
 
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org