org.dcache.xrootd.plugins.AccessLogHandler.java Source code

Java tutorial

Introduction

Here is the source code for org.dcache.xrootd.plugins.AccessLogHandler.java

Source

/* dCache - http://www.dcache.org/
 *
 * Copyright (C) 2014 Deutsches Elektronen-Synchrotron
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.dcache.xrootd.plugins;

import com.google.common.base.Strings;
import com.google.common.net.HostAndPort;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.haproxy.HAProxyCommand;
import io.netty.handler.codec.haproxy.HAProxyMessage;
import org.slf4j.Logger;

import javax.security.auth.Subject;

import java.net.InetSocketAddress;
import java.time.Instant;

import dmg.cells.nucleus.CDC;

import org.dcache.auth.LoginReply;
import org.dcache.auth.Subjects;
import org.dcache.util.NetLoggerBuilder;
import org.dcache.xrootd.door.LoginEvent;
import org.dcache.xrootd.protocol.XrootdProtocol;
import org.dcache.xrootd.protocol.messages.CloseRequest;
import org.dcache.xrootd.protocol.messages.EndSessionRequest;
import org.dcache.xrootd.protocol.messages.ErrorResponse;
import org.dcache.xrootd.protocol.messages.LocateRequest;
import org.dcache.xrootd.protocol.messages.LoginRequest;
import org.dcache.xrootd.protocol.messages.LoginResponse;
import org.dcache.xrootd.protocol.messages.MkDirRequest;
import org.dcache.xrootd.protocol.messages.MvRequest;
import org.dcache.xrootd.protocol.messages.OpenRequest;
import org.dcache.xrootd.protocol.messages.OpenResponse;
import org.dcache.xrootd.protocol.messages.PathRequest;
import org.dcache.xrootd.protocol.messages.PrepareRequest;
import org.dcache.xrootd.protocol.messages.ReadRequest;
import org.dcache.xrootd.protocol.messages.ReadVRequest;
import org.dcache.xrootd.protocol.messages.RedirectResponse;
import org.dcache.xrootd.protocol.messages.SetRequest;
import org.dcache.xrootd.protocol.messages.StatRequest;
import org.dcache.xrootd.protocol.messages.StatRequest.Target;
import org.dcache.xrootd.protocol.messages.StatResponse;
import org.dcache.xrootd.protocol.messages.StatxRequest;
import org.dcache.xrootd.protocol.messages.SyncRequest;
import org.dcache.xrootd.protocol.messages.WriteRequest;
import org.dcache.xrootd.protocol.messages.XrootdRequest;
import org.dcache.xrootd.protocol.messages.XrootdResponse;
import org.dcache.xrootd.util.FileStatus;

import static com.google.common.base.Strings.emptyToNull;
import static org.dcache.util.NetLoggerBuilder.Level.*;
import static org.dcache.xrootd.protocol.XrootdProtocol.*;

@ChannelHandler.Sharable
public class AccessLogHandler extends ChannelDuplexHandler {
    protected final Logger logger;

    public AccessLogHandler(Logger logger) {
        this.logger = logger;
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof LoginEvent) {
            LoginReply loginReply = ((LoginEvent) evt).getLoginReply();
            Subject subject = loginReply.getSubject();
            NetLoggerBuilder log = new NetLoggerBuilder(INFO, "org.dcache.xrootd.login").omitNullValues();
            log.add("session", CDC.getSession());
            log.add("user.dn", Subjects.getDn(subject));
            log.add("user.mapped", subject);
            log.toLogger(logger);
        }
        ctx.fireUserEventTriggered(evt);
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        NetLoggerBuilder log = new NetLoggerBuilder(INFO, "org.dcache.xrootd.connection.start").omitNullValues();
        log.add("session", CDC.getSession());
        log.add("socket.remote", (InetSocketAddress) ctx.channel().remoteAddress());
        log.add("socket.local", (InetSocketAddress) ctx.channel().localAddress());
        log.toLogger(logger);
        ctx.fireChannelActive();
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        NetLoggerBuilder log = new NetLoggerBuilder(INFO, "org.dcache.xrootd.connection.end").omitNullValues();
        log.add("session", CDC.getSession());
        log.toLogger(logger);
        ctx.fireChannelInactive();
    }

    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
        if (msg instanceof XrootdResponse<?> && logger.isErrorEnabled()) {
            XrootdResponse<?> response = (XrootdResponse<?>) msg;
            XrootdRequest request = response.getRequest();

            NetLoggerBuilder.Level level;
            if (response instanceof ErrorResponse) {
                level = ERROR;
            } else if (request instanceof WriteRequest || request instanceof ReadRequest
                    || request instanceof ReadVRequest) {
                level = DEBUG;
            } else {
                level = INFO;
            }

            if (level == ERROR || level == INFO && logger.isInfoEnabled()
                    || level == DEBUG && logger.isDebugEnabled()) {
                NetLoggerBuilder log = new NetLoggerBuilder(level, "org.dcache.xrootd.request").omitNullValues();
                log.add("session", CDC.getSession());
                log.add("request", getRequestId(request));

                if (request instanceof PathRequest) {
                    log.add("path", (Strings.emptyToNull(((PathRequest) request).getPath())));
                    log.add("opaque", (Strings.emptyToNull(((PathRequest) request).getOpaque())));
                    if (request instanceof OpenRequest) {
                        if (!((OpenRequest) request).isReadOnly()) {
                            int mode = ((OpenRequest) request).getUMask();
                            if (mode == 0) {
                                log.add("mode", "0");
                            } else {
                                log.add("mode", "0" + Integer.toOctalString(mode));
                            }
                        }
                        log.add("options", "0x" + Integer.toHexString(((OpenRequest) request).getOptions()));
                    } else if (request instanceof LocateRequest) {
                        log.add("options", "0x" + Integer.toHexString(((LocateRequest) request).getOptions()));
                    } else if (request instanceof MkDirRequest) {
                        log.add("options", "0x" + Integer.toHexString(((MkDirRequest) request).getOptions()));
                    } else if (request instanceof StatRequest) {
                        if (((StatRequest) request).getTarget() == Target.FHANDLE) {
                            log.add("handle", ((StatRequest) request).getFhandle());
                        }
                        log.add("vfs", ((StatRequest) request).isVfsSet());
                    }
                } else if (request instanceof CloseRequest) {
                    log.add("handle", ((CloseRequest) request).getFileHandle());
                } else if (request instanceof LoginRequest) {
                    log.add("username", ((LoginRequest) request).getUserName());
                    log.add("capver", ((LoginRequest) request).getClientProtocolVersion());
                    log.add("pid", ((LoginRequest) request).getPID());
                    log.add("token", emptyToNull(((LoginRequest) request).getToken()));
                } else if (request instanceof MvRequest) {
                    log.add("source", ((MvRequest) request).getSourcePath());
                    log.add("target", ((MvRequest) request).getTargetPath());
                } else if (request instanceof PrepareRequest) {
                    log.add("options", "0x" + Integer.toHexString(((PrepareRequest) request).getOptions()));
                    if (((PrepareRequest) request).getPathList().length == 1) {
                        log.add("path", ((PrepareRequest) request).getPathList()[0]);
                    } else {
                        log.add("files", ((PrepareRequest) request).getPathList().length);
                    }
                } else if (request instanceof StatxRequest) {
                    if (((StatxRequest) request).getPaths().length == 1) {
                        log.add("path", ((StatxRequest) request).getPaths()[0]);
                    } else {
                        log.add("files", ((StatxRequest) request).getPaths().length);
                    }
                } else if (request instanceof SetRequest) {
                    final String APPID_PREFIX = "appid ";
                    final int APPID_PREFIX_LENGTH = APPID_PREFIX.length();
                    final int APPID_MSG_LENGTH = 80;
                    String data = ((SetRequest) request).getData();
                    if (data.startsWith(APPID_PREFIX)) {
                        log.add("appid", data.substring(APPID_PREFIX_LENGTH,
                                Math.min(APPID_PREFIX_LENGTH + APPID_MSG_LENGTH, data.length())));
                    }
                } else if (request instanceof EndSessionRequest) {
                    log.add("sessionId", ((EndSessionRequest) request).getSessionId());
                } else if (request instanceof SyncRequest) {
                    log.add("handle", ((SyncRequest) request).getFileHandle());
                }

                log.add("response", getStatusCode(response));
                if (response instanceof ErrorResponse) {
                    log.add("error.code", getErrorCode((ErrorResponse) response));
                    log.add("error.msg", ((ErrorResponse) response).getErrorMessage());
                } else if (response instanceof RedirectResponse) {
                    log.add("host", ((RedirectResponse) response).getHost());
                    log.add("port", ((RedirectResponse) response).getPort());
                    log.add("token", emptyToNull(((RedirectResponse) response).getToken()));
                } else if (response instanceof StatResponse) {
                    log.add("flags", ((StatResponse) response).getFlags());
                    log.add("modtime", Instant.ofEpochSecond(((StatResponse) response).getModificationTime()));
                    log.add("size", ((StatResponse) response).getSize());
                } else if (response instanceof LoginResponse) {
                    log.add("sessionId", ((LoginResponse) response).getSessionId());
                    log.add("sec", emptyToNull(((LoginResponse) response).getSec()));
                } else if (response instanceof OpenResponse) {
                    log.add("handle", ((OpenResponse) response).getFileHandle());
                    FileStatus fs = ((OpenResponse) response).getFileStatus();
                    if (fs != null) {
                        log.add("flags", fs.getFlags());
                        log.add("modtime", Instant.ofEpochSecond(fs.getModificationTime()));
                        log.add("size", fs.getSize());
                    }
                }

                log.toLogger(logger);
            }
        }
        ctx.write(msg, promise);
    }

    private String getErrorCode(ErrorResponse response) {
        int errorNumber = response.getErrorNumber();
        switch (errorNumber) {
        case kXR_ArgInvalid:
            return "ArgInvalid";
        case kXR_ArgMissing:
            return "ArgMissing";
        case kXR_ArgTooLong:
            return "ArgTooLong";
        case kXR_FileLocked:
            return "FileLocked";
        case kXR_FileNotOpen:
            return "FileNotOpen";
        case kXR_FSError:
            return "FSError";
        case kXR_InvalidRequest:
            return "InvalidRequest";
        case kXR_IOError:
            return "IOError";
        case kXR_NoMemory:
            return "NoMemory";
        case kXR_NoSpace:
            return "NoSpace";
        case kXR_NotAuthorized:
            return "NotAuhorized";
        case kXR_NotFound:
            return "NotFound";
        case kXR_ServerError:
            return "ServerError";
        case kXR_Unsupported:
            return "Unsupported";
        case kXR_noserver:
            return "noserver";
        case kXR_NotFile:
            return "NotFile";
        case kXR_isDirectory:
            return "isDirectory";
        case kXR_Cancelled:
            return "Cancelled";
        case kXR_ChkLenErr:
            return "ChkLenErr";
        case kXR_ChkSumErr:
            return "ChkSumErr";
        case kXR_inProgress:
            return "inProgress";
        case kXR_noErrorYet:
            return "noErrorYet";
        default:
            return String.valueOf(errorNumber);
        }
    }

    private static String getStatusCode(XrootdResponse<?> response) {
        int status = response.getStatus();
        switch (status) {
        case XrootdProtocol.kXR_authmore:
            return "authmore";
        case XrootdProtocol.kXR_error:
            return "error";
        case XrootdProtocol.kXR_ok:
            return "ok";
        case XrootdProtocol.kXR_oksofar:
            return "oksofar";
        case XrootdProtocol.kXR_redirect:
            return "redirect";
        case XrootdProtocol.kXR_wait:
            return "wait";
        case XrootdProtocol.kXR_waitresp:
            return "waitresp";
        default:
            return String.valueOf(status);
        }
    }

    private static String getRequestId(XrootdRequest request) {
        switch (request.getRequestId()) {
        case kXR_handshake:
            return "handshake";
        case kXR_auth:
            return "auth";
        case kXR_query:
            return "query";
        case kXR_chmod:
            return "chdmod";
        case kXR_close:
            return "close";
        case kXR_dirlist:
            return "dirlist";
        case kXR_getfile:
            return "getfile";
        case kXR_protocol:
            return "protocol";
        case kXR_login:
            return "login";
        case kXR_mkdir:
            return "mkdir";
        case kXR_mv:
            return "mv";
        case kXR_open:
            return "open";
        case kXR_ping:
            return "ping";
        case kXR_putfile:
            return "putfile";
        case kXR_read:
            return "read";
        case kXR_rm:
            return "rm";
        case kXR_rmdir:
            return "rmdir";
        case kXR_sync:
            return "sync";
        case kXR_stat:
            return "stat";
        case kXR_set:
            return "set";
        case kXR_write:
            return "write";
        case kXR_admin:
            return "admin";
        case kXR_prepare:
            return "prepare";
        case kXR_statx:
            return "statx";
        case kXR_endsess:
            return "endsess";
        case kXR_bind:
            return "bind";
        case kXR_readv:
            return "readv";
        case kXR_verifyw:
            return "verifyw";
        case kXR_locate:
            return "locate";
        case kXR_truncate:
            return "truncate";
        default:
            return String.valueOf(request.getRequestId());
        }
    }
}