/*
* Copyright (C) 2011 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;
import com.android.ddmlib.Log.LogLevel;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* A logging utility class. Useful for code that needs to override static
* methods from {@link Log}
*/
public class LogUtil {
/**
* Make uninstantiable
*/
private LogUtil() {
}
/**
* Sent when a log message needs to be printed. This implementation prints
* the message to stdout in all cases.
*
* @param logLevel
* The {@link LogLevel} enum representing the priority of the
* message.
* @param tag
* The tag associated with the message.
* @param message
* The message to display.
*/
public static void printLog(LogLevel logLevel, String tag, String message) {
System.out.print(LogUtil.getLogFormatString(logLevel, tag, message));
}
/**
* Creates a format string that is similar to the "threadtime" log format on
* the device. This is specifically useful because it includes the day and
* month (to differentiate times for long-running TF instances), and also
* uses 24-hour time to disambiguate morning from evening.
* <p/>
* {@see Log#getLogFormatString()}
*/
public static String getLogFormatString(LogLevel logLevel, String tag,
String message) {
SimpleDateFormat formatter = new SimpleDateFormat("MM-dd HH:mm:ss");
return String.format("%s %c/%s: %s\n", formatter.format(new Date()),
logLevel.getPriorityLetter(), tag, message);
}
/**
* A shim class for {@link Log} that automatically uses the simple classname
* of the caller as the log tag
*/
public static class CLog {
/**
* The shim version of {@link Log#v(String, String)}.
*
* @param message
* The {@code String} to log
*/
public static void v(String message) {
// frame 2: skip frames 0 (#getClassName) and 1 (this method)
Log.v(getClassName(2), message);
}
/**
* The shim version of {@link Log#v(String, String)}. Also calls
* String.format for convenience.
*
* @param format
* A format string for the message to log
* @param args
* The format string arguments
*/
public static void v(String format, Object... args) {
// frame 2: skip frames 0 (#getClassName) and 1 (this method)
Log.v(getClassName(2), String.format(format, args));
}
/**
* The shim version of {@link Log#d(String, String)}.
*
* @param message
* The {@code String} to log
*/
public static void d(String message) {
// frame 2: skip frames 0 (#getClassName) and 1 (this method)
Log.d(getClassName(2), message);
}
/**
* The shim version of {@link Log#d(String, String)}. Also calls
* String.format for convenience.
*
* @param format
* A format string for the message to log
* @param args
* The format string arguments
*/
public static void d(String format, Object... args) {
// frame 2: skip frames 0 (#getClassName) and 1 (this method)
Log.d(getClassName(2), String.format(format, args));
}
/**
* The shim version of {@link Log#i(String, String)}.
*
* @param message
* The {@code String} to log
*/
public static void i(String message) {
// frame 2: skip frames 0 (#getClassName) and 1 (this method)
Log.i(getClassName(2), message);
}
/**
* The shim version of {@link Log#i(String, String)}. Also calls
* String.format for convenience.
*
* @param format
* A format string for the message to log
* @param args
* The format string arguments
*/
public static void i(String format, Object... args) {
// frame 2: skip frames 0 (#getClassName) and 1 (this method)
Log.i(getClassName(2), String.format(format, args));
System.out.flush();
}
/**
* The shim version of {@link Log#w(String, String)}.
*
* @param message
* The {@code String} to log
*/
public static void w(String message) {
// frame 2: skip frames 0 (#getClassName) and 1 (this method)
Log.w(getClassName(2), message);
}
/**
* The shim version of {@link Log#w(String, String)}. Also calls
* String.format for convenience.
*
* @param format
* A format string for the message to log
* @param args
* The format string arguments
*/
public static void w(String format, Object... args) {
// frame 2: skip frames 0 (#getClassName) and 1 (this method)
Log.w(getClassName(2), String.format(format, args));
}
/**
* The shim version of {@link Log#e(String, String)}.
*
* @param message
* The {@code String} to log
*/
public static void e(String message) {
// frame 2: skip frames 0 (#getClassName) and 1 (this method)
Log.e(getClassName(2), message);
}
/**
* The shim version of {@link Log#e(String, String)}. Also calls
* String.format for convenience.
*
* @param format
* A format string for the message to log
* @param args
* The format string arguments
*/
public static void e(String format, Object... args) {
// frame 2: skip frames 0 (#getClassName) and 1 (this method)
Log.e(getClassName(2), String.format(format, args));
}
/**
* The shim version of {@link Log#e(String, Throwable)}.
*
* @param t
* the {@link Throwable} to output.
*/
public static void e(Throwable t) {
// frame 2: skip frames 0 (#getClassName) and 1 (this method)
Log.e(getClassName(2), t);
}
/**
* The shim version of
* {@link Log#logAndDisplay(LogLevel, String, String)}.
*
* @param logLevel
* the {@link LogLevel}
* @param format
* A format string for the message to log
* @param args
* The format string arguments
*/
public static void logAndDisplay(LogLevel logLevel, String format,
Object... args) {
// frame 2: skip frames 0 (#getClassName) and 1 (this method)
Log.logAndDisplay(logLevel, getClassName(2),
String.format(format, args));
System.out.flush();
}
/**
* Return the simple classname from the {@code frame}th stack frame in
* the call path. Note: this method does <emph>not</emph> check array
* bounds for the stack trace length.
*
* @param frame
* The index of the stack trace frame to inspect for the
* class name
* @return The simple class name (or full-qualified if an error occurs
* getting a ref to the class) for the given element of the
* stack trace.
*/
public static String getClassName(int frame) {
StackTraceElement[] frames = (new Throwable()).getStackTrace();
String fullName = frames[frame].getClassName();
@SuppressWarnings("rawtypes")
Class klass = null;
try {
klass = Class.forName(fullName);
} catch (ClassNotFoundException e) {
// oops; not much we can do.
// Intentionally fall through so we hit the null check below
}
if (klass == null) {
return fullName;
} else {
return klass.getSimpleName();
}
}
}
}