Android Logger便捷使用

build(app)的配置

 //初次新建记得添加
    // {"kind":"error","text":"Invoke-customs are only supported starting with Android O
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
  buildTypes {
        def date = new Date().format("yyyy-MM-dd-hh-mm-ss")
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            buildConfigField("String", "apkBuildTime", "\"${date}\"")
            buildConfigField "boolean", "IS_DEBUG", "false"

        }
        debug {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            //设置BuildConfig 生成IS_DEBUG、apkBuildTime等变量
            buildConfigField("String", "apkBuildTime", "\"${date}\"")
            buildConfigField "boolean", "IS_DEBUG", "true"
        }
    }
  // timber
    implementation 'com.jakewharton.timber:timber:4.1.1'

LocalApplication进行初始化


import android.app.Application;
import android.util.Log;

import example.com.summary.util.Logger;


public class LocalApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        _initConfig();
    }

    private void _initConfig() {
        if (BuildConfig.IS_DEBUG) {
            Logger.builder()
                    .setLogPriority(Log.DEBUG)
                    .isShowThreadInfo(true)
                    .initialize(true);
        } else {
            Logger.builder()
                    .setLogPriority(Log.ASSERT)
                    .isShowThreadInfo(true)
                    .initialize(false);
        }
        Logger.d(Logger._TJ, "on Appliction Create set Logger Iml");

    }
}


 import android.support.annotation.CheckResult;
import android.support.annotation.IntDef;
import android.support.annotation.LongDef;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.StringReader;
import java.io.StringWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

import javax.xml.transform.OutputKeys;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import timber.log.Timber;


 
public class Logger {

    /************************************* - TAG - ****************************************/
    //TAG最大标记为63,最多左移63为,因为long是8字节 64位
    public static final long BASE_ONE = 1L; //

    /** 1~15属于公共资源 */
    public static final long _PUBLIC = Short.MAX_VALUE; //打印公共资源的全部log
    public static final long _NET = BASE_ONE << 1; //网络请求
    public static final long _READ_ASSETS = BASE_ONE << 2; //网络请求

    public static final long _FOCUSE = BASE_ONE << 15; // 焦点变化
    /** 建晶 16~31*/
    public static final long _TJ = _PUBLIC << 16;  
    public static final long _TJ_ListPresenter = BASE_ONE << 16; //
    public static final long _TJ_ChannelPresenter = BASE_ONE << 17; //
    /** 佳南 32~47*/
    public static final long _JN = _TJ << 16; 
    public static final long _TM_SplashActivity = BASE_ONE << 32;  

    /** 记得把新建的TAG注入到下面的对应栏目中 TAG的取值只能取如下几种*/
    @Retention(RetentionPolicy.SOURCE)
    @LongDef({
            /**公共资源*/_PUBLIC,_NET,_READ_ASSETS,
             _TJ, _TJ_ListPresenter,_TJ_ChannelPresenter,
             _JN,_TM_SplashActivity
    })
    @interface LogType {}

    private static final long MY_LOG = _FOCUSE|_TJ|_JN;
    /* MY_LOG 取值事例:
    private static final long MY_LOG = _TJ;     
    private static final long MY_LOG = _TJ | _NET;   
    private static final long MY_LOG = _TJ_ListPresenter | _TM_SplashActivity;  
    */


    /************************************* - LOG - ****************************************/

    /**
     * LogLevel的取值只能取如下几种
     */
    @Retention(RetentionPolicy.SOURCE)
    @IntDef({Log.VERBOSE, Log.DEBUG, Log.INFO, Log.WARN, Log.ERROR, Log.ASSERT})
    @interface LogLevel {}

    protected Logger() {}

    public static Timber.Tree t(String tag) {
        return Timber.tag(tag);
    }

    /**eg:Logger.v(Logger._NET,"name = %s", name);*/
    public static void v(@LogType long log, String message, Object... args) {
        if ((log & MY_LOG) != 0 ){
            Timber.v(handleNullMsg(message), args);
        }
    }
    /**eg:Logger.v(Logger._NET,"name = %s", name);*/
    public static void d(@LogType long log, String message, Object... args) {
        if ((log & MY_LOG) != 0 ) {
            Timber.d(handleNullMsg(message), args);
        }
    }
    /**eg:Logger.i(Logger._NET,"name = %s", name);*/
    public static void i(@LogType long log, String message, Object... args) {
        if ((log & MY_LOG) != 0 ){
            Timber.i(handleNullMsg(message), args);
        }
    }
    /**eg:Logger.i("name = %s", name); 所有人可见*/
    public static void i(String message, Object... args) {
        Timber.i(handleNullMsg(message), args);
    }
    /**eg:Logger.w("name = %s", name); 所有人可见*/
    public static void w(String message, Object... args) {
        Timber.w(handleNullMsg(message), args);
    }
    /**eg:Logger.w(throwable,"name = %s", name); 所有人可见*/
    public static void w(Throwable throwable, String message, Object... args) {
        Timber.w(throwable, handleNullMsg(message), args);
    }
    /**eg:Logger.e("name = %s", name); 所有人可见*/
    public static void e(String message, Object... args) {
        Timber.e(handleNullMsg(message), args);
    }
    /**eg:Logger.e(throwable); 所有人可见*/
    public static void e(Throwable throwable) {
        Timber.e(throwable, "");
    }
    /**eg:Logger.e(throwable,"name = %s", name); 所有人可见*/
    public static void e(Throwable throwable, String message, Object... args) {
        Timber.e(throwable, handleNullMsg(message), args);
    }
    /**eg:Logger.wft(Logger._NET,"name = %s", name);*/
    public static void wtf(@LogType long log, String message, Object... args) {
        if ((log & MY_LOG) != 0 ) {
            Timber.wtf(handleNullMsg(message), args);
        }
    }
    /**eg:Logger.wft(Logger._NET,throwable,"name = %s", name);*/
    public static void wtf(@LogType long log, Throwable throwable, String message, Object... args) {
        if ((log & MY_LOG) != 0 ) {
            Timber.wtf(throwable, handleNullMsg(message), args);
        }
    }
    /**eg:Logger.json(Logger._NET,json);*/
    public static void json(@LogType long log, String json) {
        if ((log & MY_LOG) != 0 ) {
            Timber.d(XmlJsonParser.json(json));
        }
    }
    /**eg:Logger.xml(Logger._NET,xml);*/
    public static void xml(@LogType long log, String xml) {
        if ((log & MY_LOG) != 0 ) {
            Timber.d(XmlJsonParser.xml(xml));
        }
    }

    public static void object(@LogType long log, Object object) {
        if ((log & MY_LOG) != 0 ) {
            Timber.d(ObjParser.parseObj(object));
        }
    }

    /**
     * Timber will swallow message if it's null and there's no throwable.
     */
    @NonNull
    private static String handleNullMsg(String message) {
        if (message == null) {
            message = "null";
        }
        return message;
    }

    public static Builder builder() {
        return new Builder();
    }

    /************************************* - Builder - ****************************************/
    /**
     * 通过Builder初始化Timber
     * Builder is a wrapper of {@link Timber}
     * @author
     */
    public static final class Builder {

        int methodOffset = 0;
        boolean showMethodLink = true;
        boolean showThreadInfo = false;
        int priority = Log.DEBUG;

        public Builder setMethodOffset(int methodOffset) {
            this.methodOffset = methodOffset;
            return this;
        }

        public Builder isShowThreadInfo(boolean showThreadInfo) {
            this.showThreadInfo = showThreadInfo;
            return this;
        }

        public Builder isShowMethodLink(boolean showMethodLink) {
            this.showMethodLink = showMethodLink;
            return this;
        }

        /**
         * @param priority one of
         * {@link Log#DEBUG}
         */
        public Builder setLogPriority(@LogLevel int priority) {
            this.priority = priority;
            return this;
        }

        public void initialize(boolean isMustLog) {
            if (isMustLog) priority = Log.VERBOSE;
            Timber.plant(new MyDebugTree(this));
        }
    }

    /************************************* - DebugTree - ****************************************/
    private static final class MyDebugTree extends Timber.DebugTree{

        private int methodOffset = 0;
        private boolean showMethodLink = true;
        private boolean showThreadInfo = false;
        private int priority = Log.DEBUG;

        private static final int STACK_OFFSET = 8;

        private static final String BOTTOM_BORDER = "╚═══════════════════════════";

        private static final String PREFIX_BORDER = "║";

        /**
         * 因为如果设置了tag,那么会在timber中多走一个方法,方法栈会发生变化,造成不准确的情况。
         */
        private boolean isCustomTag = true;

        private StringBuilder sb = new StringBuilder();


        private final String PROPERTY = System.getProperty("line.separator");

        public MyDebugTree(Builder builder) {
            methodOffset = builder.methodOffset;
            showMethodLink = builder.showMethodLink;
            showThreadInfo = builder.showThreadInfo;
            priority = builder.priority;
        }

        /**
         * rule for auto tag
         */
        @Override
        protected String createStackElementTag(StackTraceElement ignored) {
            isCustomTag = false;
            int offset = STACK_OFFSET + methodOffset - 1;
            return super.createStackElementTag(new Throwable().getStackTrace()[offset]);
        }

        protected void log(int priority, String tag, @NonNull String message, Throwable ignored) {
            String[] lines = message.split(PROPERTY);
            StringBuilder buf = new StringBuilder();
            for (int i = 0; i < lines.length; i++) {
                buf.append(PREFIX_BORDER + lines[i] + "\n");
            }

            String relLog = String.format("%s\n%s%s", getTail(), buf.toString(), BOTTOM_BORDER);

            super.log((priority), tag, relLog, null);

            isCustomTag = true;

            //            for (int i = 0, length = lines.length; i < length; i++) {
            //                if (i == length - 1) {
            //                    // last line
            //                    super.log(priority, tag, PREFIX_BORDER + lines[i] + getTail(), null);
            //                } else {
            //                    super.log((priority), tag, PREFIX_BORDER + lines[i], null);
            //                }
            //            }
            //            // Finally print bottom line
            //            super.log((priority), tag, BOTTOM_BORDER, null);

            //            isCustomTag = true;
        }

        /**
         * ==> onCreate(MainActivity.java:827) Thread:main
         */
        private String getTail() {
            if (!showMethodLink) {
                return "";
            }

            int index = STACK_OFFSET + methodOffset + 1;
            if (isCustomTag) {
                index -= 2;
            }
            final StackTraceElement stack = Thread.currentThread().getStackTrace()[index];

            if (sb.length() < 0) {
                sb = new StringBuilder();
            } else {
                sb.setLength(0);
            }

            sb.append(String.format(" ==>  Method:  %s(%s:%s)",
                    stack.getMethodName(),
                    stack.getFileName(),
                    stack.getLineNumber()));

            if (showThreadInfo) {
                sb.append(" Thread: ").append(Thread.currentThread().getName()); // Thread:main
            }
            return sb.toString();
        }

        /**
         * 根据级别显示log
         */
        @Override
        protected boolean isLoggable(int priority) {
            return priority >= this.priority;
        }
    }
    /*----------------------------------- END --------------------------------------------------*/

                                   /*以下是工具类-不对外提供*/

    /************************************* - XmlJsonParser - ****************************************/
    private static final class XmlJsonParser {
        /**
         * It is used for json pretty print
         */
        private static final int JSON_INDENT = 4;

        @CheckResult
        public static String xml(String xml) {
            if (TextUtils.isEmpty(xml)) {
                return "Empty/Null xml content.(This msg from logger)";
            }
            try {
                Source xmlInput = new StreamSource(new StringReader(xml));
                StreamResult xmlOutput = new StreamResult(new StringWriter());
                Transformer transformer = TransformerFactory.newInstance().newTransformer();
                transformer.setOutputProperty(OutputKeys.INDENT, "yes");
                transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
                transformer.transform(xmlInput, xmlOutput);
                return xmlOutput.getWriter().toString().replaceFirst(">", ">\n");
            } catch (TransformerException e) {
                return e.getCause().getMessage() + "\n" + xml;
            }
        }

        @CheckResult
        public static String json(@Nullable String json) {
            if (TextUtils.isEmpty(json)) {
                return "Empty/Null json content.(This msg from logger)";
            }
            try {
                if (json.startsWith("{")) {
                    return new JSONObject(json).toString(JSON_INDENT);
                } else if (json.startsWith("[")) {
                    return new JSONArray(json).toString(JSON_INDENT);
                }
            } catch (JSONException e) {
                return e.getCause().getMessage() + "\n" + json;
            }
            return "Log error!.(This msg from logger)";
        }
    }

    /************************************* - ObjParser - ****************************************/
    private static final class ObjParser {
        // 基本数据类型
        private final static String[] TYPES = {"int", "java.lang.String", "boolean", "char",
                "float", "double", "long", "short", "byte"};

        public static String parseObj(Object object) {
            if (object == null) {
                return "null";
            }
            final String simpleName = object.getClass().getSimpleName();
            if (object.getClass().isArray()) {
                StringBuilder msg = new StringBuilder("Temporarily not support more than two dimensional Array!");
                int dim = ArrayParser.getArrayDimension(object);
                switch (dim) {
                    case 1:
                        Pair pair = ArrayParser.arrayToString(object);
                        msg = new StringBuilder(simpleName.replace("[]", "[" + pair.first + "] {\n"));
                        msg.append(pair.second).append("\n");
                        break;
                    case 2:
                        Pair pair1 = ArrayParser.arrayToObject(object);
                        Pair pair2 = (Pair) pair1.first;
                        msg = new StringBuilder(simpleName.replace("[][]", "[" + pair2.first + "][" + pair2.second + "] {\n"));
                        msg.append(pair1.second).append("\n");
                        break;
                    default:
                        break;
                }
                return msg + "}";
            } else if (object instanceof Collection) {
                Collection collection = (Collection) object;
                String msg = "%s size = %d [\n";
                msg = String.format(Locale.ENGLISH, msg, simpleName, collection.size());
                if (!collection.isEmpty()) {
                    Iterator iterator = collection.iterator();
                    int flag = 0;
                    while (iterator.hasNext()) {
                        String itemString = "[%d]:%s%s";
                        Object item = iterator.next();
                        msg += String.format(Locale.ENGLISH, itemString,
                                flag,
                                objectToString(item),
                                flag++ < collection.size() - 1 ? ",\n" : "\n");
                    }
                }
                return msg + "\n]";
            } else if (object instanceof Map) {
                String msg = simpleName + " {\n";
                Map map = (Map) object;
                Set keys = map.keySet();
                for (Object key : keys) {
                    String itemString = "[%s -> %s]\n";
                    Object value = map.get(key);
                    msg += String.format(itemString, objectToString(key), objectToString(value));
                }
                return msg + "}";
            } else {
                return objectToString(object);
            }
        }
        /**
         * 将对象转化为String
         */
        protected static <T> String objectToString(T object) {
            if (object == null) {
                return "Object{object is null}";
            }
            if (object.toString().startsWith(object.getClass().getName() + "@")) {
                StringBuilder builder = new StringBuilder(object.getClass().getSimpleName() + "{");
                Field[] fields = object.getClass().getDeclaredFields();
                for (Field field : fields) {
                    field.setAccessible(true);
                    boolean flag = false;
                    for (String type : TYPES) {
                        if (field.getType().getName().equalsIgnoreCase(type)) {
                            flag = true;
                            Object value = null;
                            try {
                                value = field.get(object);
                            } catch (IllegalAccessException e) {
                                value = e;
                            } finally {
                                builder.append(String.format("%s=%s, ", field.getName(),
                                        value == null ? "null" : value.toString()));
                            }
                        }
                    }
                    if (!flag) {
                        builder.append(String.format("%s=%s, ", field.getName(), "Object"));
                    }
                }
                return builder.replace(builder.length() - 2, builder.length() - 1, "}").toString();
            } else {
                return object.toString();
            }
        }
    }

    /************************************* - ArrayParser - ****************************************/
    private static final class ArrayParser {
        /**
         * 获取数组的纬度
         */
        public static int getArrayDimension(Object objects) {
            int dim = 0;
            for (int i = 0; i < objects.toString().length(); ++i) {
                if (objects.toString().charAt(i) == '[') {
                    ++dim;
                } else {
                    break;
                }
            }
            return dim;
        }

        public static Pair<Pair<Integer, Integer>, String> arrayToObject(Object object) {
            StringBuilder builder = new StringBuilder();
            int cross, vertical;
            if (object instanceof int[][]) {
                int[][] ints = (int[][]) object;
                cross = ints.length;
                vertical = cross == 0 ? 0 : ints[0].length;
                for (int[] ints1 : ints) {
                    builder.append(arrayToString(ints1).second).append("\n");
                }
            } else if (object instanceof byte[][]) {
                byte[][] ints = (byte[][]) object;
                cross = ints.length;
                vertical = cross == 0 ? 0 : ints[0].length;
                for (byte[] ints1 : ints) {
                    builder.append(arrayToString(ints1).second).append("\n");
                }
            } else if (object instanceof short[][]) {
                short[][] ints = (short[][]) object;
                cross = ints.length;
                vertical = cross == 0 ? 0 : ints[0].length;
                for (short[] ints1 : ints) {
                    builder.append(arrayToString(ints1).second).append("\n");
                }
            } else if (object instanceof long[][]) {
                long[][] ints = (long[][]) object;
                cross = ints.length;
                vertical = cross == 0 ? 0 : ints[0].length;
                for (long[] ints1 : ints) {
                    builder.append(arrayToString(ints1).second).append("\n");
                }
            } else if (object instanceof float[][]) {
                float[][] ints = (float[][]) object;
                cross = ints.length;
                vertical = cross == 0 ? 0 : ints[0].length;
                for (float[] ints1 : ints) {
                    builder.append(arrayToString(ints1).second).append("\n");
                }
            } else if (object instanceof double[][]) {
                double[][] ints = (double[][]) object;
                cross = ints.length;
                vertical = cross == 0 ? 0 : ints[0].length;
                for (double[] ints1 : ints) {
                    builder.append(arrayToString(ints1).second).append("\n");
                }
            } else if (object instanceof boolean[][]) {
                boolean[][] ints = (boolean[][]) object;
                cross = ints.length;
                vertical = cross == 0 ? 0 : ints[0].length;
                for (boolean[] ints1 : ints) {
                    builder.append(arrayToString(ints1).second).append("\n");
                }
            } else if (object instanceof char[][]) {
                char[][] ints = (char[][]) object;
                cross = ints.length;
                vertical = cross == 0 ? 0 : ints[0].length;
                for (char[] ints1 : ints) {
                    builder.append(arrayToString(ints1).second).append("\n");
                }
            } else {
                Object[][] objects = (Object[][]) object;
                cross = objects.length;
                vertical = cross == 0 ? 0 : objects[0].length;
                for (Object[] objects1 : objects) {
                    builder.append(arrayToString(objects1).second).append("\n");
                }
            }
            return Pair.create(Pair.create(cross, vertical), builder.toString());
        }

        /**
         * 数组转化为字符串
         */
        public static Pair arrayToString(Object object) {
            StringBuilder builder = new StringBuilder("[");
            int length;
            if (object instanceof int[]) {
                int[] ints = (int[]) object;
                length = ints.length;
                for (int i : ints) {
                    builder.append(i).append(",\t");
                }
            } else if (object instanceof byte[]) {
                byte[] bytes = (byte[]) object;
                length = bytes.length;
                for (byte item : bytes) {
                    builder.append(item).append(",\t");
                }
            } else if (object instanceof short[]) {
                short[] shorts = (short[]) object;
                length = shorts.length;
                for (short item : shorts) {
                    builder.append(item).append(",\t");
                }
            } else if (object instanceof long[]) {
                long[] longs = (long[]) object;
                length = longs.length;
                for (long item : longs) {
                    builder.append(item).append(",\t");
                }
            } else if (object instanceof float[]) {
                float[] floats = (float[]) object;
                length = floats.length;
                for (float item : floats) {
                    builder.append(item).append(",\t");
                }
            } else if (object instanceof double[]) {
                double[] doubles = (double[]) object;
                length = doubles.length;
                for (double item : doubles) {
                    builder.append(item).append(",\t");
                }
            } else if (object instanceof boolean[]) {
                boolean[] booleans = (boolean[]) object;
                length = booleans.length;
                for (boolean item : booleans) {
                    builder.append(item).append(",\t");
                }
            } else if (object instanceof char[]) {
                char[] chars = (char[]) object;
                length = chars.length;
                for (char item : chars) {
                    builder.append(item).append(",\t");
                }
            } else {
                Object[] objects = (Object[]) object;
                length = objects.length;
                for (Object item : objects) {
                    builder.append(ObjParser.objectToString(item)).append(",\t");
                }
            }
            return Pair.create(length, builder.replace(builder.length() - 2, builder.length(), "]").toString());
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值