funini.com 自由研究 SD Logger

SD Logger

ログを取って後でじっくり分析したいとき、logcat では溢れてしまったり、 抜き出しが面倒だったりします。そこで、sd カードに出すツールを作ってみました。

特徴

SDLogger のソース

package com.funini.sdlogger;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Environment;
import android.util.Log;
import android.widget.Toast;

/**
 * Simple logger for Android
 * Export app logs to sdcard
 * 
 * Usage:
 * sdLogger = SDLogger.getInstance();
 * sdLogger.writeln("TAG", "message");
 * 
 */
@SuppressLint("SimpleDateFormat")
public class SDLogger {
    public final static String TAG = "SDLogger"; 
    final static String SEPARATOR = ","; 
    
    static SDLogger mLogger = null;
    final File mLogDir, mLogFile;
    StringBuffer mBuffer = new StringBuffer();
    final static int BUFFER_THRES = 4096;
    Context mContext;
    static DateFormat mStringDateFormat = new SimpleDateFormat("yyyy-MM-dd_hhmm");
    
    private SDLogger(Context context) {
        mContext = context;
        mLogDir = Environment.getExternalStoragePublicDirectory("PonLog");
        String dateExpr = mStringDateFormat.format(new Date());
        mLogFile = new File(Environment.getExternalStoragePublicDirectory("PonLog"), dateExpr + ".csv");
        showMsg("Starting logging to " + mLogFile.toString());
        Log.w("SDLogger", "Starting logging to " + mLogFile);
    }

    
    public void flush() {
        Log.w("SDLogger", "Stopping logging");
        dump();
    }

        
    void showMsg(String msg) {
        Log.i(TAG, msg);
        Toast.makeText(mContext, msg, Toast.LENGTH_LONG).show();
    }

    
    public static SDLogger getLoger(Context context) {
        if(mLogger == null) {
            mLogger = new SDLogger(context);
        }
        return mLogger;
    }
    

    void appendTime() {
        Date now = new Date();
        String dateExpr = mStringDateFormat.format(now);
        mBuffer.append(dateExpr);
        mBuffer.append(SEPARATOR);
        mBuffer.append(now.getTime());
        mBuffer.append(SEPARATOR);
    }

    
    /**
     * Write log with tag
     * @param tag Log tag
     * @param log Log message
     */
    public void writeln(final String tag, final String log) {
        writeln(tag + SEPARATOR + log);
    }
    
    
    public void writeln(final String log) {
        appendTime();
        mBuffer.append(log);
        mBuffer.append("\n");
        if(mBuffer.length() > BUFFER_THRES) {
            dump();
        }
    }
        
    
    public void dump() {
        if(!mLogDir.exists()) {
            showMsg(mLogDir + " does not exists");
            if(!mLogDir.mkdirs()) {
                showMsg("Failed to mkdir(" + mLogDir + "). Check if WRITE_EXTERNAL_STORAGE permission is set.");
                return;
            }
        }
        
        boolean appendMode = mLogFile.exists();
        try {
            FileWriter writer = new FileWriter(mLogFile, appendMode);
            writer.write(mBuffer.toString());
            writer.close();
            mBuffer.setLength(0);
            showMsg("Logs are successfully written to " + mLogFile);
        } catch (FileNotFoundException e) {
            showMsg("Log file " + mLogFile.toString() + " not found ");
            return;
        } catch (IOException e) {
            showMsg("Failed to write log to " + mLogFile + "\n" + e.toString());
        }
    }
}

使うサンプル

タッチされた点が 10 個まで画面に表示されます。
タッチされた点の座標をログします。
SDLoggerSample.tgz
package com.funini.sdlogger;

import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;

public class MainActivity extends Activity {
    SDLogger mSDLogger;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new MyView(this));
        mSDLogger = SDLogger.getLoger(this);
    }

  
    @Override
    protected void onPause() {
        super.onPause();
        mSDLogger.flush();
    }

    
    class MyView extends View {
        final static int DIAM = 40;
        final static int N_POINTS = 10;
        Paint mPaint = new Paint();
        List mPoints = new ArrayList();
        int[] mColors = new int[N_POINTS];
        
        public MyView(Context context){
            super(context);
            for(int i = 0; i < N_POINTS; i++) {
                int r = (int)(127.0 * i / N_POINTS + 128);
                int g = (int)(63.0 * i / N_POINTS + 192);
                mColors[i] = Color.rgb(r, g, 255);
            }
        }
        
        void addPoint(int x, int y){
            mPoints.add(0, new Point(x, y));
            if(mPoints.size() > N_POINTS){
                mPoints.remove(mPoints.size() - 1);
            }
            mSDLogger.writeln(x + "," + y);
            invalidate();
        }
        
        
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            for(int i = mPoints.size() - 1; i >= 0; i--) {
                Point p = mPoints.get(i);
                mPaint.setColor(mColors[i]);
                canvas.drawCircle(p.x, p.y, DIAM, mPaint);
            }
        }
        
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            int x = (int) event.getX();
            int y = (int) event.getY();
            addPoint(x, y);
            return super.onTouchEvent(event);
        }
    }
}