AndroidUtil - 极简日志工具类 - 异步缓存

import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.util.Log;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.ConcurrentModificationException;
import java.util.Locale;

public class XLogUtil {

    private static final String TAG = "XLogUtil";

    public static final String APP_VERSION = "";

    private static final String LOGPRE_SPLIT = "|";
    private static final String LOGPRE_APPVER = APP_VERSION + LOGPRE_SPLIT;
    private static final String LOGPRE_TIME_FORMAT = "yyyyMMdd-HH:mm:ss:SSS" + LOGPRE_SPLIT;

    /* 每次打印字符串的最大长度 */
    private static final int LOGCAT_MESSAGE_MAX_LENTH = 4000;

    /* 限制每个log文件最大3M */
    private static final int MAX_LOGFILE_LENGTH = 1 * 1024 * 1024;

    /* 限制log文件个数 */
    private static final int MAX_LOGFILE_NUMBER = 5;

    public static final String APP_NAME = "ahisense";
    private static String LOGFILE_PATH = null;
    private static final String FILECONTENT_ENCODE = "UTF-8";

    /* logfile缓存大小 128k */
    private static final long LOGFILE_BUFFER_MAX = 128 * 1024;

    /* 6sec */
    private static final long LOGFILE_DELAY = 6 * 1000;
    /* 5mins */
    private static final long LOGFILE_THREAD_EXIT_DELAY = 5 * 60 * 1000;

    /* 处理消息 */
    private static final int MSG_SAVE_LOG_FILE = 1;
    private static final int MSG_LOG_FILE_THREAD_EXIT = 2;

    /* 内存泄露检测开关 */
    public static final boolean DEBUG_MEMORYWATCHER = true;
    /* STRICT_MODE开关 */
    public static final boolean DEBUG_STRICT_MODE = false;

    private static StringBuilder logFileBuffer;
    private static Handler logFileHandler;

    private LogUtil() {
    }

    /**
     * 打印debug级别的log
     *
     * @param tag
     * @param msg
     */
    public static void d(String tag, Object... msg) {
        String text = buildMessage(msg, LOGPRE_APPVER);
        if (text != null) {
            int len = text.length();
            if (len <= LOGCAT_MESSAGE_MAX_LENTH) {
                Log.d(tag, text);
            } else {
                do {
                    Log.d(tag, text.substring(0, LOGCAT_MESSAGE_MAX_LENTH));
                    text = text.substring(LOGCAT_MESSAGE_MAX_LENTH);
                    len = text.length();
                } while (len > LOGCAT_MESSAGE_MAX_LENTH);
                if (len > 0) {
                    Log.d(tag, text);
                }
            }
        }

        f(tag, msg);
    }

    /**
     * 打印debug级别的log
     *
     * @param tag
     * @param msg
     */
    public static void d(boolean isSaveLog, String tag, Object... msg) {
        String text = buildMessage(msg, LOGPRE_APPVER);
        if (text != null) {
            int len = text.length();
            if (len <= LOGCAT_MESSAGE_MAX_LENTH) {
                Log.d(tag, text);
            } else {
                do {
                    Log.d(tag, text.substring(0, LOGCAT_MESSAGE_MAX_LENTH));
                    text = text.substring(LOGCAT_MESSAGE_MAX_LENTH);
                    len = text.length();
                } while (len > LOGCAT_MESSAGE_MAX_LENTH);
                if (len > 0) {
                    Log.d(tag, text);
                }
            }
        }

        if (isSaveLog) {
            f(tag, msg);
        }
    }

    /**
     * 打印warn级别的log
     *
     * @param tag
     * @param msg
     */
    public static void w(String tag, Object... msg) {
        String text = buildMessage(msg, LOGPRE_APPVER);
        if (text != null) {
            int len = text.length();
            if (len <= LOGCAT_MESSAGE_MAX_LENTH) {
                Log.w(tag, text);
            } else {
                do {
                    Log.w(tag, text.substring(0, LOGCAT_MESSAGE_MAX_LENTH));
                    text = text.substring(LOGCAT_MESSAGE_MAX_LENTH);
                    len = text.length();
                } while (len > LOGCAT_MESSAGE_MAX_LENTH);
                if (len > 0) {
                    Log.w(tag, text);
                }
            }
        }
    }

    /**
     * 打印error级别的log
     *
     * @param tag
     * @param msg
     */
    public static void e(String tag, Object... msg) {
        String text = buildMessage(msg, LOGPRE_APPVER);
        if (text != null) {
            int len = text.length();
            if (len <= LOGCAT_MESSAGE_MAX_LENTH) {
                Log.e(tag, text);
            } else {
                do {
                    Log.e(tag, text.substring(0, LOGCAT_MESSAGE_MAX_LENTH));
                    text = text.substring(LOGCAT_MESSAGE_MAX_LENTH);
                    len = text.length();
                } while (len > LOGCAT_MESSAGE_MAX_LENTH);
                if (len > 0) {
                    Log.e(tag, text);
                }
            }
        }

        f(tag, msg);
    }

    /**
     * 打印error级别的log
     *
     * @param tag
     * @param msg
     */
    public static void e(boolean isSaveLog, String tag, Object... msg) {
        String text = buildMessage(msg, LOGPRE_APPVER);
        if (text != null) {
            int len = text.length();
            if (len <= LOGCAT_MESSAGE_MAX_LENTH) {
                Log.e(tag, text);
            } else {
                do {
                    Log.e(tag, text.substring(0, LOGCAT_MESSAGE_MAX_LENTH));
                    text = text.substring(LOGCAT_MESSAGE_MAX_LENTH);
                    len = text.length();
                } while (len > LOGCAT_MESSAGE_MAX_LENTH);
                if (len > 0) {
                    Log.e(tag, text);
                }
            }
        }

        if (isSaveLog) {
            f(tag, msg);
        }
    }

    /**
     * 打印敏感信息,用户信息级别的log
     *
     * @param tag 标签
     * @param msg 日志内容
     */
    public static void s(boolean isSaveLog, String tag, Object... msg) {
        String text = buildMessage(msg, LOGPRE_APPVER);
        if (text != null) {
            int len = text.length();
            if (len <= LOGCAT_MESSAGE_MAX_LENTH) {
                Log.d(tag, text);
            } else {
                do {
                    Log.d(tag, text.substring(0, LOGCAT_MESSAGE_MAX_LENTH));
                    text = text.substring(LOGCAT_MESSAGE_MAX_LENTH);
                    len = text.length();
                } while (len > LOGCAT_MESSAGE_MAX_LENTH);
                if (len > 0) {
                    Log.d(tag, text);
                }
            }
        }

        if (isSaveLog) {
            f(tag, msg);
        }
    }

    /**
     * 保存log到文件
     *
     * @param tag
     * @param msg
     */
    public static void f(String tag, Object... msg) {
        String text = buildMessage(msg, getTimePrefix(), tag + LOGPRE_SPLIT, LOGPRE_APPVER);
        if (text != null) {
            putLogFileBuffer(text);
        }
    }


    private static String getTimePrefix() {
        SimpleDateFormat df = new SimpleDateFormat(LOGPRE_TIME_FORMAT, Locale.ENGLISH);
        return df.format(System.currentTimeMillis());
    }

    private static String buildMessage(Object[] msg, String... prefix) {
        if (msg == null || msg.length == 0) {
            return null;
        }

        StringBuilder sb = new StringBuilder();
        try {
            if (prefix != null) {
                for (String p : prefix) {
                    sb.append(p);
                }
            }
            for (Object m : msg) {
                sb.append(m != null ? m : "");
            }
        } catch (ConcurrentModificationException e) {
            Log.e(TAG, e.getMessage());
            return "";
        }
        return sb.toString();
    }


    /**
     * 向文件中写文本内容
     *
     * @param file
     * @param content
     * @param append
     */
    public static void writeFile(File file, String content, boolean append) {
        if (null == file || null == content) {
            return;
        }
        byte[] bytes = null;
        try {
            bytes = content.getBytes(FILECONTENT_ENCODE);
        } catch (UnsupportedEncodingException e) {
            w(TAG, "write file failed: ", e.getMessage());
        }
        if (bytes != null) {
            writeFile(file, bytes, append);
        }
    }

    /**
     * 向文件中写二进制内容
     *
     * @param file
     * @param content
     * @param append
     */
    public static void writeFile(File file, byte[] content, boolean append) {
        FileOutputStream out = null;
        try {
            out = new FileOutputStream(file, append);
            out.write(content);
            out.flush();
        } catch (IOException e) {
            w(TAG, "write file failed: ", e.getMessage());
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                }
            }
        }
    }

    private static File getLogFile() {
        if (LOGFILE_PATH == null) {
            try {
                String sdcard = Environment.getExternalStorageDirectory().getCanonicalPath();
                LOGFILE_PATH = sdcard + "/" + APP_NAME + "/";
            } catch (IOException e) {
                Log.e(TAG, "getExternalStorageDirectory failed!");
            }
        }

        File path = new File(LOGFILE_PATH);
        if (!path.exists()) {
            if (!path.mkdirs()) {
                Log.e(TAG, "create log directory failed!");
                return null;
            }
        }

        File file = new File(LOGFILE_PATH + "log.0");
        if (file.exists() && file.length() > MAX_LOGFILE_LENGTH) {
            File tmp = new File(LOGFILE_PATH + "log." + (MAX_LOGFILE_NUMBER - 1));
            if (tmp.exists()) {
                if (!tmp.delete()) {
                    Log.e(TAG, "delete log file failed");
                    return null;
                }
            }
            for (int i = MAX_LOGFILE_NUMBER - 2; i >= 0; i--) {
                tmp = new File(LOGFILE_PATH + "log." + i);
                if (tmp.exists()) {
                    if (!tmp.renameTo(new File(LOGFILE_PATH + "log." + (i + 1)))) {
                        Log.e(TAG, "rename log file failed");
                        return null;
                    }
                }
            }
        }
        return file;
    }


    private static void putLogFileBuffer(String text) {
        synchronized (LogUtil.class) {
            if (logFileBuffer == null) {
                logFileBuffer = new StringBuilder(text);
            } else {
                logFileBuffer.append(text);
            }
            logFileBuffer.append("\n");

            boolean saveNow = logFileBuffer.length() >= LOGFILE_BUFFER_MAX;
            // schedule log file buffer saving
            if (logFileHandler == null) {
                HandlerThread thread = new HandlerThread("logfile_thread");
                thread.start();
                logFileHandler = new LogFileHandler(thread.getLooper());
                logFileHandler.sendEmptyMessageDelayed(MSG_SAVE_LOG_FILE, saveNow ? 0 : LOGFILE_DELAY);
            } else {
                logFileHandler.removeMessages(MSG_LOG_FILE_THREAD_EXIT);
                if (saveNow) {
                    logFileHandler.removeMessages(MSG_SAVE_LOG_FILE);
                    logFileHandler.sendEmptyMessage(MSG_SAVE_LOG_FILE);
                } else if (!logFileHandler.hasMessages(MSG_SAVE_LOG_FILE)) {
                    logFileHandler.sendEmptyMessageDelayed(MSG_SAVE_LOG_FILE, LOGFILE_DELAY);
                }
            }
        }
    }

    private static void flushLogFileBufferLocked() {
        synchronized (LogUtil.class) {
            if (logFileBuffer == null) {
                return;
            }

            String text = logFileBuffer.toString();
            logFileBuffer = null;
            File file = getLogFile();
            if (file != null) {
                writeFile(file, text, true);
            } else {
                w(TAG, "get log file failed.");
            }
        }
    }

    private static class LogFileHandler extends Handler {

        public LogFileHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            if (null == msg) {
                return;
            }
            switch (msg.what) {
                case MSG_SAVE_LOG_FILE:
                    synchronized (LogUtil.class) {
                        logFileHandler.removeMessages(MSG_SAVE_LOG_FILE);
                        flushLogFileBufferLocked();
                        logFileHandler.sendEmptyMessageDelayed(MSG_LOG_FILE_THREAD_EXIT, LOGFILE_THREAD_EXIT_DELAY);
                    }
                    break;

                case MSG_LOG_FILE_THREAD_EXIT:
                    synchronized (LogUtil.class) {
                        if (!logFileHandler.hasMessages(MSG_SAVE_LOG_FILE)) {
                            logFileHandler.getLooper().quit();
                            logFileHandler = null;
                        }
                    }
                    break;

                default:
                    break;
            }
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值