blob: d72d6bd47a817af5272c6a1f4755d1fa17142648 [file] [log] [blame]
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.tradefed.log;
import com.android.ddmlib.Log.LogLevel;
import com.android.tradefed.config.Option;
import com.android.tradefed.config.Option.Importance;
import com.android.tradefed.config.OptionClass;
import com.android.tradefed.result.ByteArrayInputStreamSource;
import com.android.tradefed.result.InputStreamSource;
import com.android.tradefed.result.SnapshotInputStreamSource;
import com.android.tradefed.util.SizeLimitedOutputStream;
import com.android.tradefed.util.StreamUtil;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.HashSet;
/**
* A {@link ILeveledLogOutput} that directs log messages to a file and to stdout.
*/
@OptionClass(alias = "file")
public class FileLogger implements ILeveledLogOutput {
private static final String TEMP_FILE_PREFIX = "tradefed_log_";
private static final String TEMP_FILE_SUFFIX = ".txt";
@Option(name = "log-level", description = "the minimum log level to log.")
private LogLevel mLogLevel = LogLevel.DEBUG;
@Option(name = "log-level-display", shortName = 'l',
description = "the minimum log level to display on stdout.",
importance = Importance.ALWAYS)
private LogLevel mLogLevelDisplay = LogLevel.ERROR;
@Option(name = "log-tag-display", description = "Always display given tags logs on stdout")
private Collection<String> mLogTagsDisplay = new HashSet<String>();
@Option(name = "max-log-size", description = "maximum allowable size of tmp log data in mB.")
private long mMaxLogSizeMbytes = 20;
private SizeLimitedOutputStream mLogStream;
/**
* Adds tags to the log-tag-display list
*
* @param tags collection of tags to add
*/
void addLogTagsDisplay(Collection<String> tags) {
mLogTagsDisplay.addAll(tags);
}
public FileLogger() {
}
/**
* {@inheritDoc}
*/
@Override
public void init() throws IOException {
mLogStream = new SizeLimitedOutputStream(mMaxLogSizeMbytes * 1024 * 1024,
TEMP_FILE_PREFIX, TEMP_FILE_SUFFIX);
}
/**
* Creates a new {@link FileLogger} with the same log level settings as the current object.
* <p/>
* Does not copy underlying log file content (ie the clone's log data will be written to a new
* file.)
*/
@Override
public ILeveledLogOutput clone() {
FileLogger logger = new FileLogger();
logger.setLogLevelDisplay(mLogLevelDisplay);
logger.setLogLevel(mLogLevel);
logger.addLogTagsDisplay(mLogTagsDisplay);
return logger;
}
/**
* {@inheritDoc}
*/
@Override
public void printAndPromptLog(LogLevel logLevel, String tag, String message) {
internalPrintLog(logLevel, tag, message, true /* force print to stdout */);
}
/**
* {@inheritDoc}
*/
@Override
public void printLog(LogLevel logLevel, String tag, String message) {
internalPrintLog(logLevel, tag, message, false /* don't force stdout */);
}
/**
* A version of printLog(...) which can be forced to print to stdout, even if the log level
* isn't above the urgency threshold.
*/
private void internalPrintLog(LogLevel logLevel, String tag, String message,
boolean forceStdout) {
String outMessage = LogUtil.getLogFormatString(logLevel, tag, message);
if (forceStdout
|| logLevel.getPriority() >= mLogLevelDisplay.getPriority()
|| mLogTagsDisplay.contains(tag)) {
System.out.print(outMessage);
}
try {
writeToLog(outMessage);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Writes given message to log.
* <p/>
* Exposed for unit testing.
*
* @param outMessage the entry to write to log
* @throws IOException
*/
void writeToLog(String outMessage) throws IOException {
if (mLogStream != null) {
mLogStream.write(outMessage.getBytes());
}
}
/**
* {@inheritDoc}
*/
@Override
public LogLevel getLogLevel() {
return mLogLevel;
}
/**
* {@inheritDoc}
*/
@Override
public void setLogLevel(LogLevel logLevel) {
mLogLevel = logLevel;
}
/**
* Sets the log level filtering for stdout.
*
* @param logLevel the minimum {@link LogLevel} to display
*/
void setLogLevelDisplay(LogLevel logLevel) {
mLogLevelDisplay = logLevel;
}
/**
* Gets the log level filtering for stdout.
*
* @return the current {@link LogLevel}
*/
LogLevel getLogLevelDisplay() {
return mLogLevelDisplay;
}
/**
* {@inheritDoc}
*/
@Override
public InputStreamSource getLog() {
if (mLogStream != null) {
try {
// create a InputStream from log file
mLogStream.flush();
return new SnapshotInputStreamSource(mLogStream.getData());
} catch (IOException e) {
System.err.println("Failed to get log");
e.printStackTrace();
}
}
return new ByteArrayInputStreamSource(new byte[0]);
}
/**
* {@inheritDoc}
*/
@Override
public void closeLog() {
try {
doCloseLog();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Flushes stream and closes log file.
* <p/>
* Exposed for unit testing.
*
* @throws IOException
*/
void doCloseLog() throws IOException {
SizeLimitedOutputStream stream = mLogStream;
mLogStream = null;
if (stream != null) {
try {
stream.flush();
stream.close();
} finally {
stream.delete();
}
}
}
/**
* Dump the contents of the input stream to this log
*
* @param createInputStream
* @throws IOException
*/
void dumpToLog(InputStream inputStream) throws IOException {
if (mLogStream != null) {
StreamUtil.copyStreams(inputStream, mLogStream);
}
}
}