1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.messaging.util;
18
19/**
20 * Log utility class.
21 */
22public class LogUtil {
23    public static final String BUGLE_TAG = "MessagingApp";
24    public static final String PROFILE_TAG = "MessagingAppProf";
25    public static final String BUGLE_DATABASE_TAG = "MessagingAppDb";
26    public static final String BUGLE_DATABASE_PERF_TAG = "MessagingAppDbPerf";
27    public static final String BUGLE_DATAMODEL_TAG = "MessagingAppDataModel";
28    public static final String BUGLE_IMAGE_TAG = "MessagingAppImage";
29    public static final String BUGLE_NOTIFICATIONS_TAG = "MessagingAppNotif";
30    public static final String BUGLE_WIDGET_TAG = "MessagingAppWidget";
31
32    public static final int DEBUG = android.util.Log.DEBUG;
33    public static final int WARN = android.util.Log.WARN;
34    public static final int VERBOSE = android.util.Log.VERBOSE;
35    public static final int INFO = android.util.Log.INFO;
36    public static final int ERROR = android.util.Log.ERROR;
37
38    // If this is non-null, DEBUG and higher logs will be tracked in-memory. It will not include
39    // VERBOSE logs.
40    private static LogSaver sDebugLogSaver;
41    private static volatile boolean sCaptureDebugLogs;
42
43    /**
44     * Read Gservices to see if logging should be enabled.
45     */
46    public static void refreshGservices(final BugleGservices gservices) {
47        sCaptureDebugLogs = gservices.getBoolean(
48                BugleGservicesKeys.ENABLE_LOG_SAVER,
49                BugleGservicesKeys.ENABLE_LOG_SAVER_DEFAULT);
50        if (sCaptureDebugLogs && (sDebugLogSaver == null || !sDebugLogSaver.isCurrent())) {
51            // We were not capturing logs before. We are now.
52            sDebugLogSaver = LogSaver.newInstance();
53        } else if (!sCaptureDebugLogs && sDebugLogSaver != null) {
54            // We were capturing logs. We aren't anymore.
55            sDebugLogSaver = null;
56        }
57    }
58
59 // This is called from FactoryImpl once the Gservices class is initialized.
60    public static void initializeGservices (final BugleGservices gservices) {
61        gservices.registerForChanges(new Runnable() {
62            @Override
63            public void run() {
64                refreshGservices(gservices);
65            }
66        });
67        refreshGservices(gservices);
68    }
69
70    /**
71     * Send a {@link #VERBOSE} log message.
72     * @param tag Used to identify the source of a log message.  It usually identifies
73     *        the class or activity where the log call occurs.
74     * @param msg The message you would like logged.
75     */
76    public static void v(final String tag, final String msg) {
77        println(android.util.Log.VERBOSE, tag, msg);
78    }
79
80    /**
81     * Send a {@link #VERBOSE} log message.
82     * @param tag Used to identify the source of a log message.  It usually identifies
83     *        the class or activity where the log call occurs.
84     * @param msg The message you would like logged.
85     * @param tr An exception to log
86     */
87    public static void v(final String tag, final String msg, final Throwable tr) {
88        println(android.util.Log.VERBOSE, tag, msg + '\n'
89                + android.util.Log.getStackTraceString(tr));
90    }
91
92    /**
93     * Send a {@link #DEBUG} log message.
94     * @param tag Used to identify the source of a log message.  It usually identifies
95     *        the class or activity where the log call occurs.
96     * @param msg The message you would like logged.
97     */
98    public static void d(final String tag, final String msg) {
99        println(android.util.Log.DEBUG, tag, msg);
100    }
101
102    /**
103     * Send a {@link #DEBUG} log message and log the exception.
104     * @param tag Used to identify the source of a log message.  It usually identifies
105     *        the class or activity where the log call occurs.
106     * @param msg The message you would like logged.
107     * @param tr An exception to log
108     */
109    public static void d(final String tag, final String msg, final Throwable tr) {
110        println(android.util.Log.DEBUG, tag, msg + '\n'
111                + android.util.Log.getStackTraceString(tr));
112    }
113
114    /**
115     * Send an {@link #INFO} log message.
116     * @param tag Used to identify the source of a log message.  It usually identifies
117     *        the class or activity where the log call occurs.
118     * @param msg The message you would like logged.
119     */
120    public static void i(final String tag, final String msg) {
121        println(android.util.Log.INFO, tag, msg);
122    }
123
124    /**
125     * Send a {@link #INFO} log message and log the exception.
126     * @param tag Used to identify the source of a log message.  It usually identifies
127     *        the class or activity where the log call occurs.
128     * @param msg The message you would like logged.
129     * @param tr An exception to log
130     */
131    public static void i(final String tag, final String msg, final Throwable tr) {
132        println(android.util.Log.INFO, tag, msg + '\n'
133                + android.util.Log.getStackTraceString(tr));
134    }
135
136    /**
137     * Send a {@link #WARN} log message.
138     * @param tag Used to identify the source of a log message.  It usually identifies
139     *        the class or activity where the log call occurs.
140     * @param msg The message you would like logged.
141     */
142    public static void w(final String tag, final String msg) {
143        println(android.util.Log.WARN, tag, msg);
144    }
145
146    /**
147     * Send a {@link #WARN} log message and log the exception.
148     * @param tag Used to identify the source of a log message.  It usually identifies
149     *        the class or activity where the log call occurs.
150     * @param msg The message you would like logged.
151     * @param tr An exception to log
152     */
153    public static void w(final String tag, final String msg, final Throwable tr) {
154        println(android.util.Log.WARN, tag, msg);
155        println(android.util.Log.WARN, tag, android.util.Log.getStackTraceString(tr));
156    }
157
158    /**
159     * Send an {@link #ERROR} log message.
160     * @param tag Used to identify the source of a log message.  It usually identifies
161     *        the class or activity where the log call occurs.
162     * @param msg The message you would like logged.
163     */
164    public static void e(final String tag, final String msg) {
165        println(android.util.Log.ERROR, tag, msg);
166    }
167
168    /**
169     * Send a {@link #ERROR} log message and log the exception.
170     * @param tag Used to identify the source of a log message.  It usually identifies
171     *        the class or activity where the log call occurs.
172     * @param msg The message you would like logged.
173     * @param tr An exception to log
174     */
175    public static void e(final String tag, final String msg, final Throwable tr) {
176        println(android.util.Log.ERROR, tag, msg);
177        println(android.util.Log.ERROR, tag, android.util.Log.getStackTraceString(tr));
178    }
179
180    /**
181     * What a Terrible Failure: Report a condition that should never happen.
182     * The error will always be logged at level ASSERT with the call stack.
183     * Depending on system configuration, a report may be added to the
184     * {@link android.os.DropBoxManager} and/or the process may be terminated
185     * immediately with an error dialog.
186     * @param tag Used to identify the source of a log message.
187     * @param msg The message you would like logged.
188     */
189    public static void wtf(final String tag, final String msg) {
190        // Make sure this goes into our log buffer
191        println(android.util.Log.ASSERT, tag, "wtf\n" + msg);
192        android.util.Log.wtf(tag, msg, new Exception());
193    }
194
195    /**
196     * What a Terrible Failure: Report a condition that should never happen.
197     * The error will always be logged at level ASSERT with the call stack.
198     * Depending on system configuration, a report may be added to the
199     * {@link android.os.DropBoxManager} and/or the process may be terminated
200     * immediately with an error dialog.
201     * @param tag Used to identify the source of a log message.
202     * @param msg The message you would like logged.
203     * @param tr An exception to log
204     */
205    public static void wtf(final String tag, final String msg, final Throwable tr) {
206        // Make sure this goes into our log buffer
207        println(android.util.Log.ASSERT, tag, "wtf\n" + msg + '\n' +
208                android.util.Log.getStackTraceString(tr));
209        android.util.Log.wtf(tag, msg, tr);
210    }
211
212    /**
213     * Low-level logging call.
214     * @param level The priority/type of this log message
215     * @param tag Used to identify the source of a log message.  It usually identifies
216     *        the class or activity where the log call occurs.
217     * @param msg The message you would like logged.
218     */
219    private static void println(final int level, final String tag, final String msg) {
220        android.util.Log.println(level, tag, msg);
221
222        LogSaver serviceLog = sDebugLogSaver;
223        if (serviceLog != null && level >= android.util.Log.DEBUG) {
224            serviceLog.log(level, tag, msg);
225        }
226    }
227
228    /**
229     * Save logging into LogSaver only, for dumping to bug report
230     *
231     * @param level The priority/type of this log message
232     * @param tag Used to identify the source of a log message.  It usually identifies
233     *        the class or activity where the log call occurs.
234     * @param msg The message you would like logged.
235     */
236    public static void save(final int level, final String tag, final String msg) {
237        LogSaver serviceLog = sDebugLogSaver;
238        if (serviceLog != null) {
239            serviceLog.log(level, tag, msg);
240        }
241    }
242
243    /**
244     * Checks to see whether or not a log for the specified tag is loggable at the specified level.
245     * See {@link android.util.Log#isLoggable(String, int)} for more discussion.
246     */
247    public static boolean isLoggable(final String tag, final int level) {
248        return android.util.Log.isLoggable(tag, level);
249    }
250
251    /**
252     * Returns text as is if {@value #BUGLE_TAG}'s log level is set to DEBUG or VERBOSE;
253     * returns "--" otherwise. Useful for log statements where we don't want to log
254     * various strings (e.g., usernames) with default logging to avoid leaking PII in logcat.
255     */
256    public static String sanitizePII(final String text) {
257        if (text == null) {
258            return null;
259        }
260
261        if (android.util.Log.isLoggable(BUGLE_TAG, android.util.Log.DEBUG)) {
262            return text;
263        } else {
264            return "Redacted-" + text.length();
265        }
266    }
267
268    public static void dump(java.io.PrintWriter out) {
269        final LogSaver logsaver = sDebugLogSaver;
270        if (logsaver != null) {
271            logsaver.dump(out);
272        }
273    }
274}
275