定期LogCat轮询更新并保存到SD卡

时间:2012-07-19 22:49:39

标签: android

目标

收集LogCat的定期更新并将这些文本块保存(追加)到SD卡上的文件中

问题

Log类不提供自特定时间戳

以来的更新

可能的解决方案

我的计划是定期运行类似于http://www.helloandroid.com/tutorials/reading-logs-programatically的代码 或https://stackoverflow.com/a/9039352/550471

但是,有一个值得注意的区别:使用-v time参数确保每一行都带有时间戳。

每次收集LogCat数据后,应用程序将存储最后一个日志条目的时间戳。下次收集LogCat数据时,应用程序将搜索文本以查找时间戳,然后将数据块保存到自指定时间戳以来添加到日志中的SD卡。

可能出现的问题

如果在太短的时间内收集LogCat数据,则CPU正忙于处理大量“旧”数据。 如果Logcat数据的收集时间太长,那么可能会遗漏一些数据。

有更好的方法吗?

1 个答案:

答案 0 :(得分:1)

这就是我提出的 - 当它没有冻结时效果非常好。

您可能知道,Runtime.getRuntime().exec("")很有可能在早于Jelly Bean的Android中导致ANR。如果有人有解决方案来克服ANR,请分享。

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;

import android.os.Environment;
import android.util.Log;

/*
 * For (compressed) buffer sizes, see: http://elinux.org/Android_Logging_System
 * buffer:main = 64KB
 * buffer:radio = 64KB
 * buffer:system = 64KB
 * buffer:event = 256KB
 * 
 * NOTE: the 'command' must include "-d -v time" !!
 * to switch buffers, use "-b <buffer>"
 */
public class LogCatReader {
    // constants
    private static final String CR = "\r\n";
    private static final String END_OF_DATE_TIME = "): ";
    private static final int DEFAULT_SEARCH_START_INDEX = 0;

    // member variables
    private StringBuilder mLog;
    private LogThread mLogThread = null;
    private String mLastLogReadToken = "";
    private String mLogCommand = "";
    private int mStringCapacity;
    private File mFileTarget = null;

    // constructor
    public LogCatReader(String command, int capacity) {
        mLogCommand = command;
        mStringCapacity = capacity;
    }

    // returns complete logcat buffer
    // note: takes about 1.5sec to finish
    synchronized public StringBuilder getLogComplete() {
        try {
            // capacity should be about 25% bigger than buffer size since the
            // buffer is compressed
            mLog = new StringBuilder(mStringCapacity);

            // command to capture log
            Process process = Runtime.getRuntime().exec(mLogCommand);
            BufferedReader bufferedReader = new BufferedReader(
                    new InputStreamReader(process.getInputStream()));

            String line;
            while ((line = bufferedReader.readLine()) != null) {
                // append() is costly if capacity needs to be increased, be sure
                // to reserve enough in the first place
                mLog.append(line + CR);
            }
        } catch (IOException e) {
        }

        return mLog;
    }

    public String getLogUpdatesOnly() {
        String strReturn = "";

        StringBuilder sbLog = getLogComplete();

        try {
            int iStartindex = DEFAULT_SEARCH_START_INDEX;

            // if there exists a token from a previous search then use that
            if (mLastLogReadToken.length() > 0) {
                iStartindex = sbLog.indexOf(mLastLogReadToken);

                // if string not found then start at beginning
                if (iStartindex == -1) {
                    // start search at beginning of log
                    iStartindex = DEFAULT_SEARCH_START_INDEX;
                }
            }

            int iEndindex = sbLog.length();

            // if token is found then move index to the next line
            if (iStartindex > DEFAULT_SEARCH_START_INDEX) {
                iStartindex = sbLog.indexOf(CR, iStartindex);

                if (iStartindex != -1) {
                    iStartindex += CR.length();
                } else {
                    // return an empty string
                    iStartindex = iEndindex;
                }
            }

            // grab the data between the start and end indices
            strReturn = sbLog.substring(iStartindex, iEndindex);

            // grab date/time token for next search
            iStartindex = sbLog.lastIndexOf(END_OF_DATE_TIME);

            if (iStartindex != -1) {
                iEndindex = iStartindex;
                iStartindex = sbLog.lastIndexOf(CR, iEndindex);
                iStartindex += CR.length();

                if (iStartindex == -1) {
                    // read from beginning
                    iStartindex = 0;
                }

                mLastLogReadToken = sbLog.substring(iStartindex, iEndindex);
            }
        } catch (Exception e) {
            strReturn = "";
        }

        return strReturn;
    }

    public void startPeriodicLogCatReader(int timePeriod, String logfilename) {
        if (mLogThread == null) {
            mLogThread = new LogThread(timePeriod, logfilename);
            mLogThread.start();
        }
    }

    public void stopPeriodicLogCatReader() {
        if (mLogThread != null) {
            mLogThread.interrupt();
            mLogThread = null;
        }
    }

    private class LogThread extends Thread {
        private boolean mInterrupted;
        private int mTimePeriod;// in seconds
        private String mLogref;
        private BufferedWriter mBuffWriter = null;
        public boolean mPauseLogCollection = false;

        // constructor: logfilename is optional - pass null to not use
        public LogThread(int timePeriod, String logfilename) {
            mTimePeriod = timePeriod;

            if (logfilename != null) {
                File fLogFolder = new File(
                        Environment.getExternalStorageDirectory() + "/logfiles");
                if (fLogFolder.exists() == false) {
                    if (fLogFolder.mkdirs() == false) {
                        Log.e("LogCatReader",
                                "Could not create "
                                        + fLogFolder.getAbsolutePath());
                    }
                }

                mFileTarget = new File(
                        Environment.getExternalStorageDirectory() + "/logfiles",
                        logfilename);

                if (mFileTarget.exists() == false) {
                    try {
                        // file doesn't yet exist - create a fresh one !
                        mFileTarget.createNewFile();
                    } catch (IOException e) {
                        e.printStackTrace();
                        mFileTarget = null;
                    }
                }
            }
        }

        @Override
        public void interrupt() {
            mInterrupted = true;
            super.interrupt();
        }

        @Override
        public void run() {
            super.run();

            // initialization
            mInterrupted = false;

            // set up storage
            if (mFileTarget != null) {
                try {
                    mBuffWriter = new BufferedWriter(new FileWriter(
                            mFileTarget, true), 10240);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            while ((mInterrupted == false) && (mBuffWriter != null)) {
                if (mPauseLogCollection == false) {
                    // read log updates
                    mLogref = getLogUpdatesOnly();

                    // save log updates to file
                    try {
                        mBuffWriter.append(mLogref);
                        mBuffWriter.flush();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }

                if (!mInterrupted) {
                    try {
                        sleep(mTimePeriod * 1000);
                    } catch (InterruptedException e) {
                    }
                }
            }

            if (mBuffWriter != null) {
                try {
                    mBuffWriter.close();
                    mBuffWriter = null;
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }// end of inner class
}// end of outer class

我以前只查找更新的过程是捕获logcat最后一行的日期和时间,并在下次使用它作为搜索令牌。

要使用此类,以下是一个示例:

        LogCatReader logcatPeriodicReader = new LogCatReader("logcat -b main -d -v time", 80 * 1024);//collect "main" buffer, exit after reading logcat
        logcatPeriodicReader.startPeriodicLogReader(90, "log.txt");//read logcat every 90 secs