【问题标题】:Android LogCat File Location and Emailing A Copy of ItAndroid LogCat 文件位置并通过电子邮件发送其副本
【发布时间】:2019-03-03 05:54:25
【问题描述】:

我使用LogCat 在我的 Android 应用程序通过我的 eclipse 模拟器运行时获得有关它的反馈。

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

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

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

【问题讨论】:

  • 澄清一下,我在stackoverflow.com/questions/4424544/… 看到了如何使用 adb 执行此操作的参考,但有没有办法在生产中打开它并获取报告的信息?
  • “如果 LogCat 不这样做,那么任何关于替代方法的建议都将不胜感激。” -- 使用 ACRA:acra.ch,可能与您自己在 LogCat 之外的日志记录结合使用。

标签: android logcat android-file


【解决方案1】:

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

(进行了大量的复制/粘贴,所以如果我遗漏了一些重要的代码,请告诉我!我还没有测试最大 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()");

发送电子邮件的密钥(带日志):(如上所述)

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-06-14
    • 2018-12-16
    • 2016-03-10
    • 2017-10-21
    • 2015-08-25
    • 2021-07-18
    • 1970-01-01
    • 2012-04-24
    相关资源
    最近更新 更多