安卓在当前进程直接使用log存运行日志会有两个问题
- 多少有点耗时,打印的日志需要实时存到文件
- 当前进程异常退出可能会出现日志丢失的情况
解决方法最好是新建一个服务,执行命令 logcat -f file -v threadtime tag:v *:s,这里过滤方式最好使用tag,不要用grep,后者是输出日志后过滤,依然会存到文件里,造成大量无效信息!
通常app这边有测试环境和生产环境,测试环境可以只过滤http的,生产环境再输出全部日志;测试环境的时候开发可以看到全部日志的,但是测试组通常只关心请求日志~
(附日志服务代码:设置了过滤、文件大小限制等) 存好日志文件可以通过静默推送或者用户手动拉回就可以咯
public class LogRecordService extends Service {
private static final String TAG = LogRecordService.class.getSimpleName();
private static final String ACTION = "action";
Timer timer;
Process process;
String logFile;
private void execLogcatCmd() {
List<String> commandList = new ArrayList<>();
commandList.add("logcat");
commandList.add("-c");
// 先清除日志
try {
Runtime.getRuntime().exec(
commandList.toArray(new String[commandList.size()]));
} catch (Exception e1) {
ZNLog.printStacktrace(e1);
}
//测试环境只存 http请求, 正式环境存所有的log
String tagGrep = EnvConfig.isDebug()? ZNHttpLogInterceptor.TAG:ZNLog.TAG;
//测试环境只看http,正式环境打印所有log
commandList.clear();
commandList.add("logcat");
commandList.add("-f");
commandList.add(logFile);
commandList.add("-v");
commandList.add("threadtime");
commandList.add(tagGrep+":v");
commandList.add("*:S");
try {
String[] comms = commandList
.toArray(new String[commandList.size()]);
process = Runtime.getRuntime().exec(comms);
ZNLog.e(TAG, "writeLog command: " + Arrays.deepToString(comms));
} catch (Exception e) {
ZNLog.printStacktrace(e);
}
}
/**
* 日志文件超过一定大小
* @return
*/
private boolean isLogOverMax(){
ZNLog.d(TAG, "isLogOverMax() called : " + "");
if(TextUtils.isEmpty(logFile)){
return false;
}
File file = FileUtils.getFileByPath(logFile);
if(!file.exists()){
return false;
}
double size = (file.length()/(1024.0*1024.0));
ZNLog.d(TAG, "isLogOverMax() called : space = " + size);
return size>3;//大于3m
}
@Override
public void onDestroy() {
super.onDestroy();
if(timer!=null){
timer.cancel();
}
timer = null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(intent!=null&&intent.getExtras()!=null){
int action = intent.getIntExtra(ACTION,1);
if(action!=1){
onStopCmd(true);
}else{
onStartCmd();
}
}
return super.onStartCommand(intent, flags, startId);
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
private void onStartCmd(){
ZNLog.e(TAG, "开启日志记录服务...");
onStopCmd(false);
timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
if(timer==null){
return;
}
ZNLog.d(TAG, "run() called : logFile==null " + (logFile==null));
if(TextUtils.isEmpty(logFile)){
logFile = LogFileHelp.getLastFilePath();
if(!FileUtil.isFileExist(logFile)||isLogOverMax()){//文件不存在或如果超过了容量
logFile = LogFileHelp.getNewLogFilePath();
}
execLogcatCmd();
}else{
if(isLogOverMax()){//再次循环的时候,如果超过了容量
if(!ZNApplication.isDebugMode()){
//正式环境一旦超过容量,就停掉日志记录(也就是说只会记录一个文件,留作上传使用)
onStopCmd(true);
return;
}
logFile = LogFileHelp.getNewLogFilePath();
execLogcatCmd();
}
}
}
},100,5*60*1000);//5分钟检测一次
}
private void onStopCmd(boolean stopServer) {
if(timer!=null){
timer.cancel();
}
timer = null;
try {
if(process!=null){
process.destroy();
process = null;
}
} catch (Exception e) {
e.printStackTrace();
}
logFile = null;
if(stopServer){
stopSelf();
}
}
//开始
public static void startService(){
Intent intent = new Intent(ZNApplication.getZNContext(), LogRecordService.class);
intent.putExtra(ACTION,1);
ZNApplication.getZNContext().startService(intent);
}
//停止
public static void stopService(){
Intent intent = new Intent(ZNApplication.getZNContext(), LogRecordService.class);
intent.putExtra(ACTION,0);
ZNApplication.getZNContext().startService(intent);
}
}