Домой Android разработкаJava, Kotlin и Android SDK Логирование при разработке под Android

Логирование при разработке под Android

by dilix
Поиск ошибок, логирование и Logcat

Логи в разработке очень полезны для дебага и ловли багов. Также они помогают отслеживать поведение вашего приложения, например при сетевых запросах.

Logcat. Уровни логирования.

Logcat — стандартный инструмент в Android, с помощью которого можно посмотреть dump логов с устройства или эмулятора. Скачать его можно как в составе Android Studio, так и отдельно. Для этого необходимо выкачать SDK platform tools, в которые входит утилита ADB (Android Device Bridge).

Logcat в Android studio

Открываете Android Studio и внизу видите возможность открыть Logcat.

Logcat в android studio

Прелесть использования Logcat в Android Studio в том, что в случае крешей — место ошибки кликабельно. По нажатию на строку можно перейти в исходный код.

Кликабельные строки в StackTrace

Все логи можно отфильтровать по тексту, процессу, который запускаете в режиме debug, по устройству, на котором запускаете приложение и т.д.

Hint: когда используете логи для отладки приложения, можно использовать заведомо уникальную последовательность символом. Такой подход позволит без проблем отфильтровать логи и увидеть только нужные вам строки. Я для этого использую строку «!@#» — ее легко написать (Shift + 1,2,3) и она точно уникальная в рамках Android.

Logcat в консоли

Если по каким-либо причинам вы не хотите открывать или устанавливать Android Studio, то logcat можно также запускать из командной строки (терминала). Для этого есть команда adb logcat. Убедитесь, что путь до adb добавлен в переменные окружения, иначе система скажет что она не знает такой команды.

Запуск logcat из терминала также удобен для тестировщиков. Если есть баг или креш, который нужно зафиксировать, то можно

  • Запустить команды adb logcat > my_logs.txt в консоли
  • Воспроизвести ошибку
  • Остановить выполнения логирования (например по ctrl + c)
  • Скинуть логи из файлы my_logs.txt разработчикам.

Уровни логирования в Logcat

Для удобства выделены несколько возможных уровней логирования. В зависимости от важности и критичности вывода можно использовать те или иные приоритеты:

  • Log.e(String, String) (ошибки)
  • Log.w(String, String) (предупреждения)
  • Log.i(String, String) (информация)
  • Log.d(String, String) (дебаг)
  • Log.v(String, String) (подробная информация)

Логирование как способ дебага

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

Когда используете логи для отладки приложения, можно использовать заведомо уникальную последовательность символом. Такой подход позволит без проблем отфильтровать логи и увидеть только нужные вам строки. Я для этого использую строку «!@#» — ее легко написать (Shift + 1,2,3) и она точно уникальная в рамках Android.

Расставив по участку кода, в котором потенциально находится ошибка текст

Logs.e("!@#", "Some text, var, position")

можно проследить порядок выполнения кода и промежуточные результаты.

Логи обфусцированного приложения

Если приложение обфусцировано, то логи могут содержать непонятные строки вида a.a$b. Для решения проблемы прочтения существую mapping файлы. Это специальные списки соответствия между обфусцированным кодом и исходниками. Такие файлы создаются автоматически на этапе компиляции и их можно найти в build папке вашего приложения. Их можно загрузить в Google play developer console для деобфускации stacktrace.

Логирование сетевых запросов

В большинстве случаев современное приложение использует Retrofit для доступа к сети и выполнению запросов. Для целей логирования есть специальный класс HttpLoggingInterceptor. Он позволяет настроить вывод сетевых запросов. Обычной практикой является добавление всех логов в Debug режиме.

Если мы например используем Dagger, то можно данный interceptor создавать и использовать в вашем модуле сетевого слоя:

    @Provides
    @Singleton
    @Named(LOG_INTERCEPTOR)
    fun provideLoggingInterceptor(): Interceptor =
        HttpLoggingInterceptor().apply {
            level =
                if (WHEN_TO_DISABLE_LOGS)
                    HttpLoggingInterceptor.Level.NONE
                else HttpLoggingInterceptor.Level.BODY
        }

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

        val client = OkHttpClient().newBuilder()
            .addInterceptor(connectionInterceptor)
            .addInterceptor(forceUpdateInterceptor)
            .addInterceptor(versionInterceptor)
            .addInterceptor(loggingInterceptor)
            .build()

Продвинутое логирование с Timber

В самом базовом случае обычного Android Logs будет достаточно. Когда вам перестанет хватать стандартного функционала (например захочется писать логи в разные места и в зависимости от внешней конфигурации) — присмотритесь к Timber. Это легкая, но мощная надстройка над стандартными логами. Она позволяет задавать на старте стратегию логирования. К примеру важные логи можно отправлять в Crashlytics или на ваш сторонний сервер:

public class App extends Application {

    @Override
    public void onCreate() {
        super.onCreate();

        Timber.plant(BuildConfig.DEBUG
                ? new Timber.DebugTree()
                : new CrashReportingTree());

        Fabric.with(this, new Crashlytics());

        FirebaseAnalytics.getInstance(this);
        
        // other things...

    }

    private class CrashReportingTree extends Timber.Tree {
        private static final String CRASHLYTICS_KEY_PRIORITY = "priority";
        private static final String CRASHLYTICS_KEY_TAG = "tag";
        private static final String CRASHLYTICS_KEY_MESSAGE = "message";

        @Override
        protected void log(int priority, String tag, String message, Throwable throwable) {
            if (priority == Log.VERBOSE || priority == Log.DEBUG) {
                return;
            }

            Throwable t = throwable != null
                    ? throwable
                    : new Exception(message);

            // Crashlytics
            Crashlytics.setInt(CRASHLYTICS_KEY_PRIORITY, priority);
            Crashlytics.setString(CRASHLYTICS_KEY_TAG, tag);
            Crashlytics.setString(CRASHLYTICS_KEY_MESSAGE, message);
            Crashlytics.logException(t);

            // Firebase Crash Reporting
            FirebaseCrash.logcat(priority, tag, message);
            FirebaseCrash.report(t);
        }
    }
}

Логирование — мощный инструмент, который при правильном использовании заметно ускоряет и упрощает разработку. Также не стоит забывать и про профилирование приложения для оптимизации скорости работы. Да прибудут с вами безбажные и быстрые Android приложения!

Хочешь обсудить Android разработку?
Заходи к нам Вконтакте, на Facebook и в Телеграм!

Добавить комментарий

1 комментарий

dilix 16.09.2020 - 23:27

Только надо не забывать, что Crashlytics от Fabric всё. Надо использовать Firebase Crashlytics.

Ответить

Может быть интересно

Этот сайт использует Cookie файлы для улучшения вашего пользовательского взаимодействия. Используя данный сайт вы соглашается с этим. Принять Читать

Политика конфиденциальности и Cookies