1

LogCat私は、Eclipse エミュレーターを介して Android アプリケーションを実行したときに、その実行に関するフィードバックを得るために使用していました。

apkを実際の電話で実行すると、動作が異なります。LogCatが電話のどこかにファイルを生成し、私もアクセスできるかどうか興味があります。

最終的には、LogCat結果を取得し、サポートの電子メール アドレスを介して自分自身に電子メールで送信したいと考えています。その目的は、プログラムに問題があるユーザーが、問題が発生したLogCatときに結果のコピーを私に送信できるようにすることです。

LogCatアクセスできるファイルを作成し、それを自分宛てに電子メールで送信できますか? LogCatこれを行わない場合、これを行う別の方法はありますか?

4

1 に答える 1

0

非常に難しい作業ですが、これが役立つことを願っています...

(多くのコピー/貼り付けを行っているため、重要なコードが欠落している場合はお知らせください! 最大 1MB の設定はまだテストしていません。ログメッセージでそれを呼び出さないでください、しかしこれはうまくいきます...)

これの一部は LogCollector からのものです

私の LogCollector クラスからの関連メソッド: (明らかな入力を受け取り、ログの複数の添付ファイルをメールで送信します。両方が存在する場合、logcat と同様にログ ファイルを有効にするオプションがあります。ところで、logcat には最大 64KB のメモリがあるため、取得できません。それから多くのログが記録されるため、ファイルにログを記録する必要があります)

public boolean sendLog(String email, String subject, String body) {
    Logger.v("LogCollector - sendLog()");
    ArrayList<String> lines = mLastLogs;
    if (lines.size() > 0) {
        Uri emailUri = Uri.parse("mailto:" + email);
        ///////////////////////////////////////////////////////////////////////////////////////     
        // Create and open folder for output file
        Logger.d("LogCollector - Creating folder & file...");
        final String filename = "AppName_logCat.txt";
        File folder = new File(Environment.getExternalStorageDirectory()+"/temp/");
        // Create directory structure if needed
        if(folder.mkdirs()){
            Logger.v("Created temp folder.");  
        }else{
            Logger.v("Did NOT create temp folder - perhaps it already exists");  
        }
        //Create log file
        File logFile = new File(Environment.getExternalStorageDirectory()+"/temp/", filename);
        Logger.v("Log File Path: "+logFile.getAbsolutePath());  
        FileWriter fileWriter;
        //String phoneInfo = collectPhoneInfo();
        //String appInfo = collectAppInfo();
        //Put contents into log file, including phone info
        try {
            Logger.d("LogCollector - Putting info into log file...");
            fileWriter = new FileWriter(logFile, false);        //dont append, clear first
            BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
            //bufferedWriter.write(phoneInfo);
            //bufferedWriter.write("\n\n");
            //bufferedWriter.write(appInfo);
            bufferedWriter.write("\n\n");
            for (String line : lines) {
                    bufferedWriter.write(line);
                    bufferedWriter.newLine();
            }
            bufferedWriter.close();
        } catch (IOException e1) {
            Logger.w("LogCollector - Error putting log info into file: "+e1);
            if(!android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) {
                Logger.w("SD card not present or not accessible");
            }
            return false;
        }
        // Check if log can be read for debugging
        if(!logFile.canRead()){
            Logger.e("Can't read file!");
            return false;
        }
        // Create appLogFile objects
        appLogFile = new File(Environment.getExternalStorageDirectory()+"/temp/", appFilename);

        //Send log file via email
        Logger.d("LogCollector - Emailing Logs...");
        // Need to assemble body this way due to Android bug
        //emailIntent.putExtra(Intent.EXTRA_TEXT, body);                        //Regular method - Causes warning
        //ArrayList<String> extra_text = new ArrayList<String>();               //workaround
        //extra_text.add("See attached CSV files.");                            //workaround
        //emailIntent.putStringArrayListExtra(Intent.EXTRA_TEXT, extra_text);   //causes no error but missing body/text - not a big deal, but pointless to have if doesnt issue a body
        // Put info in email
        Intent emailIntent = new Intent(Intent.ACTION_SEND_MULTIPLE);
        emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[]{emailUri.toString()});
        emailIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
        emailIntent.setType("text/plain");
        ArrayList<Uri> uris = new ArrayList<Uri>();     
        String[] filePaths;             
        // If appLogFile exists & is valid, attach to email
        if(appLogFile.exists() && appLogFile.isFile() && appLogFile.canRead()) {
            Logger.i("appLogFile exists; attaching to email");
            filePaths = new String[] {logFile.toString(),appLogFile.toString()};
        }else{
            Logger.w("Error finding or reading logfile. Debug disabled?!");
            filePaths = new String[] {logFile.toString()};
        }
        for (String file : filePaths) {
            File fileIn = new File(file);
            Uri u = Uri.fromFile(fileIn);
            uris.add(u);
        }
        emailIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
        mContext.startActivity(Intent.createChooser(emailIntent, "Email Logs to Developer"));
    }
    return true;
}

カスタム ロガー クラス: (すべてのログを処理 - デバッグ オプションが有効な場合はファイルにも書き込みます)

public class Logger {
private static final String TAG = "AppName";
private static final int MAX_FILESIZE=1;    //in MB
private static File logFolder;
private static File logFile;
private static String filename = TAG+"_logfile.txt";
private static FileWriter fileWriter;
private static BufferedWriter bufferedWriter;
private static SimpleDateFormat sdf;
private static String dateTime;
private static int PID;
private static int TID;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public static void v(String message) {
    // Do normal logging to logcat
    Log.v(TAG,message);
    // Log to file
    if(MainActivity.enable_debug()) {
        PID= android.os.Process.myPid();
        TID=android.os.Process.myTid();
        logToFile(PID,TID,"V",message);
    }
}

public static void d(String message) {
    // Do normal logging to logcat
    Log.d(TAG,message);
    // Log to file
    if(MainActivity.enable_debug()) {
        PID= android.os.Process.myPid();
        TID=android.os.Process.myTid();
        logToFile(PID,TID,"D",message);
    }
}
public static void i(String message) {
    // Do normal logging to logcat
    Log.i(TAG,message);
    // Log to file
    if(MainActivity.enable_debug()) {
        PID= android.os.Process.myPid();
        TID=android.os.Process.myTid();
        logToFile(PID,TID,"I",message);
    }
}
public static void w(String message) {
    // Do normal logging to logcat
    Log.w(TAG,message);
    // Log to file
    if(MainActivity.enable_debug()) {
        PID= android.os.Process.myPid();
        TID=android.os.Process.myTid();
        logToFile(PID,TID,"W",message);
    }
}   
public static void e(String message) {
    // Do normal logging to logcat
    Log.e(TAG,message);
    // Log to file
    if(MainActivity.enable_debug()) {
        PID= android.os.Process.myPid();
        TID=android.os.Process.myTid();
        logToFile(PID,TID,"E",message);
    }
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@SuppressLint("SimpleDateFormat")
private static void logToFile(int PID,int TID,String LEVEL,String message) {
    //return if there is no SD card, or it's inaccessible
    if(!android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) {
        return;
    }
    // Date - Time - PID - TID - LEVEL - TAG? - Message
    // Create and initialize temp folder for log file if doesn't already exist      
    if(logFolder == null) {
        logFolder = new File(Environment.getExternalStorageDirectory()+"/temp/");
    }
    // Create temp folder if doesn't exist
    if(!logFolder.exists()) {
        //Logger.i("Creating temp folder on SD card root...");
        logFolder.mkdirs();
    }
    // Create log file if doesn't already exist
    if(logFile == null) {
        logFile = new File(Environment.getExternalStorageDirectory()+"/temp/", filename);
        try {
            logFile.createNewFile();
        } catch (IOException e) {
            Logger.e("Error creating new file: "+e);
        }
    }
    // Check log file validity - Error if there's a problem with the file
    // Not sure if this is a performance hit
    if(!logFile.exists() || !logFile.isFile() || !logFile.canRead()) {
        //Logger.e("Problem with logFile! Doesnt exist, isn't a file, or can't read it");
        return;
    }
    //Get Date/Time
    if(sdf == null) {
        sdf = new SimpleDateFormat("yyyyMMdd HH:mm:ss");    //determines dateTime format
    }
    dateTime = sdf.format(new Date());  //set to current date/time

    // Write log message to file
    try {
        if(fileWriter == null) {
            //if(size of file is > 1MB or whatever, then set below to false to clear file first?  Or need to do something better so we dont wipe mid incoming text) {
            if(logFile.length() > MAX_FILESIZE*1024*1024) {
                Logger.i("logFile is > "+MAX_FILESIZE+" MB, clearing first...");
                fileWriter = new FileWriter(logFile, false);        // true=dont append, clear first
            }else{
                fileWriter = new FileWriter(logFile, true);         // false=append, clear first
            }
        }
        if(bufferedWriter == null) {
            bufferedWriter = new BufferedWriter(fileWriter);
        }
        bufferedWriter.write(dateTime+" "+PID+" "+TID+" "+LEVEL+" "+TAG+": "+message);  //write line to log file
        bufferedWriter.newLine();
        bufferedWriter.flush();     //forces to write to file?
    } catch (IOException e) {
        Logger.e("Error writing to log: ");
        e.printStackTrace();
    }           
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

}

Utilities クラスの重要なメソッド:

// EMAIL LOGS
public static void emailLogsDialog(final Context context) {
    final AlertDialog.Builder builder = new AlertDialog.Builder(context); 
    builder.setTitle("Send Logs to Developer");
    builder.setMessage("Do you want to send your system logs to the Developer for troubleshooting?\n\nWarning: The logs may contain personal information; this is beyond the Developer's control.");
    builder.setInverseBackgroundForced(true);
    builder.setPositiveButton("Ok",new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog,int which) {
            dialog.dismiss();
            emailLogs(context);
        }
    });
    builder.setNegativeButton("Cancel",new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog,int which) {
            dialog.dismiss();
        }
    });
    AlertDialog alertConfirm = builder.create();
    alertConfirm.show();
}
public static void emailLogs(final Context context) {
    final LogCollector logCollector = new LogCollector(context);
    final AlertDialog.Builder builder = new AlertDialog.Builder(context);  
    new AsyncTask<Void, Void, Boolean>() {
        AlertDialog alert;
        @Override
        protected Boolean doInBackground(Void... params) {
            return logCollector.collect();
        }
        @Override
        protected void onPreExecute() {
            builder.setTitle("Send Logs to Developer");
            builder.setMessage("Collecting Logs & Emailing now...");
            builder.setInverseBackgroundForced(true);
            builder.setNegativeButton("Cancel",
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog,int which) {
                            dialog.dismiss();
                            return;
                        }
                    });
            alert = builder.create();
            alert.show();
        }
        @Override
        protected void onPostExecute(Boolean result) {
            alert.dismiss();
            builder.setTitle("Send Logs to Developer");
            builder.setMessage("Logs successfully sent to Developer\n\n (Make sure your email app successfully sent the email.)");
            builder.setInverseBackgroundForced(true);
            builder.setPositiveButton("Ok",
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog,int which) {
                            dialog.dismiss();
                        }
                    });
            if (result) {
                Logger.d("Successfully extracted logs.");
                if(logCollector.sendLog("ArnoldSwarteneger@gmail.com", "OnCallPager Error Log", "Error Log\n")) {
                    Toast.makeText(context,"Logs successfully extracted to your default email application",Toast.LENGTH_LONG).show();
                }else{
                    Toast.makeText(context,"There was a problem extracting the logs.\n\nDo you have an SD card and is it mounted?",Toast.LENGTH_LONG).show();
                }
            }else{
                Logger.e("Failed to extract logs!");
                Toast.makeText(context,"Error acquiring logs!",Toast.LENGTH_LONG).show();
            }
        }    
    }.execute();
}

この方法でログを呼び出します。

Logger.v("LogCollector - sendLog()");

sendEmail のキー (ログ付き): (上記で使用)

if(logCollector.sendLog("ArnoldSwarteneger@gmail.com", "OnCallPager Error Log", "Error Log\n")) {
                Toast.makeText(context,"Logs successfully extracted to your default email application",Toast.LENGTH_LONG).show();
            }else{
                Toast.makeText(context,"There was a problem extracting the logs.\n\nDo you have an SD card and is it mounted?",Toast.LENGTH_LONG).show();
            }
于 2014-01-11T08:33:41.800 に答える