2

目标

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

问题

由于特定时间戳,Log 类不提供更新

可能的解决方案

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

但是,有一个显着的区别:使用-v time参数来确保每一行都带有时间戳。

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

可能的问题

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

有没有更好的办法 ?

4

1 回答 1

1

这就是我想出的——当它不冻结时效果很好。

正如您可能知道的那样,Runtime.getRuntime().exec("")在 Android 中导致 ANR 的可能性比 Jelly Bean 更早。如果有人有解决 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
于 2012-07-30T22:51:36.073 回答