1

LogCat当我的 Android 应用程序通过我的 Eclipse 模拟器运行时,我会获得有关它执行的反馈。

apk在我的一部真实手机上运行时,我会遇到一些不同的行为。我很好奇它是否会LogCat在手机上的某个地方生成一个文件,我也可以访问它。

最终,我想获得LogCat结果并通过支持电子邮件地址将它们通过电子邮件发送给自己。目的是允许对程序有问题的用户LogCat在遇到问题时向我发送他们的结果副本。

是否LogCat创建了一个我可以访问的文件,我可以通过电子邮件将其发送给自己吗?如果LogCat不这样做,有没有其他方法可以做到这一点?

4

1 回答 1

0

非常艰巨的任务,但希望这会有所帮助......

(做了很多复制/粘贴,所以如果我遗漏了一些重要的代码,请告诉我!我还没有测试最大 1MB 设置 - 将它放在 MainActivity.onCreate() 中也可能有意义,所以我们不要用任何日志消息来调用它,但这有效......)

其中一些来自 LogCollector,因此在应得的情况下给予信用:(https://code.google.com/p/android-log-collector/

我的 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;
}

自定义 Logger 类:(处理我的所有日​​志记录 - 如果启用了调试选项,也会写入文件)

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();
    }           
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

}

我的实用程序类中的重要方法:

// 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 回答