Android write log to file

Логирование в Android приложениях

Уверен, что всем разработчикам приложений на платформе Android знаком класс Log, позволяющий логировать различные события. По различным причинам, формат записи логов для каждого проекта может отличаться достаточно сильно — начиная от «AAA», «111111» и «I was here» до более-менее внятных — «Opening HTTP connection to habrahabr.ru». Под катом вы найдете пример функции, которая поможет навести порядок в логах.
Данный топик не претендует на оригинальность и универсальность. И поэтому, если в вашем проекте уже существует некий стандарт логирования событий, то смело проходите мимо — топик скорее ориентирован на начинающих разработчиков.

Как правило, ценность логов начинаешь понимать только когда заказчик матерясь отсылает лог на почту и просит засабмитить фикс через 5 минут. И если лог состоит из сообщений невнятного характера, то как минимум, разбр данного лога займет куда больше времени, чем хотелось бы.

Пытаемся навести порядок

Логи существуют для того, чтобы разработчик мог понять что, где и когда произошло. Найти ответ на вопрос «когда произошло» достаточно просто — в логах Андройд записывает время события. Нахождение ответа на вопрос «что произошло» так же не вызывает больших трудностей, если сообщение в лог было написано со смыслом, например: «Opening file. ». Вопрос «где произошло» оказывается наиболее сложным. Если проект большой, то придеться потратить время на нахождение нужного места кода, даже, если лог был написан со смыслом.

Если событие логируется с указанием Throwable (чаще Exception), например, метод public static int d (String tag, String msg, Throwable tr) , то в консоле сообщений будет выведен стек, который поможет быстро идентифицировать место логирования. Но использование данного метода без особой необходимости до безобразия перегрузит лог ненужной информацией.

Если же логируется просто текст, то при логировании можно явно указывать место вызова. Например:

Однако, писать такое каждый раз — дело утомительное и неблагодарное.

Ниже приведен пример класса Log , который делает это автоматически.

Использование класса очень простое:

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

Примечание:
По понятным причинам, данный способ мало пригоден для приложений «пропущенных» через обфускатор.

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

Источник

Android: логгирование и отправка результатов на почту

Хочу начать небольшой разговор о том, как можно получать данные о работе приложения и некоторых его компонентов от пользователей.

Одно дело — разработка, LogCat в Android Studio (если вы из любителей пожестче — можно распечатку в консоли смотреть с помощью adb), и совсем другое — ломать голову над вопросом почему у вас все работает на всем парке тестовых устройств, а пользователь жалуется на абсолютно обратную ситуацию. Коммуникация между разработчиком и конечным пользователем — это хорошо, но совсем другое — видеть своими глазами картинку происходящего (помните, как в матрице — для кого-то это зеленые иероглифы, а для кого-то — женщина в красном?)

Предлагаю разбить задачу на несколько частей, а именно — сбор и хранение логов, способ их передачи из одного приложения в другие с помощью FileProvider, ну и небольшой helper класс для создания писем с аттачами. Итак, поехали.

Сбор и хранение логов.

Кто-то использует System.out.println, кто-то — статические методы класса Log. Я с некоторых пор пришел к написанию своего класса для распечатки логов. Давайте вкратце расскажу почему.

Во-первых, это проще. Как правило, для отслеживания изменений в процессе выполнения приложения я использую одну и ту же метку. И вот однажды я подумал — зачем ты пишешь постоянно Log.i(MY_TAG, «info») если можно сократить немного и убрать из этой формулы одну постоянную?

Во-вторых, расширение логгирования. Это конкретно упирается в нашу задачу — хранение логов в файлах. Можно написать отдельный класс, в который будем передавать какие-то данные, как то: данные и имя файла, но данные мы уже передаем в метод Log.i / Log.e / проч., создавать лишний раз переменную что ли для этого? Некрасиво все это как-то.

Ладно, довольно лирики, давайте лучше взглянем на класс Diagnostics.

Для того, чтобы вывести информацию в LogCat с дефолтной меткой, достаточно написать следующее:

Иногда мне хочется видеть какие методы вызываются и в каких объектах. И с какими параметрами или значениями переменных. В общем, тут важно для меня — где именно производится вызов. Тогда я использую следующую конструкцию

Diagnostics.i(this, “onCreate w/param1 = “ + param1);

где this — это экземпляр класса Caller. Например, для MainActivity вы увидите следующее:

03–29 12:31:53.203 16072–16072/com.isidroid.platform I/Diagnostics: MainActivity.onCreate w/param1 = 200

И все сразу становится понятно — кто вызывает и где вызывает.

А теперь о хранении этой информации.

Как вы уже могли видеть, в классе Diagnostics есть методы для работы с файлами — createLog и appendLog. Объяснять, я думаю, не стоит — первый создает файл, второй — добавляет в него строку. Для новичков или тех, кто ленится читать код, уточню — appendLog создает файл, если его не существует, а createLog всегда создает новый. Чтобы лишней информации там не хранилось.

Читайте также:  Android button layout width

Файлы хранятся в cache директории, которая, к слову, недоступна для других приложений (ну, если у вас телефон не рутован, конечно).

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

Надеюсь, это выглядит просто в использовании.

Передача файлов в другие приложения

Как я уже говорил выше, наши файлы для лога хранятся в некоторой защищенной от чужих глаз папке. Она настолько защищена, что если вы попробуете передать файлы в другое приложение с использованием относительного пути File.getAbsolutePath(), то вы потерпите неудачу.

На помощь к нам мчится FileProvider, друзья!

Вообще, в документации есть отличная статья (она же — пошаговая инструкция) на эту тему — Setting Up File Sharing, но для тех, кто предпочитает читать StackOverFlow и isidroid.com, я приведу выжимку из статьи с кодом реализации.

  1. Добавляем FileProvider в Manifest.

2. Указываем директории, доступные для шаринга. Для этого создаем файл res/xml/cache_file_paths и для нашего конкретного примера заполняем его.
Конец.

Нет, правда, это все.

На самом деле это довольно мощный инструмент для работы с файлами в вашем приложении, но в рамках поставленной задачи это все, что нам нужно сделать. Подробности — в официальной документации.

Отправка писем с логами.

Мы с вами почти добрались до конца, осталось дело за малым. Вообще, создание намерения (intent) для отправки писем — это довольно тривиальная задача, чтобы под нее писать отдельный хелпер. Но с другой стороны, если можно причесать код в вашей Activity / Fragment, то почему бы и нет, верно?

Гораздо симпатичнее будет выглядеть какой-нибудь строитель (builder) в коде нежели условия, проверки и лишние циклы. Я за то, чтоб это выносить в отдельный класс (кстати, не только я ратую за разделение представления от бизнес-логики).

Давайте перейдем сразу к сути. Сначала я покажу класс (который вы можете скопировать и использовать не глядя, конечно), а потом пример его использования. Поехали!

Где this — это Activity.

Вы можете самостоятельно указать «рыбу» для текста письма, но я рекомендую использовать те данные, которые указаны в методе buildContent, расширяя их при необходимости. Можно конечно извернуться и применить паттерн «декоратор» для расширения этих данных без модификации класса FeedbackHelper, но лично для меня необходимости в этом не было… Что до вас, то дерзайте!

Источник

Android Writing Logs в текстовый файл

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

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

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

Microlog4android работает для меня, но документация довольно бедна. Все, что им нужно добавить, это быстрый учебник по началу работы.

Вот быстрый учебник, который я нашел.

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

Добавьте в свой onCreate() :

Создайте файл с именем microlog.properties и сохраните его в каталоге assets

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

Добавляйте такие заявления:

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

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

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

Для тех, кто новичок в регистрации 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, и поэтому я не мог его использовать.

Используйте Log4j с android-logging-log4j . Что делает андроид-logging-log4j? Это упрощает использование Log4j в Android, предоставляя две функции.

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

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

  • Но попробовать LogBack . LogBack разработан тем же человеком, который придумал библиотеки Log4J 1.x и SL4J. Однако не связано с Log4j 2.x.
  • Читайте также:  Переводчик морзе для андроид

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

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

    Добавить разрешения только при использовании внешнего хранилища

    Запись вспомогательного класса Log4j

    В классе Activity

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

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

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

    Тогда в вашем коде просто сделайте что-то похожее на это:

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

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

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

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

    В вашем файле манифеста обязательно.

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

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

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

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

    Slf4android поддерживается главным образом @miensol .

    Узнайте больше о slf4android в нашем блоге:

    • Представляем slf4android
    • Интеграция slf4android с Crashlytics

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

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

    Источник

    Logging to disk reactively on Android

    Feb 23, 2020 · 9 min read

    Logging is not a new concept, Log.v here, Log.d there, and a Log.wtf for good measure. For anyone working on a large project, logging is often a utility that is taken for granted — generally the plumbing has already been done to ensure that logs are captured, stored, rotated, and eventually uploaded to some external service to aid with debugging.

    This past year I’ve been fortunate enoug h to have a project see enough traffic and by proxy a set of more nuanced bugs that I can no longer just find the obvious issue. Partial logs that are bundled with the Firebase Crashlytics tool no longer capture enough valuable information to deal with non-crash related events, or that pesky unexpected state that the user is in that for the life in you, you can’t seem to be able to reproduce. The point is, its no longer feasible to not have a clearer picture of what’s happening in your application when you get one of these reports. And so, it’s time to bring in the big guns.

    Logging on android is rather straightforward, you can use the regular android.util.Log class to do just about everything, the Android Studio (or terminal) Logcat utility is great at debugging information, but out of the box, the logs are not saved to disk and as a result, cannot be uploaded for remote triaging. I use Timber for logging, it’s a lightweight utility for logging which wraps the android.util.Log class for its console output but also provides abstractions of logging so that you can bake in your own custom solution.

    Prior to requiring the logs to be viewed remotely, I had two log “Trees” configured. The first was the Timber.DebugTree which performed the necessary logging to Android’s Logcat, and a custom one to log to Crashlytics, unoriginally named CrashlyticsTree . The implementation for the latter, and how the logs are viewed can be seen below:

    Writing to disk seems like a rather practical thing to do. The naive approach is to keep a reference to the filehandle and FileWriter#append(. ) all the logs, but as we perhaps all know, disk IO operations can be rather taxing to the device, not to mention that synchronous logging to disk is already problematic since it would be, by definition, a blocking operation.

    The question then becomes how do you handle logging asynchronously to disk.

    Since I was already using RxJava I decided to make use of the schedulers to defer logs to a background thread and buffer the logs before writing them to disk as a batch operation. The implementation of the Tree is as follows.

    The log collector and emitter

    The process began by first creating the Tree class as well as a PublishSubject to allow the logs to be written to and later processed from.

    Once the tree was created it was trivial to “plant” it.

    The next step was to set up a buffering technique, which Rx has built-in using the buffer. My buffering criteria was every 5 minutes or 20 log lines.

    The issue here was that I would eventually need a method of manually flushing the logs to disk once certain actions were taken, for example when the user submitted a report manually or when the application was closed.

    The solution was not quite as elegant as I would have liked. The default buffer operators did not provide an external signal argument. I opted for a simpler solution — use a manual signal to indicate that the buffer needed to be released.

    This meant that I would need to modify the buffer to accept this signal.

    Once I had the buffering ready, the next step was to write the logs to disk. This involved opening the file and appending all the buffered LogElements and then closing (and flushing) the FileWriter .

    Now that the logs were being written to disk, the next step was to build a mechanism to rotate the logs as needed. In my case, I chose to prune log files older than 14 days and rotate the logs as soon as they were larger than about 1.66 MB so that when viewing log files using gzcat, for example, they’d be fast to scroll through.

    Log rotation methodology

    Log rotation is a simple concept. Once your log file gets large enough it is “rotated” and the log files are pruned.

    I chose to keep the individual files pretty small and 1.66MB seemed like a reasonable size. The logic was modified to validate file size and rotate if required. This rotation step involved gzipping the file to reduce the file size for upload.

    The trick here was that since the writing to disk was asynchronous, I’d need to wait the operation was complete to decide to rotate the logs. This lent itself to the use of another observer which would receive a signal with the size of the current log file when the log writing operation was complete.

    I updated the logBuffer ‘s subscribe to emit the filesize to this observer.

    Next, I implemented the rotateLogs function and a helper to compress the files and clear the log file.

    and finally the logic for compressing the file:

    And that is it! Once the implementation was complete the logs were being written to disk and being rotated as expected.

    Future work

    I’ve had this implementation live for almost two months now and have been able to track down a number of issues with the help of logs submitted by users — spoiler: I’ll cover my approach to uploading to Firebase CloudStorage in another post. However, there are still a few things that I’d like to improve upon in the future, below are some of these items:

    • I’d like to consider implementing a backpressure strategy by using a PublishProcessor instead of a PublishSubject for the logBuffer . Sometimes large JSON objects are being written to logs and the buffer can quickly fill up.
    • On a related note to the above, I’d like to change the size of the Strings to smaller 1024 byte sizes to prevent possible memory-related exceptions on less powerful devices that could be holding a few hundred KBs in logs in memory.
    • Consider using Kotlin Flow in place of RxJava — as we all perhaps know, RxJava is often abused to do concurrency/asynchronous work, moving the logic to a paradigm that is better suited for the kind of work being done here might be valuable.
    • Implementing post-processing for log lines to strip out sensitive data before writing logging them to console and to disk.

    Thanks for reading and be sure to check out the example source code along with a followup post on how I handle uploading to Firebase CloudStorage in the near future.

    If you have any more feedback, comments, or if there is a glaring mistake, let me know below!

    Источник

    Читайте также:  Звук для батареи андроид
    Оцените статью