0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019 package org.apache.hive.service.cli.operation;
0020 import java.io.CharArrayWriter;
0021 import java.util.Enumeration;
0022 import java.util.regex.Pattern;
0023
0024 import org.apache.hadoop.hive.ql.exec.Task;
0025 import org.apache.hadoop.hive.ql.log.PerfLogger;
0026 import org.apache.hadoop.hive.ql.session.OperationLog;
0027 import org.apache.hadoop.hive.ql.session.OperationLog.LoggingLevel;
0028 import org.apache.hive.service.cli.CLIServiceUtils;
0029 import org.apache.log4j.Appender;
0030 import org.apache.log4j.ConsoleAppender;
0031 import org.apache.log4j.Layout;
0032 import org.apache.log4j.Logger;
0033 import org.apache.log4j.WriterAppender;
0034 import org.apache.log4j.spi.Filter;
0035 import org.apache.log4j.spi.LoggingEvent;
0036
0037 import com.google.common.base.Joiner;
0038
0039
0040
0041
0042 public class LogDivertAppender extends WriterAppender {
0043 private static final Logger LOG = Logger.getLogger(LogDivertAppender.class.getName());
0044 private final OperationManager operationManager;
0045 private boolean isVerbose;
0046 private Layout verboseLayout;
0047
0048
0049
0050
0051
0052
0053
0054
0055 private static class NameFilter extends Filter {
0056 private Pattern namePattern;
0057 private LoggingLevel loggingMode;
0058 private OperationManager operationManager;
0059
0060
0061
0062
0063 private static final Pattern verboseExcludeNamePattern = Pattern.compile(Joiner.on("|")
0064 .join(new String[] {LOG.getName(), OperationLog.class.getName(),
0065 OperationManager.class.getName()}));
0066
0067
0068
0069
0070 private static final Pattern executionIncludeNamePattern = Pattern.compile(Joiner.on("|")
0071 .join(new String[] {"org.apache.hadoop.mapreduce.JobSubmitter",
0072 "org.apache.hadoop.mapreduce.Job", "SessionState", Task.class.getName(),
0073 "org.apache.hadoop.hive.ql.exec.spark.status.SparkJobMonitor"}));
0074
0075
0076
0077
0078 private static final Pattern performanceIncludeNamePattern = Pattern.compile(
0079 executionIncludeNamePattern.pattern() + "|" + PerfLogger.class.getName());
0080
0081 private void setCurrentNamePattern(OperationLog.LoggingLevel mode) {
0082 if (mode == OperationLog.LoggingLevel.VERBOSE) {
0083 this.namePattern = verboseExcludeNamePattern;
0084 } else if (mode == OperationLog.LoggingLevel.EXECUTION) {
0085 this.namePattern = executionIncludeNamePattern;
0086 } else if (mode == OperationLog.LoggingLevel.PERFORMANCE) {
0087 this.namePattern = performanceIncludeNamePattern;
0088 }
0089 }
0090
0091 NameFilter(
0092 OperationLog.LoggingLevel loggingMode, OperationManager op) {
0093 this.operationManager = op;
0094 this.loggingMode = loggingMode;
0095 setCurrentNamePattern(loggingMode);
0096 }
0097
0098 @Override
0099 public int decide(LoggingEvent ev) {
0100 OperationLog log = operationManager.getOperationLogByThread();
0101 boolean excludeMatches = (loggingMode == OperationLog.LoggingLevel.VERBOSE);
0102
0103 if (log == null) {
0104 return Filter.DENY;
0105 }
0106
0107 OperationLog.LoggingLevel currentLoggingMode = log.getOpLoggingLevel();
0108
0109 if (currentLoggingMode == OperationLog.LoggingLevel.NONE) {
0110 return Filter.DENY;
0111 }
0112
0113
0114 if (currentLoggingMode != loggingMode) {
0115 loggingMode = currentLoggingMode;
0116 setCurrentNamePattern(loggingMode);
0117 }
0118
0119 boolean isMatch = namePattern.matcher(ev.getLoggerName()).matches();
0120
0121 if (excludeMatches == isMatch) {
0122
0123
0124
0125 return Filter.DENY;
0126 }
0127 return Filter.NEUTRAL;
0128 }
0129 }
0130
0131
0132 private final CharArrayWriter writer = new CharArrayWriter();
0133
0134 private void setLayout(boolean isVerbose, Layout lo) {
0135 if (isVerbose) {
0136 if (lo == null) {
0137 lo = CLIServiceUtils.verboseLayout;
0138 LOG.info("Cannot find a Layout from a ConsoleAppender. Using default Layout pattern.");
0139 }
0140 } else {
0141 lo = CLIServiceUtils.nonVerboseLayout;
0142 }
0143 setLayout(lo);
0144 }
0145
0146 private void initLayout(boolean isVerbose) {
0147
0148 Logger root = Logger.getRootLogger();
0149 Layout layout = null;
0150
0151 Enumeration<?> appenders = root.getAllAppenders();
0152 while (appenders.hasMoreElements()) {
0153 Appender ap = (Appender) appenders.nextElement();
0154 if (ap.getClass().equals(ConsoleAppender.class)) {
0155 layout = ap.getLayout();
0156 break;
0157 }
0158 }
0159 setLayout(isVerbose, layout);
0160 }
0161
0162 public LogDivertAppender(OperationManager operationManager,
0163 OperationLog.LoggingLevel loggingMode) {
0164 isVerbose = (loggingMode == OperationLog.LoggingLevel.VERBOSE);
0165 initLayout(isVerbose);
0166 setWriter(writer);
0167 setName("LogDivertAppender");
0168 this.operationManager = operationManager;
0169 this.verboseLayout = isVerbose ? layout : CLIServiceUtils.verboseLayout;
0170 addFilter(new NameFilter(loggingMode, operationManager));
0171 }
0172
0173 @Override
0174 public void doAppend(LoggingEvent event) {
0175 OperationLog log = operationManager.getOperationLogByThread();
0176
0177
0178 if (log != null) {
0179 boolean isCurrModeVerbose = (log.getOpLoggingLevel() == OperationLog.LoggingLevel.VERBOSE);
0180
0181
0182
0183 if (isCurrModeVerbose != isVerbose) {
0184 isVerbose = isCurrModeVerbose;
0185 setLayout(isVerbose, verboseLayout);
0186 }
0187 }
0188 super.doAppend(event);
0189 }
0190
0191
0192
0193
0194
0195 @Override
0196 protected void subAppend(LoggingEvent event) {
0197 super.subAppend(event);
0198
0199 String logOutput = writer.toString();
0200 writer.reset();
0201
0202 OperationLog log = operationManager.getOperationLogByThread();
0203 if (log == null) {
0204 LOG.debug(" ---+++=== Dropped log event from thread " + event.getThreadName());
0205 return;
0206 }
0207 log.writeOperationLog(logOutput);
0208 }
0209 }