Запись журналов Android в текстовый файл

129

Я пытаюсь записывать журналы в пользовательский файл Log.txt в файле Android, используя этот код Mine, но затем этот метод создает файл, но ничего не содержит. В основном я хочу прочитать предыдущее содержимое файла, а затем добавить свои данные к существующему содержимому.

Кодекс выглядит следующим образом:

public static void write(String str) 
    {
        InputStream fileInputStream = null;
        FileOutputStream fileOutpurStream = null;
        try
        { 
            fileInputStream = new FileInputStream(file);
            fileOutpurStream = new FileOutputStream(file);
            if(file.exists())
            {
                int ch = 0;
                int current = 0;
                StringBuffer buffer = new StringBuffer();
                while((ch = fileInputStream.read()) != -1)
                {
                    buffer.append((char) ch);
                    current++;
                }
                byte data[]=new byte[(int)file.length()];
                fileInputStream.read(data);   
                fileOutpurStream.write(data);
                fileOutpurStream.write(str.getBytes(),0,str.getBytes().length);
                fileOutpurStream.flush();
            } 
            else
            {   
                file.createNewFile();
                fileOutpurStream.write(str.getBytes(),0,str.getBytes().length);
                fileOutpurStream.flush();
            }
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
        finally
        {
            try
            {
                fileInputStream.close();
                fileOutpurStream.flush();
                fileOutpurStream.close();
                fileOutpurStream = null;
                fileInputStream = null;
            }
            catch (IOException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
у Рамеш рао
источник

Ответы:

247

Надеюсь, это поможет ...

public void appendLog(String text)
{       
   File logFile = new File("sdcard/log.file");
   if (!logFile.exists())
   {
      try
      {
         logFile.createNewFile();
      } 
      catch (IOException e)
      {
         // TODO Auto-generated catch block
         e.printStackTrace();
      }
   }
   try
   {
      //BufferedWriter for performance, true to set append to file flag
      BufferedWriter buf = new BufferedWriter(new FileWriter(logFile, true)); 
      buf.append(text);
      buf.newLine();
      buf.close();
   }
   catch (IOException e)
   {
      // TODO Auto-generated catch block
      e.printStackTrace();
   }
}
outkkast
источник
83
Не забудьте добавить разрешение на запись_external_storage в Manifest!
virusss8
5
Мне нужно было добавить buf.flush (); beforebuf.close (); но функция tjis была именно тем, что мне было нужно. спасибо
Csabi 06
1
откуда я должен вызвать эту функцию, чтобы она записывала журнал всего приложения в файл ???
uniruddh
10
Я бы рекомендовал реструктурировать код так, чтобы buf.close()он находился внутри finallyблока.
Уильям Прайс,
2
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />это, конечно, то, что имел в виду @ virusss8.
Bengt
29

Для тех, кто плохо знаком с ведением журнала Java в целом и ведением журнала Android

  1. Log4j - это общая реализация ведения журналов Java, которая теперь является проектом программного обеспечения Apache. Он не специфичен для Android и поэтому имеет некоторые несовместимости с Android.
  2. SL4J - это не реализация журналирования, это уровень абстракции. Это помогает избежать ситуаций, когда каждая сторонняя библиотека зависит от проекта, пытаясь использовать собственную реализацию ведения журнала, такую ​​как Log4j. Источник .

Ниже приведены некоторые варианты входа в txt в Android.

  1. Используйте, logcat -fкак в этом ответе, чтобы войти в файл. Обратите внимание, что с Android 4.2 разрешение READ_LOGS не оказывает никакого влияния, и каждое приложение (если телефон не рутирован) может читать только свои собственные журналы. Недостатком здесь является то, что буфер logcat является кольцевым и имеет ограничение по размеру. Вы можете не получить более ранние журналы.
  2. Используйте microlog4android (написанный для мобильных устройств, таких как Android), как в предыдущем ответе . Возможен способ, но я не мог понять, как использовать microlog4Android для входа во внутреннее хранилище приложения. Единственным вариантом для пути к журналам было внешнее хранилище, такое как sdcard, поэтому я не мог его использовать.
  3. Используйте Log4j с android-logging-log4j . Что делает android-logging-log4j? Это упрощает использование Log4j в Android, предоставляя две функции.

    • возможность отправлять журналы в logcat в дополнение к файлу журнала
    • простой способ установить параметры конфигурации Log4j, такие как путь к файлу, максимальный размер файла, количество резервных копий и т. д., предоставив класс LogConfigurator.

    Простой пример ниже. Обратите внимание, что loggerобъект в приведенном ниже примере является возвращенным объектом Log4j, а не классом android-logging-log4j. Таким образом, android-logging-log4j используется только для настройки Log4j.

  4. Еще предстоит попробовать LogBack . LogBack разработан тем же человеком, который придумал библиотеки Log4J 1.x и SL4J. Однако не имеет отношения к Log4j 2.x.

Шаги по использованию Log4j в Android.

  1. Добавьте log4j-1.2.x.jar и android-logging-log4j-1.0.3.jar в папку libs.

  2. Добавляйте разрешения только при использовании внешнего хранилища
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

  3. Написать Log4jвспомогательный класс

    package com.example.logger;
    
    import android.os.Environment;
    import de.mindpipe.android.logging.log4j.LogConfigurator;
    
    public class Log4jHelper {
        private final static LogConfigurator mLogConfigrator = new LogConfigurator();
    
        static {
            configureLog4j();
        }
    
        private static void configureLog4j() {
            String fileName = Environment.getExternalStorageDirectory() + "/" + "log4j.log";
            String filePattern = "%d - [%c] - %p : %m%n";
            int maxBackupSize = 10;
            long maxFileSize = 1024 * 1024;
    
            configure( fileName, filePattern, maxBackupSize, maxFileSize );
        }
    
        private static void configure( String fileName, String filePattern, int maxBackupSize, long maxFileSize ) {
            mLogConfigrator.setFileName( fileName );
            mLogConfigrator.setMaxFileSize( maxFileSize );
            mLogConfigrator.setFilePattern(filePattern);
            mLogConfigrator.setMaxBackupSize(maxBackupSize);
            mLogConfigrator.setUseLogCatAppender(true);
            mLogConfigrator.configure();
    
        }
    
        public static org.apache.log4j.Logger getLogger( String name ) {
            org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger( name );
            return logger;
        }
    }
  4. В классе активности

    org.apache.log4j.Logger log= Log4jHelper.getLogger( "YourActivity" );
    log.error("Error");
    log.info("Info");
    log.warn("Warn");

Пример источника . Обратите внимание, что log4j 2.x (улучшенная функциональность), переписанный с нуля, не поддерживает обратную совместимость с log4j 1.x. Итак, вам нужно использовать jar-файл log4j 1.2.x с jar-файлом android-logging-log4j. Мне удалось войти во внутренний файл приложения, а затем отправить файл по электронной почтеsetReadable(true, false)

Киран
источник
24

microlog4android у меня работает, но документация оставляет желать лучшего. Все, что им нужно добавить, - это краткое руководство .

Вот краткое руководство, которое я нашел.

  1. Добавьте следующую статическую переменную в свое основное действие:

    private static final Logger logger = LoggerFactory.getLogger();
  2. Добавьте в свой onCreate()метод следующее:

    PropertyConfigurator.getConfigurator(this).configure();
  3. Создайте файл с именем microlog.propertiesи сохраните его в assetsкаталоге

  4. Отредактируйте microlog.propertiesфайл следующим образом:

    microlog.level=DEBUG
    microlog.appender=LogCatAppender;FileAppender
    microlog.formatter=PatternFormatter
    microlog.formatter.PatternFormatter.pattern=%c [%P] %m %T
  5. Добавьте такие операторы регистрации:

    logger.debug("M4A");

Для каждого класса вы создаете объект регистратора, как указано в 1)

6. Вы можете добавить следующее разрешение:

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

Вот источник учебника

Генри Беннетт
источник
4
FileAppender создаст файл «microlog.txt» на вашей SD-карте (полный путь в моем случае - «/sdcard/microlog.txt»)
Руслан Янчишин
2
Это краткое руководство должно быть частью официальной документации Microlog4Android.
Йохан Карлссон
Ошибка: Android Dex: [проект] com.android.dex.Dexception: несколько файлов dex определяют Lcom / google / code / microlog4android / Level; ?
10

Предупреждение: возможно, я вас неправильно понимаю, но если вам нужен только файл журнала, зачем беспокоиться?

Поместите это в файл bat (измените путь к каталогу инструментов, и yourappname, конечно же, будет именем вашего приложения):

cd "C:\devAndroid\Software\android-sdk-windows-1.6_r1\android-sdk-windows-1.6_r1\tools"
adb logcat -v time   ActivityManager:W  yourappname:D  *:W >"C:\devAndroid\log\yourappname.log"

Затем в вашем коде просто сделайте что-то подобное:

Log.d("yourappname", "Your message");

Чтобы создать журнал, подключите USB-кабель и запустите файл bat.

С уважением

BeMeCollective
источник
Не забудьте импортировать android.util.Log.
Spidey
Он возвращает «ошибка: более одного устройства и эмулятора - ожидание устройства -» и ничего более. Что-то не так?
eros
20
Как это работает, если во время работы приложения вы не находитесь рядом с ПК?
DDSports
@DDSports это не так. Но он не понял сути вопроса
Эвоки
@DDSports вы можете использовать adb через Wi-Fi.
Daniel F
8

Используйте slf4android lib.
Это простая реализация slf4j api с использованием android java.util.logging. *.

Особенности:

  • запись в файл из коробки
  • вход в любой другой пункт назначения LoggerConfiguration.configuration().addHandlerToLogger
  • встряхните устройство, чтобы отправить журналы со снимками экрана по электронной почте
  • очень маленький, он занимает всего ~ 55 КБ

slf4android поддерживается в основном @miensol .

Подробнее о slf4android читайте в нашем блоге:

Klimat
источник
7

Вам следует взглянуть на microlog4android. У них есть готовое решение для входа в файл.

http://code.google.com/p/microlog4android/

Дарий
источник
12
Кажется, это хорошая библиотека, но документация ужасна. Я просто не мог понять, как заставить это работать, и в итоге собрал что-то сам.
Paul Lammertsma 06
@PaulLammertsma: Я думаю, было бы неплохо, если бы вы внесли свой вклад в Microlog4Android вместо этого. К вашему сведению: он имеет тот же API, что и Log4j. Извините за плохую документацию.
Йохан Карлссон
@Paul Lammertsma Как может НИЧЕГО быть хорошим, если документация настолько плоха, что вы не можете ее использовать? Если не получается заставить его работать - это чушь.
Невероятный
7

Это может быть поздно, но надеюсь, что это поможет ... Попробуйте ...

public void writefile()
    {
        File externalStorageDir = Environment.getExternalStorageDirectory();
        File myFile = new File(externalStorageDir , "yourfilename.txt");

        if(myFile.exists())
        {
           try
           {

        FileOutputStream fostream = new FileOutputStream(myFile);
        OutputStreamWriter oswriter = new OutputStreamWriter(fostream); 
        BufferedWriter bwriter = new BufferedWriter(oswriter);   
        bwriter.write("Hi welcome ");
        bwriter.newLine();            
        bwriter.close(); 
        oswriter.close(); 
        fostream.close();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }
        else
        {
            try {
                myFile.createNewFile();
            }
            catch (IOException e) 
            {
                e.printStackTrace();
            }
        }

здесь bfwritter.newlineзаписывает ваш текст в файл. И добавляем разрешение

 <uses-permission android:name = "android.permission.WRITE_EXTERNAL_STORAGE"/>

в вашем файле манифеста в обязательном порядке.

AndroidOptimist
источник
6

Я решил эту проблему с помощью следующего фрагмента кода в командной строке:

File outputFile = new File("pathToFile"); 
Runtime.getRuntime().exec("logcat -c");
Runtime.getRuntime().exec("logcat -v time -f " + outputFile.getAbsolutePath())

Параметр «время» добавляет сведения о поле метаданных для даты, времени вызова, приоритета / тега и PID процесса, отправившего сообщение.

Затем в своем коде просто сделайте что-то подобное (используя android.util.Log):

Log.d("yourappname", "Your message");
Новая звезда
источник
4
Хорошо работает при adbподключении, но не работает, когда устройство находится в автономном режиме. Я бы не стал использовать его в производстве, но это простое решение в режиме отладки.
Жюльен Кронегг
2

В общем, перед открытием потока у вас должен быть дескриптор файла. У вас есть дескриптор fileOutputStream перед createNewFile () в блоке else. Поток не создает файл, если он не существует.

Не совсем для Android, но для этой цели требуется много ввода-вывода. Что, если вы выполните много операций "записи" одну за другой? Вы будете читать все содержимое и записывать все содержимое, отнимая время и, что более важно, время автономной работы.

Я предлагаю использовать java.io.RandomAccessFile, seek () до конца, а затем writeChars () для добавления. Это будет намного более чистый код и, вероятно, намного быстрее.

Nate
источник
2

Я создал простой и легкий класс (около 260 LoC), который расширяет стандартную реализацию android.util.Log за счет ведения журнала на основе файлов:
журнала на каждое сообщение журнала регистрируется через android.util.Log, а также записывается в текстовый файл на устройстве.

Вы можете найти его на github:
https://github.com/volkerv/FileLog

Волкер Вокинг
источник
1
не так ли, нам нужно убедиться, что файловые операции не выполняются в потоке пользовательского интерфейса. Если у нас есть огромное количество файловых журналов?
Jayshil Dave
2

После долгих исследований я обнаружил, что:

  • android.util.Log по умолчанию использовать java.util.logging.Logger
  • LogCat использует loggerс именем "", чтобы получить его экземпляр, используйтеLogManager.getLogManager().getLogger("")
  • Android Devices добавляет в LogCat loggerэкземпляр com.android.internal.logging.AndroidHandlerпосле запуска отладочных приложений
  • Но!!! com.android.internal.logging.AndroidHandlerвыводит сообщения в logcat только с уровнями выше, java.util.logging.Level.INFOнапример ( Level.INFO, Level.WARNING, Level.SEVERE, Level.OFF)

Итак, чтобы писать журналы в файл, просто rootLogger "" добавьте java.util.logging.FileHandler:

  class App : Application{
    override fun onCreate() {
      super.onCreate()
      Log.d(TAG, printLoggers("before setup"))

      val rootLogger = java.util.logging.LogManager.getLogManager().getLogger("")
      val dirFile = destinationFolder
      val file = File(dirFile,"logFile.txt")
      val handler = java.util.logging.FileHandler(file.absolutePath, 5* 1024 * 1024/*5Mb*/, 1, true)
      handler.formatter = AndroidLogFormatter(filePath = file.absolutePath)

      rootLogger?.addHandler(handler)

      Log.d(TAG, printLoggers("after setup"))
    }
  }

val destinationFolder: File
        get() {
            val parent = 
                Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).absoluteFile
            val destinationFolder = File(parent, "MyApp")
            if (!destinationFolder.exists()) {
                destinationFolder.mkdirs()
                destinationFolder.mkdir()
            }
            return destinationFolder
        }
class AndroidLogFormatter(val filePath: String = "", var tagPrefix: String = "") : Formatter() {

    override fun format(record: LogRecord): String {
        val tag = record.getTag(tagPrefix)
        val date = record.getDate()
        val level = record.getLogCatLevel()
        val message = record.getLogCatMessage()
        return "$date $level$tag: $message\n"
    }
}

fun LogRecord.getTag(tagPrefix: String): String {
    val name = loggerName
    val maxLength = 30
    val tag = tagPrefix + (if (name.length > maxLength) name.substring(name.length - maxLength) else name)
    return tag
}

fun LogRecord.getDate(): String? {
    return Date(millis).formatedBy("yyyy-MM-dd HH:mm:ss.SSS")
}

fun Date?.formatedBy(dateFormat: String): String? {
    val date = this
    date ?: return null
    val writeFormat = SimpleDateFormat(dateFormat, Locale.getDefault()) //MM в HH:mm
    return writeFormat.format(date)
}

fun LogRecord.getLogCatMessage(): String {
    var message = message

    if (thrown != null) {
        message += Log.getStackTraceString(thrown)
    }
    return message
}

fun Int.getAndroidLevel(): Int {
    return when {
        this >= Level.SEVERE.intValue() -> { // SEVERE
            Log.ERROR
        }
        this >= Level.WARNING.intValue() -> { // WARNING
            Log.WARN
        }
        this >= Level.INFO.intValue() -> { // INFO
            Log.INFO
        }
        else -> {
            Log.DEBUG
        }
    }
}

fun LogRecord.getLogCatLevel(): String {
    return when (level.intValue().getAndroidLevel()) {
        Log.ERROR -> { // SEVERE
            "E/"
        }
        Log.WARN -> { // WARNING
            "W/"
        }
        Log.INFO -> { // INFO
            "I/"
        }
        Log.DEBUG -> {
            "D/"
        }
        else -> {
            "D/"
        }
    }
}

fun getLoggerLevel(level: Int): Level {
    return when (level) {
        Log.ERROR -> { // SEVERE
            Level.SEVERE
        }
        Log.WARN -> { // WARNING
            Level.WARNING
        }
        Log.INFO -> { // INFO
            Level.INFO
        }
        Log.DEBUG -> {
            Level.FINE
        }
        else -> {
            Level.FINEST
        }
    }
}

Чтобы распечатать все регистраторы в вашем приложении, используйте:

Log.e(TAG, printLoggers("before setup"))

 private fun printLoggers(caller: String, printIfEmpty: Boolean = true): String {
        val builder = StringBuilder()
        val loggerNames = LogManager.getLogManager().loggerNames
        builder.appendln("--------------------------------------------------------------")
        builder.appendln("printLoggers: $caller")
        while (loggerNames.hasMoreElements()) {
            val element = loggerNames.nextElement()
            val logger = LogManager.getLogManager().getLogger(element)
            val parentLogger: Logger? = logger.parent
            val handlers = logger.handlers
            val level = logger?.level
            if (!printIfEmpty && handlers.isEmpty()) {
                continue
            }
            val handlersNames = handlers.map {
                val handlerName = it.javaClass.simpleName
                val formatter: Formatter? = it.formatter
                val formatterName = if (formatter is AndroidLogFormatter) {
                    "${formatter.javaClass.simpleName}(${formatter.filePath})"
                } else {
                    formatter?.javaClass?.simpleName
                }
                "$handlerName($formatterName)"
            }
            builder.appendln("level: $level logger: \"$element\" handlers: $handlersNames parentLogger: ${parentLogger?.name}")
        }
        builder.appendln("--------------------------------------------------------------")
        return builder.toString()
    }
NickUnuchek
источник
Здравствуй. Какая польза от использования этого "" логгера. С кастомным логгером разницы не вижу. или я что-то упускаю?
Абинс Шаджи,
1

Этот вариант намного короче

пытаться {
    окончательный путь к файлу = новый файл (
            Environment.getExternalStorageDirectory (), "DBO_logs5");
    if (! path.exists ()) {
        path.mkdir ();
    }
    Runtime.getRuntime (). Exec (
            "logcat -d -f" + путь + File.separator
                    + "dbo_logcat"
                    + ".txt");
} catch (IOException e) {
    e.printStackTrace ();
}
xoxol_89
источник
1

Вы можете использовать написанную мной библиотеку. Использовать очень просто:

Добавьте эту зависимость в свой файл gradle:

dependencies {
    compile 'com.github.danylovolokh:android-logger:1.0.2'
}

Инициализируем библиотеку в классе Application:

File logsDirectory = AndroidLogger.getDefaultLogFilesDirectory(this);
    int logFileMaxSizeBytes = 2 * 1024 * 1024; // 2Mb
    try {
        AndroidLogger.initialize(
                this,
                logsDirectory,
                "Log_File_Name",
                logFileMaxSizeBytes,
                false
                );
    } catch (IOException e) {
        // Some error happened - most likely there is no free space on the system
    }

Вот как вы используете библиотеку:

AndroidLogger.v("TAG", "Verbose Message");

А вот как получить логи:

AndroidLogger.processPendingLogsStopAndGetLogFiles(new AndroidLogger.GetFilesCallback() {
        @Override
        public void onFiles(File[] logFiles) {
            // get everything you need from these files
            try {
                AndroidLogger.reinitAndroidLogger();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    });

Вот ссылка на страницу github с дополнительной информацией: https://github.com/danylovolokh/AndroidLogger

Надеюсь, поможет.

Даниил Волох
источник
1

Многие из предыдущих версий log4j сейчас не работают (05/2019). Но вы можете использовать Hyperlog - я могу подтвердить, что он работает.

  1. Добавьте эту строку в свой проект зависимостей и синхронизации

    implementation 'com.hypertrack:hyperlog:0.0.10'
  2. Создайте новый класс приложения (создайте новый класс java и расширите Application). Затем в методе onCreate добавьте следующие строки:

    HyperLog.initialize(this);
    HyperLog.setLogLevel(Log.VERBOSE);
    
    HyperLog.getDeviceLogsInFile(this);
  3. Измените файл манифеста, чтобы определить файл приложения.

    <application
        android:name=".AppClass"
        .....
  4. Различные способы входа:

    HyperLog.d(TAG,"debug");
    HyperLog.i(TAG,"information");
    HyperLog.e(TAG,"error");
    HyperLog.v(TAG,"verbose");
    HyperLog.w(TAG,"warning");
    HyperLog.a(TAG,"assert");
    HyperLog.exception(TAG,"exception",throwable);
  5. Найдите файлы журнала. Перейдите к

    RootFolder/android/data/"appPackageName/LogFiles/
Хайдер Малик
источник
Я пробовал эту библиотеку в файле, созданном с помощью HyperLog.getDeviceLogsInFile (this); есть только последний сгенерированный журнал
mad_greasemonkey