在我们发布的签名应用中,日志都是关闭的,通常只会做发送崩溃日志的功能。但在某些场景中,如用户数据有异常等情况,需要对具体日志进行分析,但这是我们无法获取日志,此时就通过某个隐藏功能,让用户可以在执行这个操作后,能够将日志发送到服务器,以便开发人员进行分析。
在日志记录中,通常会使用logcat命令来进行日志的记录,关键代码如下:
private void collectOld(){
/* Logcat命令列表
Option Description
-b <buffer> 加载一个可使用的日志缓冲区供查看,比如event 和radio . 默认值是main 。具体查看Viewing Alternative Log Buffers.
-c 清楚屏幕上的日志.
-d 输出日志到屏幕上.
-f <filename> 指定输出日志信息的<filename> ,默认是stdout .
-g 输出指定的日志缓冲区,输出后退出.
-n <count> 设置日志的最大数目<count> .,默认值是4,需要和 -r 选项一起使用。
-r <kbytes> 每<kbytes> 时输出日志,默认值为16,需要和-f 选项一起使用.
-s 设置默认的过滤级别为silent.
-v <format> 设置日志输入格式,默认的是brief 格式,要知道更多的支持的格式,参看Controlling Log Output Format
*/
String logFileName = sdf.format(new Date()) + ".log";// 日志文件名称
List<String> commandList = new ArrayList<String>();
commandList.add("logcat");
//设置输入文件的路径,并将路径保存到SharedPreferences中
commandList.add("-f");
String realLogPath = getLogPath();
//设置输入格式
commandList.add(realLogPath);
commandList.add("-v");
commandList.add("time");
//过滤所有TAG的级别V以上的信息,如果需指明TAG,无论级别,则必须在指明后增加*:S命令
commandList.add("*:V");
try {
process = Runtime.getRuntime().exec(
commandList.toArray(new String[commandList.size()]));
recordLogServiceLog("start collecting the log,and log name is:"+logFileName);
process.waitFor();
} catch (Exception e) {
recordLogServiceLog("CollectorThread == >" + e.getMessage());
}
}
经过测试,上述代码确实运行正常,但也有个非常明显的问题。它会将所有日志记录下来,包括本应用的和其他应用所产生的,这对我们的日志查看非常不利,因为我们只需要看到本应用的日志即可。在命令行中使用logcat,我们可以通过grep根据应用的PID来实现过滤本应用的日志,但在logcat命令中,logcat -f 却无法使用grep来进行过滤,因此,再使用logcat -f来保存日志,并不符合需求。经过测试,使用logcat + grep来获得InputStream,通过手动写入文件的方式,而非通过logcat
-f可以实现这种过滤效果。具体的实现为:
private void collectNew(){
mPID = android.os.Process.myPid()+"";
String realLogPath = getLogPath();
SharedPreferences sp = getSharedPreferences("logserver", MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.putString("log_path", realLogPath);
editor.commit();
SimpleDateFormat sdf = new SimpleDateFormat("MM-dd HH:mm:ss:SSS");
try {
File file = new File(realLogPath);
String cmds = "logcat *:v | grep \"(" + mPID + ")\"";
logcatProc = Runtime.getRuntime().exec(cmds);
mReader = new BufferedReader(new InputStreamReader(logcatProc.getInputStream()), 1024);
out = new FileOutputStream(file);
String line = null;
while (mRunning && (line = mReader.readLine()) != null) {
if (!mRunning) {
break;
}
if (line.length() == 0) {
continue;
}
if (out != null && line.contains(mPID)) {
out.write((sdf.format(new Date()) + " " + line + "\n").getBytes());
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (logcatProc != null) {
logcatProc.destroy();
logcatProc = null;
}
if (mReader != null) {
try {
mReader.close();
mReader = null;
} catch (IOException e) {
e.printStackTrace();
}
}
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
out = null;
}
}
}
经过验证,新的方法实现了只记录本应用日志到指定文件的功能。