1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.tradefed.log; 17 18 import com.android.ddmlib.Log.LogLevel; 19 import com.android.tradefed.config.Option; 20 import com.android.tradefed.config.Option.Importance; 21 import com.android.tradefed.util.StreamUtil; 22 23 import java.io.IOException; 24 import java.io.OutputStream; 25 26 /** A {@link ILeveledLogOutput} that directs log messages to an output stream and to stdout. */ 27 public abstract class BaseStreamLogger<OS extends OutputStream> extends BaseLeveledLogOutput { 28 29 @Option(name = "log-level", description = "the minimum log level to log.") 30 private LogLevel mLogLevel = LogLevel.DEBUG; 31 32 @Option( 33 name = "log-level-display", 34 shortName = 'l', 35 description = "the minimum log level to display on stdout.", 36 importance = Importance.ALWAYS 37 ) 38 private LogLevel mLogLevelDisplay = LogLevel.ERROR; 39 40 // output stream to print logs to, exposed to subclasses 41 protected OS mOutputStream; 42 43 @Override getLogLevel()44 public LogLevel getLogLevel() { 45 return mLogLevel; 46 } 47 48 @Override setLogLevel(LogLevel logLevel)49 public void setLogLevel(LogLevel logLevel) { 50 mLogLevel = logLevel; 51 } 52 53 /** Sets the minimum {@link LogLevel} to display on stdout. */ setLogLevelDisplay(LogLevel logLevel)54 public void setLogLevelDisplay(LogLevel logLevel) { 55 mLogLevelDisplay = logLevel; 56 } 57 58 /** @return current minimum {@link LogLevel} to display on stdout. */ getLogLevelDisplay()59 LogLevel getLogLevelDisplay() { 60 return mLogLevelDisplay; 61 } 62 63 @Override closeLog()64 public void closeLog() { 65 StreamUtil.flushAndCloseStream(mOutputStream); 66 mOutputStream = null; 67 } 68 69 @Override printAndPromptLog(LogLevel logLevel, String tag, String message)70 public void printAndPromptLog(LogLevel logLevel, String tag, String message) { 71 internalPrintLog(logLevel, tag, message, true /* force print to stdout */); 72 } 73 74 @Override printLog(LogLevel logLevel, String tag, String message)75 public void printLog(LogLevel logLevel, String tag, String message) { 76 internalPrintLog(logLevel, tag, message, false /* don't force stdout */); 77 } 78 79 /** 80 * A version of printLog(...) which can be forced to print to stdout, even if the log level 81 * isn't above the urgency threshold. 82 */ internalPrintLog( LogLevel logLevel, String tag, String message, boolean forceStdout)83 private void internalPrintLog( 84 LogLevel logLevel, String tag, String message, boolean forceStdout) { 85 String outMessage = LogUtil.getLogFormatString(logLevel, tag, message); 86 if (shouldDisplay(forceStdout, mLogLevelDisplay, logLevel, tag)) { 87 System.out.print(outMessage); 88 } 89 if (shouldWrite(tag, logLevel, mLogLevel)) { 90 try { 91 writeToLog(outMessage); 92 } catch (IOException e) { 93 e.printStackTrace(); 94 } 95 } 96 } 97 98 // Determines whether a message should be written to the output stream. shouldWrite(String tag, LogLevel messageLogLevel, LogLevel invocationLogLevel)99 private boolean shouldWrite(String tag, LogLevel messageLogLevel, LogLevel invocationLogLevel) { 100 LogLevel forcedLevel = getForcedVerbosityMap().get(tag); 101 if (forcedLevel == null || !shouldForceVerbosity()) { 102 return true; 103 } 104 // Use the highest level of our forced and invocation to decide if we should log the 105 // particular tag. 106 int minWriteLevel = Math.max(forcedLevel.getPriority(), invocationLogLevel.getPriority()); 107 return messageLogLevel.getPriority() >= minWriteLevel; 108 } 109 110 /** 111 * Writes a message to the output stream. 112 * 113 * @param message the entry to write to log 114 * @throws IOException if an I/O error occurs 115 */ writeToLog(String message)116 protected void writeToLog(String message) throws IOException { 117 if (mOutputStream != null) { 118 mOutputStream.write(message.getBytes()); 119 } 120 } 121 } 122