Home | History | Annotate | Download | only in common
      1 /*
      2  * Copyright (C) 2016 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 
     17 package com.android.dialer.common;
     18 
     19 import android.support.annotation.NonNull;
     20 import android.support.annotation.Nullable;
     21 import android.telephony.PhoneNumberUtils;
     22 import android.text.TextUtils;
     23 
     24 /** Provides logging functions. */
     25 public class LogUtil {
     26 
     27   public static final String TAG = "Dialer";
     28   private static final String SEPARATOR = " - ";
     29 
     30   private LogUtil() {}
     31 
     32   /**
     33    * Log at a verbose level. Verbose logs should generally be filtered out, but may be useful when
     34    * additional information is needed (e.g. to see how a particular flow evolved). These logs will
     35    * not generally be available on production builds.
     36    *
     37    * @param tag An identifier to allow searching for related logs. Generally of the form
     38    *     'Class.method'.
     39    * @param msg The message you would like logged, possibly with format arguments.
     40    * @param args Optional arguments to be used in the formatted string.
     41    * @see {@link String#format(String, Object...)}
     42    * @see {@link android.util.Log#v(String, String)}
     43    */
     44   public static void v(@NonNull String tag, @Nullable String msg, @Nullable Object... args) {
     45     println(android.util.Log.VERBOSE, TAG, tag, msg, args);
     46   }
     47 
     48   /**
     49    * Log at a debug level. Debug logs should provide known-useful information to aid in
     50    * troubleshooting or evaluating flow. These logs will not generally be available on production
     51    * builds.
     52    *
     53    * @param tag An identifier to allow searching for related logs. Generally of the form
     54    *     'Class.method'
     55    * @param msg The message you would like logged, possibly with format arguments
     56    * @param args Optional arguments to be used in the formatted string
     57    * @see {@link String#format(String, Object...)}
     58    * @see {@link android.util.Log#d(String, String)}
     59    */
     60   public static void d(@NonNull String tag, @Nullable String msg, @Nullable Object... args) {
     61     println(android.util.Log.DEBUG, TAG, tag, msg, args);
     62   }
     63 
     64   /**
     65    * Log at an info level. Info logs provide information that would be useful to have on production
     66    * builds for troubleshooting.
     67    *
     68    * @param tag An identifier to allow searching for related logs. Generally of the form
     69    *     'Class.method'.
     70    * @param msg The message you would like logged, possibly with format arguments.
     71    * @param args Optional arguments to be used in the formatted string.
     72    * @see {@link String#format(String, Object...)}
     73    * @see {@link android.util.Log#i(String, String)}
     74    */
     75   public static void i(@NonNull String tag, @Nullable String msg, @Nullable Object... args) {
     76     println(android.util.Log.INFO, TAG, tag, msg, args);
     77   }
     78 
     79   /**
     80    * Log entry into a method at the info level.
     81    *
     82    * @param tag An identifier to allow searching for related logs. Generally of the form
     83    *     'Class.method'.
     84    */
     85   public static void enterBlock(String tag) {
     86     println(android.util.Log.INFO, TAG, tag, "enter");
     87   }
     88 
     89   /**
     90    * Log at a warn level. Warn logs indicate a possible error (e.g. a default switch branch was hit,
     91    * or a null object was expected to be non-null), but recovery is possible. This may be used when
     92    * it is not guaranteed that an indeterminate or bad state was entered, just that something may
     93    * have gone wrong.
     94    *
     95    * @param tag An identifier to allow searching for related logs. Generally of the form
     96    *     'Class.method'.
     97    * @param msg The message you would like logged, possibly with format arguments.
     98    * @param args Optional arguments to be used in the formatted string.
     99    * @see {@link String#format(String, Object...)}
    100    * @see {@link android.util.Log#w(String, String)}
    101    */
    102   public static void w(@NonNull String tag, @Nullable String msg, @Nullable Object... args) {
    103     println(android.util.Log.WARN, TAG, tag, msg, args);
    104   }
    105 
    106   /**
    107    * Log at an error level. Error logs are used when it is known that an error occurred and is
    108    * possibly fatal. This is used to log information that will be useful for troubleshooting a crash
    109    * or other severe condition (e.g. error codes, state values, etc.).
    110    *
    111    * @param tag An identifier to allow searching for related logs. Generally of the form
    112    *     'Class.method'.
    113    * @param msg The message you would like logged, possibly with format arguments.
    114    * @param args Optional arguments to be used in the formatted string.
    115    * @see {@link String#format(String, Object...)}
    116    * @see {@link android.util.Log#e(String, String)}
    117    */
    118   public static void e(@NonNull String tag, @Nullable String msg, @Nullable Object... args) {
    119     println(android.util.Log.ERROR, TAG, tag, msg, args);
    120   }
    121 
    122   /**
    123    * Log an exception at an error level. Error logs are used when it is known that an error occurred
    124    * and is possibly fatal. This is used to log information that will be useful for troubleshooting
    125    * a crash or other severe condition (e.g. error codes, state values, etc.).
    126    *
    127    * @param tag An identifier to allow searching for related logs. Generally of the form
    128    *     'Class.method'.
    129    * @param msg The message you would like logged.
    130    * @param throwable The exception to log.
    131    * @see {@link String#format(String, Object...)}
    132    * @see {@link android.util.Log#e(String, String)}
    133    */
    134   public static void e(@NonNull String tag, @Nullable String msg, @NonNull Throwable throwable) {
    135     if (!TextUtils.isEmpty(msg)) {
    136       println(android.util.Log.ERROR, TAG, tag, msg);
    137     }
    138     println(android.util.Log.ERROR, TAG, tag, android.util.Log.getStackTraceString(throwable));
    139   }
    140 
    141   /**
    142    * Used for log statements where we don't want to log various strings (e.g., usernames) with
    143    * default logging to avoid leaking PII in logcat.
    144    *
    145    * @return text as is if {@value #TAG}'s log level is set to DEBUG or VERBOSE or on non-release
    146    *     builds; returns a redacted version otherwise.
    147    */
    148   public static String sanitizePii(@Nullable Object object) {
    149     if (object == null) {
    150       return "null";
    151     }
    152     if (isDebugEnabled()) {
    153       return object.toString();
    154     }
    155     return "Redacted-" + object.toString().length() + "-chars";
    156   }
    157 
    158   /** Anonymizes char to prevent logging personally identifiable information. */
    159   public static char sanitizeDialPadChar(char ch) {
    160     if (isDebugEnabled()) {
    161       return ch;
    162     }
    163     if (is12Key(ch)) {
    164       return '*';
    165     }
    166     return ch;
    167   }
    168 
    169   /** Anonymizes the phone number to prevent logging personally identifiable information. */
    170   public static String sanitizePhoneNumber(@Nullable String phoneNumber) {
    171     if (isDebugEnabled()) {
    172       return phoneNumber;
    173     }
    174     if (phoneNumber == null) {
    175       return null;
    176     }
    177     StringBuilder stringBuilder = new StringBuilder(phoneNumber.length());
    178     for (char c : phoneNumber.toCharArray()) {
    179       stringBuilder.append(sanitizeDialPadChar(c));
    180     }
    181     return stringBuilder.toString();
    182   }
    183 
    184   public static boolean isVerboseEnabled() {
    185     return android.util.Log.isLoggable(TAG, android.util.Log.VERBOSE);
    186   }
    187 
    188   public static boolean isDebugEnabled() {
    189     return android.util.Log.isLoggable(TAG, android.util.Log.DEBUG);
    190   }
    191 
    192   private static boolean is12Key(char ch) {
    193     return PhoneNumberUtils.is12Key(ch);
    194   }
    195 
    196   private static void println(
    197       int level,
    198       @NonNull String tag,
    199       @NonNull String localTag,
    200       @Nullable String msg,
    201       @Nullable Object... args) {
    202     // Formatted message is computed lazily if required.
    203     String formattedMsg;
    204     // Either null is passed as a single argument or more than one argument is passed.
    205     boolean hasArgs = args == null || args.length > 0;
    206     if ((level >= android.util.Log.INFO) || android.util.Log.isLoggable(tag, level)) {
    207       formattedMsg = localTag;
    208       if (!TextUtils.isEmpty(msg)) {
    209         formattedMsg += SEPARATOR + (hasArgs ? String.format(msg, args) : msg);
    210       }
    211       android.util.Log.println(level, tag, formattedMsg);
    212     }
    213   }
    214 }
    215