package tws.component.log.impl;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.util.Calendar;
import tws.component.log.TwsLog;
import tws.component.log.TwsLogBaseConfig;
import tws.component.log.TwsLogReceiver;
import tws.component.log.upload.TwsLogUploadImpl;
import android.content.Context;
import android.content.IntentFilter;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
/**
* Title: TwsLogImpl Package: tws.component.log.impl Author: interzhang Date:
* 14-3-17 下午3:44 Version: v1.0
*/
public class TwsLogImpl {
private TwsLogBaseConfig mConfig = null;
private HandlerThread mLogThread = null;
private TwsLogHandler mLogHandler = null;
// private TwsTraceParams mTraceParams = null;
// private boolean mTraceInit = false;
private TwsLogReceiver mLogReceiver;
private WeakReference<Context> mContextRef = null;
private static TwsLogImpl me = null;
private static StringBuilder mStrBuilder = new StringBuilder(1024);
private boolean mDebugable = false;
private boolean mForceLog = false;
private int mPid = -1;
private TwsLogImpl() {
try {
Class<TwsLogBaseConfig> clz = (Class<TwsLogBaseConfig>) Class.forName("tws.component.config.TwsLogConfig");
mConfig = clz.newInstance();
} catch (Exception e) {
throw new RuntimeException("Missing class TwsLogConfig(must implement the abstract class TwsLogBaseConfig) "
+ "in package which is 'tws.component.config'");
}
try {
final String className = mConfig.getPackageName() + ".BuildConfig";
Class<?> clz = Class.forName(className);
Field f = clz.getField("DEBUG");
mDebugable = f.getBoolean(null);
} catch (Exception e) {
mDebugable = false;
}
// for android os
if ("android".equals(mConfig.getPackageName()) && checkIfQromDebugVer()) {
mDebugable = true;
}
mForceLog = TwsLogUtils.getLogCfgSwitch(mConfig.getPackageName());
if (mLogHandler == null) {
initLogThread();
if (mLogThread.getLooper() != null) {
mLogHandler = new TwsLogHandler(mLogThread.getLooper(), mConfig);
mLogHandler.sendEmptyMessage(TwsLogHandler.LOG_MSG_FILE_CLEAN); // 清理过期日志
}
}
}
public static TwsLogImpl getInstance() {
if (me == null) {
me = new TwsLogImpl();
}
return me;
}
public void log(char level, String tag, String msg, Throwable tr) {
if (!mForceLog && !mDebugable) {
return;
}
if (mConfig.getLogMode() == TwsLogBaseConfig.LOG_NONE) {
return;
}
if (tag == null) {
return;
}
if (msg != null) {
msg += '\n';
}
String throwableStacks = null;
// 是否需要输出到IDE控制台上
if (mConfig.getLogMode() == TwsLogBaseConfig.LOG_CONSOLE || mConfig.getLogMode() == TwsLogBaseConfig.LOG_BOTH) {
if (tr != null) {
throwableStacks = TwsLog.getStackTraceString(tr);
}
switch (level) {
case 'i':
Log.i(tag, tr == null ? msg : msg + throwableStacks);
break;
case 'v':
Log.v(tag, tr == null ? msg : msg + throwableStacks);
break;
case 'd':
Log.d(tag, tr == null ? msg : msg + throwableStacks);
break;
case 'w':
if (msg == null) {
Log.w(tag, throwableStacks);
} else {
Log.w(tag, tr == null ? msg : throwableStacks);
}
break;
case 'e':
if (msg == null) {
Log.e(tag, throwableStacks);
} else {
Log.e(tag, tr == null ? msg : msg + throwableStacks);
}
break;
case 't':
if (msg == null) {
Log.wtf(tag, tr.getMessage(), tr);
} else {
Log.wtf(tag, msg, tr);
}
break;
default:
Log.d(tag, msg);
}
}
// 是否需要在file中输出日志
if (mForceLog || mConfig.getLogMode() == TwsLogBaseConfig.LOG_FILE || mConfig.getLogMode() == TwsLogBaseConfig.LOG_BOTH) {
if (throwableStacks == null && tr != null) {
throwableStacks = TwsLog.getStackTraceString(tr);
}
// pid发生变化时,输出到日志文件中
if (mPid != android.os.Process.myPid()) {
mPid = android.os.Process.myPid();
String pidInfo = "PID:" + mPid + "\n";
sendHandlerMsg("Info", tag, pidInfo, false);
}
switch (level) {
case 'i':
sendHandlerMsg("Info", tag, tr == null ? msg : msg + throwableStacks, false);
break;
case 'v':
sendHandlerMsg("Verbose", tag, tr == null ? msg : msg + throwableStacks, false);
break;
case 'd':
sendHandlerMsg("Debug", tag, tr == null ? msg : msg + throwableStacks, false);
break;
case 'w':
if (msg == null) {
sendHandlerMsg("Warn", tag, throwableStacks, false);
} else {
sendHandlerMsg("Warn", tag, tr == null ? msg : msg + throwableStacks, false);
}
break;
case 'e':
if (msg == null) {
sendHandlerMsg("Error", tag, throwableStacks, false);
} else {
sendHandlerMsg("Error", tag, tr == null ? msg : msg + throwableStacks, false);
}
break;
case 't':
TerribleFailure what = new TerribleFailure(msg, tr);
sendHandlerMsg("Assert", tag, TwsLog.getStackTraceString(what), false);
break;
default:
sendHandlerMsg("Debug", tag, tr == null ? msg : msg + throwableStacks, false);
}
}
}
public void trace(int module, String tag, String msg, Throwable tr) {
if (!mForceLog && !mDebugable) {
return;
}
if (msg != null) {
msg += '\n';
}
if (tag != null) {
if (mForceLog || mConfig.getLogMode() == TwsLogBaseConfig.LOG_FILE || mConfig.getLogMode() == TwsLogBaseConfig.LOG_BOTH) {
sendHandlerMsg("Trace", tag, tr == null ? msg : msg + TwsLog.getStackTraceString(tr), false);
}
}
}
public void crash(String tag, Throwable throwable) {
if (throwable == null || mConfig.getLogMode() == TwsLogBaseConfig.LOG_NONE) {
return;
}
File dir = TwsLogUtils.getCrashFileDirectory(mConfig.getPackageName());
File crashFile;
if (dir != null) {
Calendar cal = Calendar.getInstance();
crashFile = TwsLogUtils.createNewFile(dir.getAbsolutePath(), "crash_" + formatDate(cal) + ".log");
if (crashFile != null) {
FileWriter writer = null;
try {
writer = new FileWriter(crashFile, true);
writer.write(formatLogMessage("Crash", tag, TwsLog.getStackTraceString(throwable)));
writer.write("\r\n");
writer.flush();
} catch (Exception ex) {
System.out.println(ex.getMessage());
} finally {
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
}
}
}
}
public void crash(String tag, String msg) {
if (tag == null || msg == null || mConfig.getLogMode() == TwsLogBaseConfig.LOG_NONE) {
return;
}
File dir = TwsLogUtils.getCrashFileDirectory(mConfig.getPackageName());
File crashFile;
if (dir != null) {
Calendar cal = Calendar.getInstance();
crashFile = TwsLogUtils.createNewFile(dir.getAbsolutePath(), "crash_" + formatDate(cal) + ".log");
if (crashFile != null) {
FileWriter writer = null;
try {
writer = new FileWriter(crashFile, true);
writer.write(formatLogMessage("Crash", tag, msg));
writer.write("\r\n");
writer.flush();
} catch (Exception ex) {
System.out.println(ex.getMessage());
} finally {
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
}
}
}
}
public void setForceLog(boolean isForce) {
mForceLog = isForce;
}
protected void sendHandlerMsg(String level, String tag, String msg, boolean isTrace) {
if (mLogHandler != null) {
Message message;
if (isTrace) {
message = mLogHandler.obtainMessage(TwsLogHandler.LOG_MSG_TRACE_WRITE, formatLogMessage(level, tag, msg));
} else {
message = mLogHandler.obtainMessage(TwsLogHandler.LOG_MSG_LOG_WRITE, formatLogMessage(level, tag, msg));
}
mLogHandler.sendMessage(message);
}
}
public void registerLogReceiver(Context context) {
if (context != null) {
setContext(context);
} else {
return;
}
if (mLogReceiver == null) {
mLogReceiver = new TwsLogReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(TwsLogReceiver.ACTION_FORCE_LOG);
filter.addAction(TwsLogReceiver.ACTION_TRACE_LOG);
// 添加接收上报日志所需的相关信息数据
String pkgName = getPkgName();
if (pkgName == null || "".equals(pkgName)) {
pkgName = context.getPackageName();
}
filter.addAction(pkgName + TwsLogUploadImpl.ACTION_REPORT_LOG_INFO);
// TwsLog.w("=====", "registerReceiver: " +
// pkgName+TwsLogUploadImpl.ACTION_REPORT_LOG_INFO);
// aidanzhang, 临时解决方法,system server中拿到的context,
// context.getApplicationContext()为null
if (context.getApplicationContext() != null)
context.getApplicationContext().registerReceiver(mLogReceiver, filter);
else
context.registerReceiver(mLogReceiver, filter);
}
}
// public void trace(int module, String tag, String msg, Throwable tr) {
// if (!mForceLog && !mDebugable) {
// return;
// }
//
// if (!mTraceInit) {
// mTraceInit = true;
// readTraceLogParams();
// }
//
// if (mTraceParams == null) {
// return;
// }
//
// if (tag != null) {
// if (mForceLog || mConfig.getLogMode() == TwsLogBaseConfig.LOG_FILE ||
// mConfig.getLogMode() == TwsLogBaseConfig.LOG_BOTH) {
// sendHandlerMsg("Trace", tag, tr == null ? msg : msg + '\n' +
// TwsLog.getStackTraceString(tr), false);
// }
//
// if (mTraceParams.traceModules.size() > 0) {
// if (mTraceParams.traceExpires < System.currentTimeMillis()) {
// closeTraceLog();
// } else {
// if (mTraceParams.traceModules.contains(module) ||
// mTraceParams.traceModules.contains(TwsLogBaseConfig.TRACE_MODULE_ALL)) {
// String moduleStr = mConfig.getTraceModules().get(module);
// sendHandlerMsg(moduleStr == null ? "UNKNOWN" : moduleStr, tag, msg,
// true);
// }
// }
// }
// }
// }
// /**
// * 打开TraceLog日志
// *
// * @param expireTime 多少毫秒后Trace失效
// */
// public void openTraceLog(ArrayList<Integer> modules, long expireTime) {
// if (modules != null && modules.size() > 0 && expireTime > 0) {
// if (mTraceParams == null) {
// mTraceParams = new TwsTraceParams();
// } else {
// mTraceParams.traceModules.clear();
// }
//
// mTraceParams.traceModules.addAll(modules);
// mTraceParams.traceExpires = System.currentTimeMillis() + expireTime;
// }
// }
//
// public void closeTraceLog() {
// if (mLogHandler == null || mTraceParams == null) {
// return;
// }
//
// Message msg = Message.obtain(mLogHandler,
// TwsLogHandler.LOG_MSG_TRACE_CLOSE);
// if (mConfig.getLogMode() == TwsLogBaseConfig.LOG_NONE) {
// msg.obj = true;
// mLogHandler.sendMessageAtFrontOfQueue(msg);
// mLogThread = null;
// mLogHandler = null;
// mCalendar = null;
// } else{
// mLogHandler.sendMessageAtFrontOfQueue(msg);
// }
//
// /* 清空Trace Params */
// mTraceParams = null;
// }
//
// public void registerTraceLogReceiver(Context context) {
// if (context != null) {
// setContext(context);
// } else {
// return;
// }
//
// if (mTraceLogReceiver == null) {
// String action = context.getPackageName() + ".ACTION_TRACELOG";
// mTraceLogReceiver = new TwsLogReceiver();
// context.getApplicationContext().registerReceiver(mTraceLogReceiver,
// new IntentFilter(action));
// }
// }
//
// public void unregisterTraceLogReceiver(Context context) {
// if (context != null) {
// setContext(context);
// } else {
// return;
// }
//
// if (mTraceLogReceiver != null) {
// context.getApplicationContext().unregisterReceiver(mTraceLogReceiver);
// mTraceLogReceiver = null;
// }
// }
//
// public ArrayList<File> prepareUploadTraceLog() {
// if (mLogHandler != null) {
// return mLogHandler.prepareUploadTraceLog();
// } else {
// return null;
// }
// }
//
// /**
// * 发广播的方式打开TraceLog日志
// *
// * @param expireTime 多少毫秒后Trace失效
// */
// public void notifyTraceLogOpened(Context context, ArrayList<Integer>
// modules, long expireTime) {
// if (context != null) {
// setContext(context);
// } else {
// return;
// }
//
// writeTraceLogParams(modules, 1);
// Intent intent = new Intent(context.getPackageName() +
// ".ACTION_TRACELOG");
// intent.putIntegerArrayListExtra("TRACE_MODULES", modules);
// if (expireTime > 0) {
// intent.putExtra("TRACE_EXPIRES", expireTime);
// }
// intent.putExtra("TRACE_FLAG", true);
// context.sendBroadcast(intent);
// }
//
// public void notifyTraceLogClosed(Context context) {
// if (context != null) {
// setContext(context);
// } else {
// return;
// }
//
// writeTraceLogParams(null, 0);
// Intent intent = new Intent(context.getPackageName() +
// ".ACTION_TRACELOG");
// intent.putExtra("TRACE_FLAG", false);
// context.sendBroadcast(intent);
// }
//
//
// private void readTraceLogParams() {
// File ini = new
// File(TwsLogUtils.getLogFileDirectory(mConfig.getPackageName(), true),
// "trace.ini");
// if (ini != null && ini.exists()) {
// BufferedReader br = null;
// String modules = null;
// String expires = null;
// try {
// br = new BufferedReader(new FileReader(ini));
// String line;
// while((line = br.readLine()) != null) {
// if (line.startsWith("TraceModules=")) {
// modules = line.substring("TraceModules=".length());
// } else if (line.startsWith("TraceExpires=")){
// expires = line.substring("TraceExpires=".length());
// }
// }
// } catch (Exception ex) {
// System.out.println(ex.getMessage());
// } finally {
// if (br != null) {
// try {
// br.close();
// } catch (IOException e) {
// System.out.println(e.getMessage());
// }
// }
// }
//
// if (!TextUtils.isEmpty(modules) && !TextUtils.isEmpty(expires)) {
// long time = Long.parseLong(expires);
// if (time > System.currentTimeMillis()) {
// String[] array = modules.split(";");
// if (array != null && array.length > 0) {
// ArrayList<Integer> list = new ArrayList<Integer>();
// for (String s : array) {
// list.add(Integer.parseInt(s));
// }
//
// if (mTraceParams == null) {
// mTraceParams = new TwsTraceParams();
// } else {
// mTraceParams.traceModules.clear();
// }
// mTraceParams.traceModules.addAll(list);
// mTraceParams.traceExpires = time;
// } else {
// ini.delete();
// }
// } else {
// ini.delete();
// }
// } else {
// ini.delete();
// }
// }
// }
//
// private void writeTraceLogParams(ArrayList<Integer> modules, int
// timeOutHours) {
// if (modules != null && modules.size() > 0) {
// File dir = TwsLogUtils.getLogFileDirectory(mConfig.getPackageName(),
// true);
// if (dir == null) {
// return;
// }
//
// // 创建ini文件
// File ini = new File(dir, "trace.ini");
// if (!ini.exists()) {
// try {
// if (!ini.createNewFile()) {
// return;
// }
// } catch (IOException ex) {
// return;
// }
// }
//
// // 解析参数
// StringBuilder builder = new StringBuilder();
// int size = modules.size();
// for (int i = 0; i < size; i++) {
// if (i != 0) {
// builder.append(";");
// }
// builder.append(modules.get(i));
// }
// long expires = System.currentTimeMillis() + timeOutHours * 60 * 60 *
// 1000;
// // 写入参数
// BufferedWriter bw = null;
// try {
// bw = new BufferedWriter(new FileWriter(ini));
// bw.write("TraceModules=" + builder.toString() + "\r\n");
// bw.write("TraceExpires=" + String.valueOf(expires) + "\r\n");
// bw.flush();
// } catch (Exception ex) {
// ini.delete();
// } finally {
// if (bw != null) {
// try {
// bw.close();
// } catch (IOException e) {
// System.out.println(e.getMessage());
// }
// }
// }
// } else {
// File ini = new
// File(TwsLogUtils.getLogFileDirectory(mConfig.getPackageName(), true),
// "trace.ini");
// if (ini.exists()) {
// ini.delete();
// }
// }
// }
private void setContext(Context context) {
if (mContextRef == null) {
if (context.getApplicationContext() != null) {
mContextRef = new WeakReference<Context>(context.getApplicationContext());
} else {
mContextRef = new WeakReference<Context>(context);
}
} else {
Context ctx = mContextRef.get();
if (ctx == null) {
if (context.getApplicationContext() != null) {
mContextRef = new WeakReference<Context>(context.getApplicationContext());
} else {
mContextRef = new WeakReference<Context>(context);
}
}
}
}
/**
* 获取context
*
* @return
*/
public Context getContext() {
if (mContextRef != null) {
return mContextRef.get();
}
return null;
}
public boolean getDebugMode() {
return mDebugable;
}
public boolean reportInReleaseMode() {
if (mConfig != null) {
return mConfig.reportInReleaseMode();
}
return false;
}
private synchronized static String formatLogMessage(String level, String tag, String content) {
// %s/thread-%d/%s/%s: %s
String time = formatTime();
mStrBuilder.setLength(0);
mStrBuilder.append(time);
try {
mStrBuilder.append("/thread-").append(Thread.currentThread().getId()).append("/");
mStrBuilder.append(level).append("/").append(tag).append(": ").append(content.toString());
} catch (ArrayIndexOutOfBoundsException e) {
// do nothing
}
return mStrBuilder.toString();
}
private static String formatTime() {
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
try {
mStrBuilder.setLength(0);
int num = calendar.get(Calendar.MONTH) + 1;
if (num < 10) {
mStrBuilder.append("0");
}
mStrBuilder.append(num);
mStrBuilder.append("-");
num = calendar.get(Calendar.DAY_OF_MONTH);
if (num < 10) {
mStrBuilder.append("0");
}
mStrBuilder.append(num);
mStrBuilder.append(" ");
num = calendar.get(Calendar.HOUR_OF_DAY);
if (num < 10) {
mStrBuilder.append("0");
}
mStrBuilder.append(num);
mStrBuilder.append(":");
num = calendar.get(Calendar.MINUTE);
if (num < 10) {
mStrBuilder.append("0");
}
mStrBuilder.append(num);
mStrBuilder.append(":");
num = calendar.get(Calendar.SECOND);
if (num < 10) {
mStrBuilder.append("0");
}
mStrBuilder.append(num);
mStrBuilder.append(":");
num = calendar.get(Calendar.MILLISECOND);
if (num < 100) {
mStrBuilder.append("0");
if (num < 10) {
mStrBuilder.append("0");
}
}
mStrBuilder.append(num);
return mStrBuilder.toString();
} finally {
mStrBuilder.setLength(0);
}
}
private synchronized static String formatDate(Calendar calendar) {
if (calendar == null) {
calendar = Calendar.getInstance();
}
try {
mStrBuilder.setLength(0);
int num = calendar.get(Calendar.YEAR);
mStrBuilder.append(num);
num = calendar.get(Calendar.MONTH) + 1;
if (num < 10) {
mStrBuilder.append("0");
}
mStrBuilder.append(num);
mStrBuilder.append("-");
num = calendar.get(Calendar.DAY_OF_MONTH);
if (num < 10) {
mStrBuilder.append("0");
}
mStrBuilder.append(num);
return mStrBuilder.toString();
} finally {
mStrBuilder.setLength(0);
}
}
// private static class TwsTraceParams {
// public Set<Integer> traceModules = null;
// public long traceExpires = 0;
// public TwsTraceParams() {
// traceModules = new HashSet<Integer>();
// }
// }
private static class TerribleFailure extends Exception {
TerribleFailure(String msg, Throwable cause) {
super(msg, cause);
}
}
public static boolean checkIfQromDebugVer() {
boolean result = false;
try {
String ret = getSysProp("getprop ro.tws.build.version.type");
if ("DD".equals(ret.trim())) {
result = true;
}
} catch (Exception e) {
}
return result;
}
private static String getSysProp(String cmd) throws Exception {
java.lang.Process process = Runtime.getRuntime().exec(cmd);
InputStreamReader inputStreamReader = new InputStreamReader(process.getInputStream());
char[] buf = new char[15];
int readLen = 0;
StringBuilder strb = new StringBuilder();
;
while ((readLen = inputStreamReader.read(buf)) != -1) {
strb.append(buf, 0, readLen);
}
return strb.toString();
}
private void initLogThread() {
if (mLogThread == null) {
mLogThread = new HandlerThread("TwsLogThread");
mLogThread.start();
}
}
public Looper getLogThreadLooper() {
initLogThread();
return mLogThread.getLooper();
}
public File getLogStoragePath() {
return TwsLogUtils.getLogFileDirectory(mConfig.getPackageName(), false);
}
public String getLogStoragePathStr() {
File logFileDir = TwsLogUtils.getLogFileDirectory(mConfig.getPackageName(), false);
if (logFileDir == null) {
return null;
}
return logFileDir.getAbsolutePath();
}
public String getPkgName() {
if (mConfig != null) {
return mConfig.getPackageName();
}
return null;
}
}