VolleyLog.java revision 3713094c56d25e25df2a508dbee4aea869ffdea1
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
193713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickimport android.util.Log;
203713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
213713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickimport java.util.ArrayList;
223713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickimport java.util.List;
233713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickimport java.util.Locale;
243713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
253713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick/** Logging helper class. */
263713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickpublic class VolleyLog {
273713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    public static String TAG = "Volley";
283713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
293713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    public static final boolean DEBUG = Log.isLoggable(TAG, Log.VERBOSE);
303713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
313713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    public static void v(String format, Object... args) {
323713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        if (DEBUG) {
333713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            Log.v(TAG, buildMessage(format, args));
343713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        }
353713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    }
363713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
373713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    public static void d(String format, Object... args) {
383713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        Log.d(TAG, buildMessage(format, args));
393713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    }
403713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
413713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    public static void e(String format, Object... args) {
423713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        Log.e(TAG, buildMessage(format, args));
433713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    }
443713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
453713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    public static void wtf(String format, Object... args) {
463713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        Log.wtf(TAG, buildMessage(format, args));
473713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    }
483713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
493713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    public static void wtf(Throwable tr, String format, Object... args) {
503713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        Log.wtf(TAG, buildMessage(format, args), tr);
513713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    }
523713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
533713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    /**
543713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick     * Formats the caller's provided message and prepends useful info like
553713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick     * calling thread ID and method name.
563713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick     */
573713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    private static String buildMessage(String format, Object... args) {
583713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        String msg = (args == null) ? format : String.format(Locale.US, format, args);
593713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        StackTraceElement[] trace = new Throwable().fillInStackTrace().getStackTrace();
603713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
613713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        String caller = "<unknown>";
623713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        // Walk up the stack looking for the first caller outside of VolleyLog.
633713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        // It will be at least two frames up, so start there.
643713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        for (int i = 2; i < trace.length; i++) {
653713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            Class<?> clazz = trace[i].getClass();
663713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            if (!clazz.equals(VolleyLog.class)) {
673713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                String callingClass = trace[i].getClassName();
683713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                callingClass = callingClass.substring(callingClass.lastIndexOf('.') + 1);
693713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                callingClass = callingClass.substring(callingClass.lastIndexOf('$') + 1);
703713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
713713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                caller = callingClass + "." + trace[i].getMethodName();
723713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                break;
733713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            }
743713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        }
753713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        return String.format(Locale.US, "[%d] %s: %s",
763713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                Thread.currentThread().getId(), caller, msg);
773713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    }
783713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
793713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    /**
803713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick     * A simple event log with records containing a name, thread ID, and timestamp.
813713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick     */
823713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    static class MarkerLog {
833713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        public static final boolean ENABLED = VolleyLog.DEBUG;
843713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
853713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        /** Minimum duration from first marker to last in an marker log to warrant logging. */
863713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        private static final long MIN_DURATION_FOR_LOGGING_MS = 0;
873713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
883713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        private static class Marker {
893713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            public final String name;
903713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            public final long thread;
913713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            public final long time;
923713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
933713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            public Marker(String name, long thread, long time) {
943713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                this.name = name;
953713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                this.thread = thread;
963713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                this.time = time;
973713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            }
983713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        }
993713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
1003713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        private final List<Marker> mMarkers = new ArrayList<Marker>();
1013713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        private boolean mFinished = false;
1023713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
1033713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        /** Adds a marker to this log with the specified name. */
1043713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        public synchronized void add(String name, long threadId) {
1053713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            if (mFinished) {
1063713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                throw new IllegalStateException("Marker added to finished log");
1073713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            }
1083713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
1093713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            mMarkers.add(new Marker(name, threadId, System.currentTimeMillis()));
1103713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        }
1113713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
1123713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        /**
1133713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick         * Closes the log, dumping it to logcat if the time difference between
1143713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick         * the first and last markers is greater than {@link #MIN_DURATION_FOR_LOGGING_MS}.
1153713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick         * @param header Header string to print above the marker log.
1163713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick         */
1173713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        public synchronized void finish(String header) {
1183713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            mFinished = true;
1193713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
1203713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            long duration = getTotalDuration();
1213713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            if (duration <= MIN_DURATION_FOR_LOGGING_MS) {
1223713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                return;
1233713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            }
1243713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
1253713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            long prevTime = mMarkers.get(0).time;
1263713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            d("(%-4d ms) %s", duration, header);
1273713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            for (Marker marker : mMarkers) {
1283713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                long thisTime = marker.time;
1293713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                d("(+%-4d) [%2d] %s", (thisTime - prevTime), marker.thread, marker.name);
1303713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                prevTime = thisTime;
1313713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            }
1323713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        }
1333713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
1343713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        @Override
1353713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        protected void finalize() throws Throwable {
1363713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            // Catch requests that have been collected (and hence end-of-lifed)
1373713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            // but had no debugging output printed for them.
1383713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            if (!mFinished) {
1393713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                finish("Request on the loose");
1403713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                e("Marker log finalized without finish() - uncaught exit point for request");
1413713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            }
1423713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        }
1433713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
1443713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        /** Returns the time difference between the first and last events in this log. */
1453713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        private long getTotalDuration() {
1463713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            if (mMarkers.size() == 0) {
1473713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                return 0;
1483713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            }
1493713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
1503713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            long first = mMarkers.get(0).time;
1513713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            long last = mMarkers.get(mMarkers.size() - 1).time;
1523713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            return last - first;
1533713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        }
1543713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    }
1553713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick}
156