2

ゴール

LogCatの定期的な更新を収集し、それらのテキストのチャンクをSDカード上のファイルに保存(追加)します

問題

Logクラスは、特定のタイムスタンプ以降の更新を提供しません

考えられる解決策

私の計画は、次のようなコードを定期的に実行することです:http ://www.helloandroid.com/tutorials/reading-logs-programatically またはhttps://stackoverflow.com/a/9039352/550471

ただし、1つの顕著な違いがあります。-v timeパラメータを使用して、各行にタイムスタンプが付けられていることを確認します。

LogCatデータが収集されるたびに、アプリは最後のログエントリのタイムスタンプを保存します。次回LogCatデータが収集されると、アプリはテキストを検索してタイムスタンプを見つけ、指定されたタイムスタンプ以降にログに追加されたデータのチャンクをsdcardに保存します。

考えられる問題

LogCatデータが短すぎる期間で収集される場合、CPUは多くの「古い」データの処理でビジー状態になります。Logcatデータが長期間収集されると、一部のデータが失われる可能性があります。

もっと良い方法はありますか?

4

1 に答える 1

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
于 2012-07-30T22:51:36.073 に答える