A simple introduction

The Android Log class can only print tag tags and Log content, which has the following disadvantages:

  1. It is not easy to filter, and it is often difficult to locate the source code of the log by looking only at the log information on the console
  2. Cannot get the thread on which the code is executing.
  3. There is no unified control over the logging switch in the Release package

LogHelper proxy encapsulates the system Log class and has the following advantages over the system Log class:

  1. Automatically print out the method, class, precise location of source code
  2. Printing thread information
  3. Provides the ability to format string parameters
  4. Support release not to print logs (via ADB instruction, control whether to print specified level logs in release package, which not only ensures security problems caused by release package log information, but also facilitates developer debugging)

Usage scenarios

Any Android project, especially a standalone library or SDK project, can filter out library or SDK-related logs through the TAG in the class to avoid confusion with the main project logs

Use the sample


// Call logs of other levels in the same way
LogHelper.i("Log content");
LogHelper.i("Md5 value: %s",md5);

Copy the code
  • Console output:
The 2020-03-12 18:18:59. 881, 32462-32462 / com. Xmexe. Exedevv3 I/EXE_TAG: [1] TestClass.testMethod: 2020-03-12 18:18:59.881 32462-32462/com.xmexe. exeDevv3 I/EXE_TAG: [24521] TestClass. TestMethod2: md5 value is: XXXXXXXXCopy the code
  • instructions

Logs are displayed on the console in the format of [Thread ID] Class name. Method: Log content

Note: The class name may also be the class name of the inner class

Switch control

From the android.util.Log source, Log levels are in the following order: VERBOSE

By default, all logs are printed in the console, but LogHelper restricts VERBOSE and DEBUG logs. By default, the release package is not printed, and only takes effect with the following ADB command and a restart of the application:

Adb -d shell setprop log.tag.EXE_TAG VERBOSE adb -d shell setprop log.tag.EXE_TAG VERBOSE adb -d shell setprop log.tagCopy the code

code

LogHelper.java

import android.arch.core.BuildConfig;
import android.util.Log;

import java.util.Locale;
import java.util.regex.Pattern;

/** * Formatted Logging helper class. */
public class LogHelper
{
    private static String TAG = "EXE_TAG";
    private static final boolean DEBUG = Log.isLoggable(TAG, Log.VERBOSE) ||
            "debug".equalsIgnoreCase(BuildConfig.BUILD_TYPE);// The debug package does not need to be restricted
    
    public static void v(Object arg)
    {
        if (DEBUG) // Restrict VERBOSE logs
        {
            String message = arg == null ? "null" : arg.toString();
            Log.v(TAG, buildMessage("%s", message)); }}public static void v(String format, Object... args)
    {
        if (DEBUG)
            Log.v(TAG, buildMessage(format, args));
    }
    
    public static void d(Object arg)
    {
        if (DEBUG) // Restrict DEBUG level logs
        {
            String message = arg == null ? "null" : arg.toString();
            Log.d(TAG, buildMessage("%s", message)); }}public static void d(String format, Object... args)
    {
        if (DEBUG)
            Log.d(TAG, buildMessage(format, args));
    }
    
    public static void e(Object arg)
    {
        String message = arg == null ? "null" : arg.toString();
        Log.e(TAG, buildMessage("%s", message));
    }
    
    public static void e(String format, Object... args)
    {
        Log.e(TAG, buildMessage(format, args));
    }
    
    public static void i(String format, Object... args)
    {
        Log.i(TAG, buildMessage(format, args));
    }
    
    public static void e(Throwable tr, String format, Object... args)
    {
        Log.e(TAG, buildMessage(format, args), tr);
    }
    
    public static void wtf(String format, Object... args)
    {
        Log.wtf(TAG, buildMessage(format, args));
    }
    
    public static void wtf(Throwable tr, String format, Object... args)
    {
        Log.wtf(TAG, buildMessage(format, args), tr);
    }
    
    /** * Formats the caller's provided message and prepends useful info like * calling thread ID and method name. */
    private static String buildMessage(String format, Object... args)
    {
        String msg = (args == null)? format : String.format(Locale.US, format, args); StackTraceElement[] trace =new Throwable().fillInStackTrace().getStackTrace();
        
        String caller = "<unknown>";
        for (int i = 2; i < trace.length; i++) { Class<? > clazz = trace[i].getClass();if(! clazz.equals(LogHelper.class)) { String callingClass = trace[i].getClassName(); callingClass = callingClass.substring(callingClass.lastIndexOf('. ') + 1);
                String endWords = callingClass.substring(callingClass.lastIndexOf('$') + 1);
                if(! isNumeric(endWords)) { callingClass = endWords; } caller = callingClass +"." + trace[i].getMethodName();
                break; }}return String.format(Locale.US, "[%d] %s: %s",
                Thread.currentThread().getId(), caller, msg);
    }
    
    private static boolean isNumeric(String str)
    {
        Pattern pattern = Pattern.compile("[0-9] +");
        returnpattern.matcher(str).matches(); }}Copy the code

Note:

INFO and above logs are printed by default, that is, log.isloggable (TAG, log.info) is true by default. Log.isLoggable(TAG, log.verbose) and log. isLoggable(TAG, log.debug) are false by default and can be enabled with adb -d shell setprop.