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