Запишите все исключения в файл - PullRequest
0 голосов
/ 17 декабря 2018

Я использую Timber для записи некоторых логов в файл, который находится на устройстве.На данный момент я пишу выбранные журналы и некоторые ответы от сервера, используя перехватчик HTTP.Но я хочу записать в файл все исключения (роковые, например).Возможно ли это с Timber или другой библиотекой?

Пока я использую Fabric, но мое приложение не всегда имеет подключение к Интернету с внешним миром

PS Я хочу написать ВСЕ фатальные исключения без попытки/ catch

TimberLooger.class

public class FileLoggingTree
{
    /**
     * Sends an error message to LogCat and to a log file.
     * @param context The context of the application.
     * @param logMessageTag A tag identifying a group of log messages. Should be a constant in the
     *                      class calling the logger.
     * @param logMessage The message to add to the log.
     */
    public static void e(Context context, String logMessageTag, String logMessage)
    {
        if (!Log.isLoggable(logMessageTag, Log.ERROR))
            return;

        int logResult = Log.e(logMessageTag, logMessage);
        if (logResult > 0)
            logToFile(context, logMessageTag, logMessage);
    }

    /**
     * Sends an error message and the exception to LogCat and to a log file.
     * @param context The context of the application.
     * @param logMessageTag A tag identifying a group of log messages. Should be a constant in the
     *                      class calling the logger.
     * @param logMessage The message to add to the log.
     * @param throwableException An exception to log
     */
    public static void e
    (Context context, String logMessageTag, String logMessage, Throwable throwableException)
    {
        if (!Log.isLoggable(logMessageTag, Log.ERROR))
            return;

        int logResult = Log.e(logMessageTag, logMessage, throwableException);
        if (logResult > 0)
            logToFile(context, logMessageTag,
                    logMessage + "\r\n" + Log.getStackTraceString(throwableException));
    }

// The i and w method for info and warning logs
// should be implemented in the same way as the e method for error logs.

    /**
     * Sends a message to LogCat and to a log file.
     * @param context The context of the application.
     * @param logMessageTag A tag identifying a group of log messages. Should be a constant in the
     *                      class calling the logger.
     * @param logMessage The message to add to the log.
     */
    public static void v(Context context, String logMessageTag, String logMessage)
    {
        // If the build is not debug, do not try to log, the logcat be
        // stripped at compilation.
        if (!BuildConfig.DEBUG || !Log.isLoggable(logMessageTag, Log.VERBOSE))
            return;

        int logResult = Log.v(logMessageTag, logMessage);
        if (logResult > 0)
            logToFile(context, logMessageTag, logMessage);
    }

    /**
     * Sends a message and the exception to LogCat and to a log file.
     * @param logMessageTag A tag identifying a group of log messages. Should be a constant in the
     *                      class calling the logger.
     * @param logMessage The message to add to the log.
     * @param throwableException An exception to log
     */
    public static void v
    (Context context,String logMessageTag, String logMessage, Throwable throwableException)
    {
        // If the build is not debug, do not try to log, the logcat be
        // stripped at compilation.
        if (!BuildConfig.DEBUG || !Log.isLoggable(logMessageTag, Log.VERBOSE))
            return;

        int logResult = Log.v(logMessageTag, logMessage, throwableException);
        if (logResult > 0)
            logToFile(context, logMessageTag,
                    logMessage + "\r\n" + Log.getStackTraceString(throwableException));
    }

// The d method for debug logs should be implemented in the same way as the v method for verbose logs.

    /**
     * Gets a stamp containing the current date and time to write to the log.
     * @return The stamp for the current date and time.
     */
    private static String getDateTimeStamp()
    {
        Date dateNow = Calendar.getInstance().getTime();
        // My locale, so all the log files have the same date and time format
        return (DateFormat.getDateTimeInstance
                (DateFormat.SHORT, DateFormat.SHORT, Locale.CANADA_FRENCH).format(dateNow));
    }

    /**
     * Writes a message to the log file on the device.
     * @param logMessageTag A tag identifying a group of log messages.
     * @param logMessage The message to add to the log.
     */
    private static void logToFile(Context context, String logMessageTag, String logMessage)
    {
        try
        {
            // Gets the log file from the root of the primary storage. If it does
            // not exist, the file is created.
            File logFile = new File(Environment.getRootDirectory(),
                    "TestApplicationLog.txt");
            if (!logFile.exists())
                logFile.createNewFile();
            // Write the message to the log with a timestamp
            BufferedWriter writer = new BufferedWriter(new FileWriter(logFile, true));
            writer.write(String.format("%1s [%2s]:%3s\r\n",
                    getDateTimeStamp(), logMessageTag, logMessage));
            writer.close();
            // Refresh the data so it can seen when the device is plugged in a
            // computer. You may have to unplug and replug to see the latest
            // changes
            MediaScannerConnection.scanFile(context,
                    new String[] { logFile.toString() },
                    null,
                    null);
        }
        catch (IOException e)
        {
            Log.e("com.cindypotvin.Logger", "Unable to log exception to file.");
        }
    }
}

TimberLogger.class

public class TimberLooger extends Timber.DebugTree {
    private static final String TAG = FileLoggingTree.class.getSimpleName();

    private Context context;

    public TimberLooger(Context context) {
        this.context = context;
    }

    @Override
    protected void log(int priority, String tag, String message, Throwable t) {

        try {

            File direct = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/FileLocation");

            if (!direct.exists()) {
                direct.mkdir();
            }

            String fileNameTimeStamp = new SimpleDateFormat("dd-MM-yyyy", Locale.getDefault()).format(new Date());
            String logTimeStamp = new SimpleDateFormat("E MMM dd yyyy 'at' hh:mm:ss:SSS aaa", Locale.getDefault()).format(new Date());

            String fileName = fileNameTimeStamp + ".html";

            File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/FileLocation" + File.separator + fileName);

            file.createNewFile();

            if (file.exists()) {

                OutputStream fileOutputStream = new FileOutputStream(file, true);

                fileOutputStream.write(("<p style=\"background:lightgray;\"><strong style=\"background:lightblue;\">&nbsp&nbsp" + logTimeStamp + " :&nbsp&nbsp</strong>&nbsp&nbsp" + message + "</p>").getBytes());
                fileOutputStream.close();

            }

            //if (context != null)
            //MediaScannerConnection.scanFile(context, new String[]{file.getAbsolutePath()}, null, null);

        } catch (Exception e) {
            Log.e(TAG, "Error while logging into file : " + e);
        }
    }
}

1 Ответ

0 голосов
/ 17 декабря 2018

Да, возможно использовать Timber для записи ваших исключений в файл.Для этого вам нужно создать собственное дерево Timber, как в примере ниже (In Kotlin):

import timber.log.Timber

class FileLogTree : Timber.Tree() {

    override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {

        if (priority == Log.ERROR) {
            try {
                val directory = Environment.getExternalStoragePublicDirectory("${Environment.DIRECTORY_DOCUMENTS}/logs")

                if (!directory.exists())
                    directory.mkdirs()

                val fileName = "myLog.txt"

                val file = File("${directory.absolutePath}${File.separator}$fileName")

                file.createNewFile()

                if (file.exists()) {
                    val fos = FileOutputStream(file, true)

                    fos.write("$message\n".toByteArray(Charsets.UTF_8))
                    fos.close()
                }

            } catch (e: IOException){
                Log.println(Log.ERROR,"FileLogTree", "Error while logging into file: $e")
            }
        }
    }
}

Позже, в процессе инициализации Timber, установите это дерево:

Timber.plant(FileLogTree())

В этом примере Timber запишет все журналы "Timber.e ()" в файл с именем "myLog.txt" в папке документов / журналов.

Вам также понадобится разрешение WRITE_EXTERNAL_STORAGEчтобы это пользовательское дерево работало.Вы можете прочитать больше о получении этого разрешения на этом ответе .

Что касается части "получить все исключения", вам нужно будет создать собственный обработчик Uncaught Exception и изменить значение по умолчанию Thread.UncaughtExceptionHandler как только ваша заявка (или действия) начинается.Для этого позвоните: Thread.setDefaultUncaughtExceptionHandler(new YourExceptionHandler(context));.Внутри этого обработчика вы можете выбрать, что делать с исключением (например, вызов Timber.e()).

Проверьте этот ответ , чтобы узнать больше о том, как реализовать это.Кроме того, вы можете взглянуть на эту ссылку , этот парень сделал один из тех обработчиков, чтобы получить эти сбои.Вы можете использовать это с вашим собственным деревом, чтобы сохранить детали в вашем лог-файле.

...