1 /* 2 * Copyright (C) 2016 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 17 package com.android.tradefed.result; 18 19 import com.android.ddmlib.Log.LogLevel; 20 import com.android.tradefed.config.IConfiguration; 21 import com.android.tradefed.invoker.IInvocationContext; 22 import com.android.tradefed.invoker.TestInvocation; 23 import com.android.tradefed.invoker.logger.InvocationMetricLogger; 24 import com.android.tradefed.invoker.logger.InvocationMetricLogger.InvocationMetricKey; 25 import com.android.tradefed.log.LogRegistry; 26 import com.android.tradefed.log.LogUtil.CLog; 27 import com.android.tradefed.log.StdoutLogger; 28 import com.android.tradefed.util.StreamUtil; 29 import com.android.tradefed.util.SystemUtil; 30 31 import java.io.IOException; 32 import java.io.InputStream; 33 import java.util.List; 34 35 /** A {@link ResultForwarder} for saving logs with the global file saver. */ 36 public class LogSaverResultForwarder extends ResultForwarder implements ILogSaverListener { 37 38 ILogSaver mLogSaver; 39 IConfiguration mConfig; 40 LogSaverResultForwarder( ILogSaver logSaver, List<ITestInvocationListener> listeners, IConfiguration config)41 public LogSaverResultForwarder( 42 ILogSaver logSaver, List<ITestInvocationListener> listeners, IConfiguration config) { 43 this(logSaver, listeners, config, true); 44 } 45 LogSaverResultForwarder( ILogSaver logSaver, List<ITestInvocationListener> listeners, IConfiguration config, boolean setLogSaver)46 public LogSaverResultForwarder( 47 ILogSaver logSaver, 48 List<ITestInvocationListener> listeners, 49 IConfiguration config, 50 boolean setLogSaver) { 51 super(listeners); 52 mLogSaver = logSaver; 53 mConfig = config; 54 if (setLogSaver) { 55 for (ITestInvocationListener listener : listeners) { 56 if (listener instanceof ILogSaverListener) { 57 ((ILogSaverListener) listener).setLogSaver(mLogSaver); 58 } 59 } 60 } 61 } 62 63 /** 64 * {@inheritDoc} 65 */ 66 @Override invocationStarted(IInvocationContext context)67 public void invocationStarted(IInvocationContext context) { 68 // Intentionally call invocationStarted for the log saver first. 69 try { 70 mLogSaver.invocationStarted(context); 71 } catch (RuntimeException e) { 72 CLog.e("Caught runtime exception from log saver: %s", mLogSaver.getClass().getName()); 73 CLog.e(e); 74 } 75 InvocationSummaryHelper.reportInvocationStarted(getListeners(), context); 76 } 77 78 /** 79 * {@inheritDoc} 80 */ 81 @Override invocationEnded(long elapsedTime)82 public void invocationEnded(long elapsedTime) { 83 InvocationSummaryHelper.reportInvocationEnded(getListeners(), elapsedTime); 84 // Intentionally call invocationEnded for the log saver last. 85 try { 86 mLogSaver.invocationEnded(elapsedTime); 87 } catch (RuntimeException e) { 88 CLog.e("Caught runtime exception from log saver: %s", mLogSaver.getClass().getName()); 89 CLog.e(e); 90 } 91 String endHostLogName = TestInvocation.TRADEFED_END_HOST_LOG; 92 if (mConfig.getCommandOptions().getHostLogSuffix() != null) { 93 endHostLogName += mConfig.getCommandOptions().getHostLogSuffix(); 94 } 95 reportEndHostLog(getListeners(), mLogSaver, endHostLogName); 96 } 97 98 /** Log a final file before completion */ logFile( List<ITestInvocationListener> listeners, ILogSaver saver, InputStreamSource source, String name, LogDataType type)99 public static void logFile( 100 List<ITestInvocationListener> listeners, 101 ILogSaver saver, 102 InputStreamSource source, 103 String name, 104 LogDataType type) { 105 try (InputStream stream = source.createInputStream()) { 106 LogFile logFile = saver.saveLogData(name, type, stream); 107 108 for (ITestInvocationListener listener : listeners) { 109 try { 110 if (listener instanceof ILogSaverListener) { 111 ((ILogSaverListener) listener).testLogSaved(name, type, source, logFile); 112 ((ILogSaverListener) listener).logAssociation(name, logFile); 113 } 114 } catch (Exception e) { 115 CLog.logAndDisplay(LogLevel.ERROR, e.getMessage()); 116 CLog.e(e); 117 } 118 } 119 } catch (IOException e) { 120 CLog.e(e); 121 } 122 } 123 124 /** Reports host_log from session in progress. */ reportEndHostLog( List<ITestInvocationListener> listeners, ILogSaver saver, String name)125 public static void reportEndHostLog( 126 List<ITestInvocationListener> listeners, ILogSaver saver, String name) { 127 LogRegistry registry = (LogRegistry) LogRegistry.getLogRegistry(); 128 try (InputStreamSource source = registry.getLogger().getLog()) { 129 if (source == null) { 130 if (!(registry.getLogger() instanceof StdoutLogger)) { 131 CLog.e("%s stream was null, skip saving it.", name); 132 } 133 return; 134 } 135 logFile(listeners, saver, source, name, LogDataType.HOST_LOG); 136 if (SystemUtil.isRemoteEnvironment()) { 137 try (InputStream stream = source.createInputStream()) { 138 // In remote environment, dump to the stdout so we can get the logs in the 139 // console. 140 System.out.println( 141 String.format( 142 "===== Result Reporters =====\n%s", 143 StreamUtil.getStringFromStream(stream))); 144 } 145 } 146 } catch (IOException e) { 147 CLog.e(e); 148 } 149 } 150 151 /** 152 * {@inheritDoc} 153 * <p/> 154 * Also, save the log file with the global {@link ILogSaver} and call 155 * {@link ILogSaverListener#testLogSaved(String, LogDataType, InputStreamSource, LogFile)} 156 * for those listeners implementing the {@link ILogSaverListener} interface. 157 */ 158 @Override testLog(String dataName, LogDataType dataType, InputStreamSource dataStream)159 public void testLog(String dataName, LogDataType dataType, InputStreamSource dataStream) { 160 testLogForward(dataName, dataType, dataStream); 161 try { 162 if (dataStream == null) { 163 CLog.w("Skip forwarding of '%s', data stream is null.", dataName); 164 return; 165 } 166 long startTime = System.currentTimeMillis(); 167 LogFile logFile = null; 168 try { 169 // If it's a file, copy it directly as it's faster 170 if (dataStream instanceof FileInputStreamSource) { 171 logFile = 172 mLogSaver.saveLogFile( 173 dataName, 174 dataType, 175 ((FileInputStreamSource) dataStream).getFile()); 176 } else { 177 logFile = 178 mLogSaver.saveLogData( 179 dataName, dataType, dataStream.createInputStream()); 180 } 181 } finally { 182 InvocationMetricLogger.addInvocationMetrics( 183 InvocationMetricKey.LOG_SAVING_TIME, 184 System.currentTimeMillis() - startTime); 185 InvocationMetricLogger.addInvocationMetrics( 186 InvocationMetricKey.LOG_SAVING_COUNT, 1); 187 } 188 for (ITestInvocationListener listener : getListeners()) { 189 if (listener instanceof ILogSaverListener) { 190 ((ILogSaverListener) listener).testLogSaved(dataName, dataType, 191 dataStream, logFile); 192 ((ILogSaverListener) listener).logAssociation(dataName, logFile); 193 } 194 } 195 } catch (RuntimeException | IOException e) { 196 CLog.e("Failed to save log data: %s", dataName); 197 CLog.e(e); 198 } 199 } 200 201 /** Only forward the testLog instead of saving the log first. */ testLogForward( String dataName, LogDataType dataType, InputStreamSource dataStream)202 public void testLogForward( 203 String dataName, LogDataType dataType, InputStreamSource dataStream) { 204 super.testLog(dataName, dataType, dataStream); 205 } 206 207 /** 208 * {@inheritDoc} 209 * 210 * <p>If {@link LogSaverResultForwarder} is wrap in another one, ensure we forward the 211 * testLogSaved callback to the listeners under it. 212 */ 213 @Override testLogSaved( String dataName, LogDataType dataType, InputStreamSource dataStream, LogFile logFile)214 public void testLogSaved( 215 String dataName, LogDataType dataType, InputStreamSource dataStream, LogFile logFile) { 216 try { 217 for (ITestInvocationListener listener : getListeners()) { 218 if (listener instanceof ILogSaverListener) { 219 ((ILogSaverListener) listener) 220 .testLogSaved(dataName, dataType, dataStream, logFile); 221 } 222 } 223 } catch (RuntimeException e) { 224 CLog.e("Failed to save log data for %s", dataName); 225 CLog.e(e); 226 } 227 } 228 229 /** {@inheritDoc} */ 230 @Override logAssociation(String dataName, LogFile logFile)231 public void logAssociation(String dataName, LogFile logFile) { 232 for (ITestInvocationListener listener : getListeners()) { 233 try { 234 // Forward the logAssociation call 235 if (listener instanceof ILogSaverListener) { 236 ((ILogSaverListener) listener).logAssociation(dataName, logFile); 237 } 238 } catch (RuntimeException e) { 239 CLog.e("Failed to provide the log association"); 240 CLog.e(e); 241 } 242 } 243 } 244 } 245