【安卓筆記】崩潰日誌收集

rowandjj發表於2015-05-22

應用釋出之後,總有人反饋說發生crash,但是由於拿不到log,我無法定位問題。後來發現,我們應該收集crash日誌,並上傳到伺服器。

國內有很多的三方機構提供了崩潰收集的sdk,我們可以直接拿來使用,比如,我之前做的app使用的是bugHD(http://bughd.com/)提供的服務。

但是崩潰收集的原理是什麼呢?搜尋了一下,發現使用的是java中的uncaughtExceptionHandler,我們可以通過Thread.setDefautUncaughtExceptionHandler()設定我們自己的UncaughtExceptionHandler。它其實是一個介面,實現方法即可。


我寫的一個demo:

import android.os.Looper;
import android.widget.Toast;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Map;
/**
 * Created by Rowandjj on 2015/5/19.
 *
 * 崩潰日誌收集
 */
public class CrashHandler implements Thread.UncaughtExceptionHandler
{
    private static CrashHandler sInstance = null;
    private static Object lock = new Object();
    private Thread.UncaughtExceptionHandler mDefaultExceptionHandler;
    private CrashHandler()
    {
    }
    public static CrashHandler getInstance()
    {
        if (sInstance == null)
        {
            synchronized (lock)
            {
                if (sInstance == null)
                    sInstance = new CrashHandler();
            }
        }
        return sInstance;
    }
    public void register()
    {
        mDefaultExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
        Thread.setDefaultUncaughtExceptionHandler(this);
    }
    @Override
    public void uncaughtException(Thread thread, Throwable ex)
    {
        //生成日誌
        final String filename = cacheLog(ex);
        new Thread(new Runnable()
        {
            @Override
            public void run()
            {
                Looper.prepare();
                if(filename != null)
                    Toast.makeText(AppEnv.getAppContext(),"程式崩潰了:( \n崩潰日誌已儲存到"+filename+"",Toast.LENGTH_SHORT).show();
                Looper.loop();
            }
        }).start();
        try
        {
            Thread.sleep(2000);
        } catch (InterruptedException e)
        {
            e.printStackTrace();
        }
        mDefaultExceptionHandler.uncaughtException(thread,ex);
    }
    private String cacheLog(Throwable ex)
    {
        if(ex == null)
            return null;
        Map<String, String> hardwareInfo = HardwareUtils.getHardwareInfo();
        StringBuilder buffer = new StringBuilder();
        for (Map.Entry<String, String> me : hardwareInfo.entrySet())
        {
            buffer.append(me.getKey() + ":" + me.getValue() + "\n");
        }
        buffer.append("packname:" + AppEnv.getPackageName() + "\n");
        buffer.append("versionname:" + AppEnv.getVersionName() + "\n");
        buffer.append("versioncode:" + AppEnv.getVersionCode() + "\n");
        Writer writer = new StringWriter();
        PrintWriter printWriter = new PrintWriter(writer);
        ex.printStackTrace(printWriter);
        Throwable cause = ex.getCause();
        while (cause != null)
        {
            cause.printStackTrace(printWriter);
            cause = cause.getCause();
        }
        printWriter.close();
        String result = writer.toString();
        buffer.append(result);
        long timestamp = System.currentTimeMillis();
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.CHINA);
        String time = formatter.format(new Date());
        String filename = "crash-" + time + "-" + timestamp + ".log";
        File file = new File(BasicUtils.getStoreDir(), filename);
        try
        {
            if (!file.exists())
                file.createNewFile();
            FileOutputStream out = new FileOutputStream(file);
            out.write(buffer.toString().getBytes());
            out.close();
            Logger.d(this,file.getAbsolutePath());
            return file.getAbsolutePath();
        } catch (IOException e)
        {
            e.printStackTrace();
        }
        return null;
    }
}

然後在你應用的Application中呼叫

CrashHandler.getInstance().register();
即可。

應用出現crash時,會把log儲存到本地。如果希望上傳到伺服器,加上一個http上傳模組即可。


部分程式碼沒有貼出,大家自己腦補。



相關文章