13713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick/* 23713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * Copyright (C) 2011 The Android Open Source Project 33713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * 43713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * Licensed under the Apache License, Version 2.0 (the "License"); 53713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * you may not use this file except in compliance with the License. 63713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * You may obtain a copy of the License at 73713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * 83713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * http://www.apache.org/licenses/LICENSE-2.0 93713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * 103713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * Unless required by applicable law or agreed to in writing, software 113713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * distributed under the License is distributed on an "AS IS" BASIS, 123713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * See the License for the specific language governing permissions and 143713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * limitations under the License. 153713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick */ 163713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 173713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickpackage com.android.volley; 183713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 199c19fc62ddd9d1b371cb3ead4e10bb5ff1100a6cJeff Sharkeyimport android.os.SystemClock; 203713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickimport android.util.Log; 213713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 223713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickimport java.util.ArrayList; 233713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickimport java.util.List; 243713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickimport java.util.Locale; 253713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 263713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick/** Logging helper class. */ 273713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickpublic class VolleyLog { 283713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick public static String TAG = "Volley"; 293713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 303713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick public static final boolean DEBUG = Log.isLoggable(TAG, Log.VERBOSE); 313713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 323713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick public static void v(String format, Object... args) { 333713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick if (DEBUG) { 343713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick Log.v(TAG, buildMessage(format, args)); 353713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } 363713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } 373713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 383713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick public static void d(String format, Object... args) { 393713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick Log.d(TAG, buildMessage(format, args)); 403713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } 413713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 423713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick public static void e(String format, Object... args) { 433713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick Log.e(TAG, buildMessage(format, args)); 443713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } 453713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 463713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick public static void wtf(String format, Object... args) { 473713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick Log.wtf(TAG, buildMessage(format, args)); 483713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } 493713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 503713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick public static void wtf(Throwable tr, String format, Object... args) { 513713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick Log.wtf(TAG, buildMessage(format, args), tr); 523713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } 533713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 543713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick /** 553713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * Formats the caller's provided message and prepends useful info like 563713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * calling thread ID and method name. 573713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick */ 583713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick private static String buildMessage(String format, Object... args) { 593713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick String msg = (args == null) ? format : String.format(Locale.US, format, args); 603713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick StackTraceElement[] trace = new Throwable().fillInStackTrace().getStackTrace(); 613713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 623713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick String caller = "<unknown>"; 633713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick // Walk up the stack looking for the first caller outside of VolleyLog. 643713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick // It will be at least two frames up, so start there. 653713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick for (int i = 2; i < trace.length; i++) { 663713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick Class<?> clazz = trace[i].getClass(); 673713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick if (!clazz.equals(VolleyLog.class)) { 683713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick String callingClass = trace[i].getClassName(); 693713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick callingClass = callingClass.substring(callingClass.lastIndexOf('.') + 1); 703713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick callingClass = callingClass.substring(callingClass.lastIndexOf('$') + 1); 713713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 723713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick caller = callingClass + "." + trace[i].getMethodName(); 733713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick break; 743713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } 753713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } 763713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick return String.format(Locale.US, "[%d] %s: %s", 773713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick Thread.currentThread().getId(), caller, msg); 783713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } 793713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 803713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick /** 813713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * A simple event log with records containing a name, thread ID, and timestamp. 823713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick */ 833713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick static class MarkerLog { 843713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick public static final boolean ENABLED = VolleyLog.DEBUG; 853713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 863713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick /** Minimum duration from first marker to last in an marker log to warrant logging. */ 873713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick private static final long MIN_DURATION_FOR_LOGGING_MS = 0; 883713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 893713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick private static class Marker { 903713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick public final String name; 913713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick public final long thread; 923713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick public final long time; 933713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 943713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick public Marker(String name, long thread, long time) { 953713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick this.name = name; 963713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick this.thread = thread; 973713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick this.time = time; 983713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } 993713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } 1003713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 1013713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick private final List<Marker> mMarkers = new ArrayList<Marker>(); 1023713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick private boolean mFinished = false; 1033713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 1043713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick /** Adds a marker to this log with the specified name. */ 1053713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick public synchronized void add(String name, long threadId) { 1063713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick if (mFinished) { 1073713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick throw new IllegalStateException("Marker added to finished log"); 1083713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } 1093713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 1109c19fc62ddd9d1b371cb3ead4e10bb5ff1100a6cJeff Sharkey mMarkers.add(new Marker(name, threadId, SystemClock.elapsedRealtime())); 1113713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } 1123713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 1133713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick /** 1143713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * Closes the log, dumping it to logcat if the time difference between 1153713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * the first and last markers is greater than {@link #MIN_DURATION_FOR_LOGGING_MS}. 1163713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * @param header Header string to print above the marker log. 1173713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick */ 1183713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick public synchronized void finish(String header) { 1193713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick mFinished = true; 1203713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 1213713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick long duration = getTotalDuration(); 1223713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick if (duration <= MIN_DURATION_FOR_LOGGING_MS) { 1233713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick return; 1243713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } 1253713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 1263713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick long prevTime = mMarkers.get(0).time; 1273713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick d("(%-4d ms) %s", duration, header); 1283713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick for (Marker marker : mMarkers) { 1293713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick long thisTime = marker.time; 1303713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick d("(+%-4d) [%2d] %s", (thisTime - prevTime), marker.thread, marker.name); 1313713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick prevTime = thisTime; 1323713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } 1333713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } 1343713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 1353713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick @Override 1363713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick protected void finalize() throws Throwable { 1373713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick // Catch requests that have been collected (and hence end-of-lifed) 1383713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick // but had no debugging output printed for them. 1393713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick if (!mFinished) { 1403713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick finish("Request on the loose"); 1413713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick e("Marker log finalized without finish() - uncaught exit point for request"); 1423713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } 1433713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } 1443713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 1453713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick /** Returns the time difference between the first and last events in this log. */ 1463713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick private long getTotalDuration() { 1473713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick if (mMarkers.size() == 0) { 1483713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick return 0; 1493713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } 1503713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 1513713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick long first = mMarkers.get(0).time; 1523713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick long last = mMarkers.get(mMarkers.size() - 1).time; 1533713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick return last - first; 1543713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } 1553713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } 1563713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick} 157