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