package cn.hotapk.fastandrutils.utils; import android.support.annotation.NonNull; import android.util.Log; import com.google.gson.Gson; import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.Date; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * @author laijian * @version 2017/9/12 * @Copyright (C)下午4:35 , www.hotapk.cn * 日志操作类 */ public class FLogUtils { private static final String Tag = "www.hotapk.cn"; private volatile static FLogUtils fLogUtils; private String TOP_LINE = "" + "\n^^^^^^^^^^^^^less code,less bug^^^^^^^^^^^^^^\n" + " _ooOoo_\n" + " o8888888o\n" + " 88\" . \"88\n" + " (| -_- |)\n" + " O\\ = /O\n" + " ____/`---'\\____\n" + " .' \\\\| |// `.\n" + " / \\\\||| : |||// \\\n" + " / _||||| -:- |||||- \\\n" + " | | \\\\\\ - /// | |\n" + " | \\_| ''\\---/'' | |\n" + " \\ .-\\__ `-` ___/-. /\n" + " ___`. .' /--.--\\ `. . __\n" + " .\"\" '< `.___\\_<|>_/___.' >'\"\".\n" + " | | : `- \\`.;`\\ _ /`;.`/ - ` : | |\n" + " \\ \\ `-. \\_ __\\ /__ _/ .-` / /\n" + "======`-.____`-.___\\_____/___.-`____.-'======\n" + " `=---='\n" + "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + " 佛祖保佑 永无BUG\n" + "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n"; private String TOP_BORDER = "═══════════════════════════════════════════════════════════════════════════════════════════════════════════"; private String BOTTOM_BORDER = "═══════════════════════════════════════════════════════════════════════════════════════════════════════════"; private String logDir = "";//设置文件存储目录 private boolean debug = true;//是否打印log private boolean savesd = false;//是否存log到sd卡 private boolean savecrash = true;//是否存crash信息到sd卡 private int CHUNK_SIZE = 120; //设置字节数 private long logSize = 1 * 1024 * 1024L;//设置log文件大小 k private ExecutorService execu = Executors.newFixedThreadPool(1); private FLogNetServer testHttpd; private FLogUtils() { Log.e(Tag, TOP_LINE); initLogFile(); } public static FLogUtils getInstance() { if (fLogUtils == null) { synchronized (FLogUtils.class) { if (fLogUtils == null) { fLogUtils = new FLogUtils(); } } } return fLogUtils; } private void initLogFile() { logDir = FFileUtils.getRootDir() + "/FastAndrUtils_log"; FFileUtils.mkDir(logDir); } public void v(@NonNull Object objMsg) { v(Tag, objMsg); } public void d(@NonNull Object objMsg) { d(Tag, objMsg); } public void i(@NonNull Object objMsg) { i(Tag, objMsg); } public void w(@NonNull Object objMsg) { w(Tag, objMsg); } public void e(@NonNull Object objMsg) { e(Tag, objMsg); } public void v(String tag, @NonNull Object objMsg) { String stackstr = targetStackTraceMSg(); if (debug) { Log.v(tag, msgFormat(stackstr, objMsg)); } if (savesd) { saveToSd(stackstr, objMsg); } } public void d(String tag, @NonNull Object objMsg) { String stackstr = targetStackTraceMSg(); if (debug) { Log.d(tag, msgFormat(stackstr, objMsg)); } if (savesd) { saveToSd(stackstr, objMsg); } } public void i(String tag, @NonNull Object objMsg) { String stackstr = targetStackTraceMSg(); if (debug) { Log.i(tag, msgFormat(stackstr, objMsg)); } if (savesd) { saveToSd(stackstr, objMsg); } } public void w(String tag, @NonNull Object objMsg) { String stackstr = targetStackTraceMSg(); if (debug) { Log.w(tag, msgFormat(stackstr, objMsg)); } if (savesd) { saveToSd(stackstr, objMsg); } } public void e(String tag, @NonNull Object objMsg) { String stackstr = targetStackTraceMSg(); if (debug) { Log.e(tag, msgFormat(stackstr, objMsg)); } if (savesd) { saveToSd(stackstr, objMsg); } } /** * app异常时使用 * * @param msg */ public void setCrash(String msg) { String stackstr = targetStackTraceMSg(); if (debug) { Log.e("www.hotapk.cn", msgFormat(stackstr, msg)); } if (savecrash) { saveToSd(stackstr, msg); } } /** * 是否开启bebug模式 * * @param debug * @return */ public FLogUtils debug(boolean debug) { this.debug = debug; return this; } public boolean isDebug() { return debug; } /** * 是否保存到sd卡 * * @param savesd * @return */ public FLogUtils saveSD(boolean savesd) { this.savesd = savesd; return this; } /** * 是否保存crash信息 * * @param savecrash * @return */ public FLogUtils saveCrash(boolean savecrash) { this.savecrash = savecrash; return this; } /** * 设置log文件大小 * * @param logSize * @return */ public FLogUtils setLogSize(int logSize) { this.logSize = logSize; return this; } /** * 设置log文件目录 * * @param logDir * @return */ public FLogUtils setlogDir(String logDir) { if (!logDir.isEmpty()) { this.logDir = logDir; } return this; } public String getLogFileDir() { return logDir; } /** * 启动log的WebServer服务 * * @param port 端口号 */ public void startLogServer(int port) { if (testHttpd == null) { synchronized (FLogUtils.class) { if (testHttpd == null) { testHttpd = new FLogNetServer(port); } } } try { testHttpd.start(); } catch (IOException e) { e.printStackTrace(); } } /** * 关闭log的WebServer服务 */ public void stopLogServer() { if (testHttpd != null && testHttpd.isAlive()) { testHttpd.stop(); } } private String targetStackTraceMSg() { StackTraceElement targetStackTraceElement = getTargetStackTraceElement(); if (targetStackTraceElement != null) { return "at " + targetStackTraceElement.getClassName() + "." + targetStackTraceElement.getMethodName() + "(" + targetStackTraceElement.getFileName() + ":" + targetStackTraceElement.getLineNumber() + ")"; } else { return ""; } } private StackTraceElement getTargetStackTraceElement() { StackTraceElement targetStackTrace = null; boolean shouldTrace = false; StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); for (StackTraceElement stackTraceElement : stackTrace) { boolean isLogMethod = stackTraceElement.getClassName().equals(FLogUtils.class.getName()); if (shouldTrace && !isLogMethod) { targetStackTrace = stackTraceElement; break; } shouldTrace = isLogMethod; } return targetStackTrace; } private String msgFormat(String stackstr, Object objMsg) { String msg = ""; if (objMsg instanceof String) { msg = objMsg.toString(); } else { msg = new Gson().toJson(objMsg); msg = FConvertUtils.jsonFormatter(msg); } byte[] bytes = new byte[0]; try { bytes = msg.getBytes("utf-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } int length = bytes.length; String newMsg = TOP_BORDER + "\n" + FDateUtils.dateToString(new Date()) + "\n" + stackstr; if (length > CHUNK_SIZE) { int i = 0; while (i < length) { int count = Math.min(length - i, CHUNK_SIZE); String tempStr = new String(bytes, i, count); newMsg += "\n" + tempStr; i += CHUNK_SIZE; } } else { newMsg += "\n" + msg; } newMsg += "\n" + BOTTOM_BORDER; return newMsg; } private void saveToSd(final String stackstr, final Object objMsg) { execu.submit(new Runnable() { @Override public void run() { String data = FDateUtils.dateToString(new Date(), "yyyy-MM-dd"); File[] files = FFileUtils.orderByDate(new File(logDir), true); List filels = FFileUtils.filter(files, data); String filepath; if (filels.size() > 0) { Long length = FFileUtils.getLength(filels.get(0)); if (length > logSize) { int index = Integer.parseInt(filels.get(0).getName().replace("log_" + data + "_", "").replace(".html", "")); int id = index + 1; filepath = logDir + "/" + "log_" + data + "_" + id + ".html"; FFileUtils.creatFile(filepath); } else { filepath = filels.get(0).getAbsolutePath(); } } else { filepath = logDir + "/" + "log_" + data + "_1.html"; FFileUtils.creatFile(filepath); } String msg = ""; if (objMsg instanceof String) { msg = objMsg.toString(); } else { msg = FConvertUtils.jsonFormatter(new Gson().toJson(objMsg)); } FFileUtils.appendText(filepath, "
" + "\n
\n" + FDateUtils.dateToString(new Date()) + "\n
\n" + stackstr + "\n
\n" + msg.replaceAll("\n", "
") + "\n
", true); } }); } }