ACRA: Как записать отчет ACRA в файл (на SD-карту)?

Я могу использовать библиотеку ACRA для управления ошибкой принудительного закрытия путем обработки неперехваченного исключения. Отчет может быть успешно отправлен в документ Google, электронную почту и настраиваемую веб-службу.

Но что я хочу..

  • Как записать отчет в файл [например. SD-карта/myapp/myLog.txt] ?

зачем мне это..

  • Пользователь моего приложения может не иметь подключения к Интернету во время принудительного закрытия.. если это так, то я пропущу отчет, если я запишу отчет в файл, то я смогу отправить его на свой сервер, когда будет доступно подключение к Интернету.

person Jayabal    schedule 23.01.2012    source источник


Ответы (4)


Думаю, то, чего вы хотите добиться, АКРА уже сделало. Вот что я вижу в своем abd logcat:

01-23 12:15:28.056: D/ACRA(614): Writing crash report file.
01-23 12:15:28.136: D/ACRA(614): Mark all pending reports as approved.
01-23 12:15:28.136: D/ACRA(614): Looking for error files in /data/data/com.ybi/files
01-23 12:15:28.136: V/ACRA(614): About to start ReportSenderWorker from #handleException
01-23 12:15:28.146: D/ACRA(614): Add user comment to null
01-23 12:15:28.146: D/ACRA(614): #checkAndSendReports - start
01-23 12:15:28.146: D/ACRA(614): Looking for error files in /data/data/com.ybi/files

Первое, что делает ACRA, — создает отчет о файле во внутренней памяти вашего приложения. Затем, если вы находитесь в сети и errorreporter правильно инициализирован, он отправляет отчет. В противном случае отчеты сохраняются в хранилище данных (для последующей отправки).

Я не просматривал данные, но в настоящее время я работаю над пользовательским регистратором. Итак, если вы хотите делать то же самое, что и ACRA, это легко:

    ACRA.init(this);

    // a custom reporter for your very own purposes
    ErrorReporter.getInstance().setReportSender(new LocalReportSender(this));

А потом :

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import org.acra.ACRA;
import org.acra.CrashReportData;
import org.acra.ReportField;
import org.acra.sender.ReportSender;
import org.acra.sender.ReportSenderException;

import android.content.Context;

import de.akquinet.android.androlog.Log;

public class LocalReportSender implements ReportSender {

private final Map<ReportField, String> mMapping = new HashMap<ReportField, String>() ;
private FileOutputStream crashReport = null; 

public LocalReportSender(Context ctx) {
    // the destination
    try {
        crashReport = ctx.openFileOutput("crashReport", Context.MODE_WORLD_READABLE);
    } catch (FileNotFoundException e) {
        Log.e("TAG", "IO ERROR",e);
    }
}

@Override
public void send(CrashReportData report) throws ReportSenderException {

    final Map<String, String> finalReport = remap(report);

    try {
        OutputStreamWriter osw = new OutputStreamWriter(crashReport);

        Set set = finalReport.entrySet();
        Iterator i = set.iterator();

        while (i.hasNext()) {
            Map.Entry<String,String> me = (Map.Entry) i.next();
            osw.write("[" + me.getKey() + "]=" + me.getValue());
        }

        osw.flush();
        osw.close();
    } catch (IOException e) {
        Log.e("TAG", "IO ERROR",e);
    }

}

private static boolean isNull(String aString) {
    return aString == null || ACRA.NULL_VALUE.equals(aString);
}

private Map<String, String> remap(Map<ReportField, String> report) {

    ReportField[] fields = ACRA.getConfig().customReportContent();
    if (fields.length == 0) {
        fields = ACRA.DEFAULT_REPORT_FIELDS;
    }

    final Map<String, String> finalReport = new HashMap<String, String>(
            report.size());
    for (ReportField field : fields) {
        if (mMapping == null || mMapping.get(field) == null) {
            finalReport.put(field.toString(), report.get(field));
        } else {
            finalReport.put(mMapping.get(field), report.get(field));
        }
    }
    return finalReport;
}

}

Я еще не полностью протестировал его, но вы поняли идею. Надеюсь, поможет.

person Gomoku7    schedule 23.01.2012
comment
большое спасибо, user1102206, у вас есть идея, как мы можем отправить те треки, которые записаны в файле, чтобы разорвать, нажав кнопку в действии после перезапуска [переоткрыть приложение]?. вместо автоматической отправки отчета. Требование: после полного тестирования. пожалуйста, обновите ответ. потому что по этому поводу не найдено хороших сообщений ... так что это будет более полезно и для других.. - person Jayabal; 23.01.2012
comment
Спасибо байя. Что касается вашего первоначального вопроса об ACRA, первый ответ на ваш вопрос: если ваше приложение выйдет из строя, ACRA самостоятельно справится с доступностью интернет-соединения, нет необходимости делать это вручную. Об отправке отчета кое-что доступно на веб-сайте acra (здесь: code.google.com/p/acra/source/browse/trunk/acra/src/main/java/). Код выше, кстати, вдохновлен одним классом. Когда я сказал, что полностью протестировано, я имею в виду предельные случаи: на устройстве не осталось места для отчета, нет прав на запись на SD-карту, неправильно настроена конфигурация acra и т. д. - person Gomoku7; 23.01.2012
comment
Устаревшее решение, пожалуйста, смотрите ответ @user2302510 - person dayanruben; 20.02.2015

Я предполагаю, что ответ от @Gomoku7 содержит некоторый устаревший код, поэтому я просто опубликую решение, которое я использовал:

Вызовите это в onCreate():

ACRA.init(this);
ACRA.getErrorReporter().setReportSender(new LocalReportSender(this));

Здесь я в основном изменил код, чтобы использовать BufferedWriter, чтобы я мог писать напрямую на SD-карту, что было невозможно с openFileOutput(). Поэтому слегка изменены только метод send() и конструктор LocalReportSender().

Примечание. Имейте в виду, что файл журнала растет довольно быстро, поэтому убедитесь, что вы не занимаете МБ места на SD-карте вашего пользователя из-за файла журнала :)

private class LocalReportSender implements ReportSender {

    private final Map<ReportField, String> mMapping = new HashMap<ReportField, String>();
    private FileWriter crashReport = null;

    public LocalReportSender(Context ctx) {
        // the destination
        File logFile = new File(Environment.getExternalStorageDirectory(), "log.txt");

        try {
            crashReport = new FileWriter(logFile, true);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void send(CrashReportData report) throws ReportSenderException {
        final Map<String, String> finalReport = remap(report);

        try {
            BufferedWriter buf = new BufferedWriter(crashReport);

            Set<Entry<String, String>> set = finalReport.entrySet();
            Iterator<Entry<String, String>> i = set.iterator();

            while (i.hasNext()) {
                Map.Entry<String, String> me = (Entry<String, String>) i.next();
                buf.append("[" + me.getKey() + "]=" + me.getValue());
            }

            buf.flush();
            buf.close();
        } catch (IOException e) {
            Log.e("TAG", "IO ERROR", e);
        }
    }

    private boolean isNull(String aString) {
        return aString == null || ACRAConstants.NULL_VALUE.equals(aString);
    }

    private Map<String, String> remap(Map<ReportField, String> report) {

        ReportField[] fields = ACRA.getConfig().customReportContent();
        if (fields.length == 0) {
            fields = ACRAConstants.DEFAULT_REPORT_FIELDS;
        }

        final Map<String, String> finalReport = new HashMap<String, String>(
                report.size());
        for (ReportField field : fields) {
            if (mMapping == null || mMapping.get(field) == null) {
                finalReport.put(field.toString(), report.get(field));
            } else {
                finalReport.put(mMapping.get(field), report.get(field));
            }
        }
        return finalReport;
    }

}
person user1071762    schedule 19.06.2014
comment
Спасибо! Это сработало для меня с блочной копией отсюда и с затмением, исправляющим отсутствующий импорт. Записанный файл идет в корень sdcard, и весит 27к. Настоятельно рекомендуется! - person Stephen Hosking; 02.12.2014

Я использовал ACRA, но не в таком виде (используется для отправки журналов на мой собственный сервер), поэтому я не уверен, как это сделать.
Но в таком случае вы не можете получить системные журналы целиком (которые будет, конечно, подробный) с использованием других libs/apis и записать его в файл.

ИЛИ, что вы можете сделать, так это использовать код ACRA zip и немного изменить его, например, с помощью файл "CrashReportData.java" или "CrashReporterDialog.java" в своем пакете и получите оттуда содержимое и сохраните его в свой файл.

Я говорю о его версии 4.2.3.

person akkilis    schedule 23.01.2012

решение выше работает отлично. Вероятно, есть только одно, Если файл не виден с помощью проводника, попробуйте добавить трансляцию намерения в Intent.ACTION_MEDIA_SCANNER_SCAN_FILE

проверьте эту ссылку

person volt    schedule 30.12.2014