android⽇志上传策略,Android进阶:⼀、⽇志打印和保存策略前⾔:
项⽬开始没有做好⽇志统计⼯作,每次有问题后端都得前端对接,严重影响⼯作效率。最近特地在项⽬中加上⽇志保存策略,在此分享,供需要的⼈学习。
更详细的⽇志信息
既然决定⾃定义⼀个log,那我们就可以让它显⽰更多的信息,如线程信息:threadId,threadName等:private String getFunctionName(){
StackTraceElement[] sts = Thread.currentThread().getStackTrace();
if (sts == null) {
return null;
}
for (StackTraceElement st : sts) {
if (st.isNativeMethod()) {
continue;
}
if (st.getClassName().equals(Name())) {
continue;
}
if (st.getClassName().Class().getName())) {
continue;
}
Thread t = Thread.currentThread();
return "[T(id:" + t.getId() +
", name:" + t.getName() +
", priority:" + t.getPriority() +
", groupName:" + t.getThreadGroup().getName() +
"): " + st.getFileName() + ":"
+ st.getLineNumber() + " " + st.getMethodName() + " ]";
}
return "";
}
复制代码
StackTrace(堆栈轨迹)存放的就是⽅法调⽤栈的信息,我们从中获取⽅法执⾏的线程相关的信息,以及执⾏的⽅法名称等。这些信息能帮助我们更好的查问题之所在。private void logPrint(int logLevel, Object msg){
if (isDebug) {
String name = getFunctionName();
customTag = TextUtils.isEmpty(customTag) ? defaultTag : customTag;
Log.println(logLevel, customTag, name + " - " + msg);
}
}
复制代码
使⽤Log.println⽅法打印相关信息即可。
⽇志保存策略
后端的⼈在测试的时候会遇到BUG,有时候不知道到底是前端出了问题还是后端的问题,为了更好更快速的定位,后端应该知道前端的⽇志保存在哪⾥。这就需要我们制定⼀个⽇志保存策略。(即使要上传⽇志,也应该先保存成⽂件再上传⽂件,不然每⼀条⽇志调⽤⼀次接⼝,接⼝的压⼒会很⼤,很不合理)
由于保存⽇志的过程是个耗时过程,我们需要开启线程去保存。但是⽇志产⽣的频率可能很⾼,⼜不能采⽤⼀般的线程去处理,太多的线程也会损耗性能。所以我们应该考虑队列的形式保存⽇志,然后⼀条⼀条的去保存。public void initSaveStrategy(Context context){
if (saveLogStrategy != null || !isDebug) {
return;
}
final int MAX_BYTES = 1024 * 1024;
String diskPath = ExternalStorageDirectory().getAbsolutePath();
File cacheFile = CacheDir();
if (cacheFile != null) {
diskPath = AbsolutePath();
}
String folder = diskPath + File.separatorChar + "log";
HandlerThread ht = new HandlerThread("SohuLiveLogger." + folder);
ht.start();
Handler handler = new SaveLogStrategy.Looper(), folder, MAX_BYTES);
saveLogStrategy = new SaveLogStrategy(handler);
}
复制代码public static class WriteHandler extends Handler{
private final String folder;
private final int maxFileSize;
WriteHandler(@NonNull Looper looper, @NonNull String folder, int maxFileSize) {
super(checkNotNull(looper));
this.folder = checkNotNull(folder);
this.maxFileSize = maxFileSize;
}
@Override
public void handleMessage(@NonNull Message msg){
String content = (String) msg.obj;
FileWriter fileWriter = null;
File logFile = getLogFile(folder, "logs");
getsavefilenametry {
fileWriter = new FileWriter(logFile, true);
writeLog(fileWriter, content);
fileWriter.flush();
fileWriter.close();
} catch (IOException e) {
if (fileWriter != null) {
try {
fileWriter.flush();
fileWriter.close();
} catch (IOException e1) {
}
}
}
}
复制代码
我们使⽤HandlerThread来处理这个任务。HandlerThread是⼀个可以使⽤handler的Thread。当我们把消息保存到消息队列中去之后会在线程中去处理,⼜能保证不会产⽣很多线程。其实这⾥也可以使⽤instentservice实现,这个服务适合量⼤⽽不太耗时的任务。
最后在⼀个⽅法中统⼀打印和保存即可:private void logPrint(int logLevel, Object msg){
if (isDebug) {
String name = getFunctionName();
if (saveLogStrategy != null) {
saveLogStrategy.log(Log.ERROR, customTag, name + " - " + msg);
}
Log.println(logLevel, customTag, name + " - " + msg);
}
}
复制代码
⾃定义的log策略还是⽐较简单,主要就是这个思想:打印⽇志信息详细,保存要采⽤队列的形式。⼀下是全部代码:public class Logger{
public final static String tag = "";
private static SaveLogStrategy saveLogStrategy;
private final static boolean logFlag = true;
private static Logger logger;
private int logLevel = Log.VERBOSE;
private static boolean isDebug = BuildConfig.DEBUG;
private String customTag = null;
private Logger(String customTag){
this.customTag = customTag;
}
public void initSaveStrategy(Context context){
if (saveLogStrategy != null || !isDebug) {
return;
}
final int MAX_BYTES = 1024 * 1024;
String diskPath = ExternalStorageDirectory().getAbsolutePath();
File cacheFile = CacheDir();
if (cacheFile != null) {
diskPath = AbsolutePath();
}
String folder = diskPath + File.separatorChar + "log";
HandlerThread ht = new HandlerThread("Logger." + folder);
ht.start();
Handler handler = new SaveLogStrategy.Looper(), folder, MAX_BYTES);
saveLogStrategy = new SaveLogStrategy(handler);
}
public static Logger getLogger(String tag){
if (logger == null) {
logger = new Logger(tag);
}
return logger;
}
public static Logger getLogger(){ if (logger == null) {
logger = new Logger(tag);
}
return logger;
}
/**
* Verbose(2) 级别⽇志
*
* @param str String
*/
public void v(Object str){ logLevel = Log.VERBOSE; logPrint(logLevel, str);
}
/**
* Debug(3) 级别⽇志
*
* @param str String
*/
public void d(Object str){ logLevel = Log.DEBUG;
logPrint(logLevel, str);
}
/**
* Info(4) 级别⽇志
*
* @param str String
*/
public void i(Object str){
logLevel = Log.INFO;
logPrint(logLevel, str);
}
/**
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论