← Назад к вопросам

Как сделать логирование в Retrofit и OkHttp

1.2 Junior🔥 172 комментариев
#Работа с данными#Сетевое взаимодействие

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Настройка логирования в Retrofit и OkHttp

Логирование сетевых запросов и ответов — критически важная часть разработки Android-приложений, особенно при отладке взаимодействия с API. Retrofit использует OkHttp в качестве HTTP-клиента, поэтому логирование настраивается именно на уровне OkHttp.

Основные подходы к логировамию

1. Использование HttpLoggingInterceptor (наиболее популярный способ)

Это стандартный перехватчик, предоставляемый библиотекой OkHttp, который позволяет логировать различные аспекты HTTP-запросов и ответов.

Шаг 1: Добавьте зависимость в build.gradle:

dependencies {
    implementation 'com.squareup.okhttp3:logging-interceptor:4.12.0'
}

Шаг 2: Создайте и настройте HttpLoggingInterceptor:

import okhttp3.logging.HttpLoggingInterceptor

val loggingInterceptor = HttpLoggingInterceptor().apply {
    // Уровень логирования зависит от типа сборки
    level = if (BuildConfig.DEBUG) {
        HttpLoggingInterceptor.Level.BODY
    } else {
        HttpLoggingInterceptor.Level.NONE
    }
}

Доступные уровни логирования:

  • NONE — без логирования
  • BASIC — логирует метод запроса, URL, код ответа и размер
  • HEADERS — добавляет заголовки запроса и ответа
  • BODY — полная информация, включая тела запроса и ответа

Шаг 3: Добавьте интерцептор в клиент OkHttp:

import okhttp3.OkHttpClient
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory

val okHttpClient = OkHttpClient.Builder()
    .addInterceptor(loggingInterceptor)
    .build()

val retrofit = Retrofit.Builder()
    .baseUrl("https://api.example.com/")
    .client(okHttpClient)
    .addConverterFactory(GsonConverterFactory.create())
    .build()

2. Создание кастомного интерцептора для расширенного логирования

Если стандартного логирования недостаточно, можно создать собственный интерцептор:

import okhttp3.Interceptor
import okhttp3.Response
import okio.Buffer
import java.nio.charset.Charset

class CustomLoggingInterceptor : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request()
        val requestTime = System.currentTimeMillis()
        
        // Логирование запроса
        logRequest(request)
        
        val response = chain.proceed(request)
        val responseTime = System.currentTimeMillis() - requestTime
        
        // Логирование ответа
        logResponse(response, responseTime)
        
        return response
    }
    
    private fun logRequest(request: Request) {
        println("→ ${request.method} ${request.url}")
        request.headers.forEach { name, value ->
            println("  $name: $value")
        }
        
        request.body?.let { body ->
            val buffer = Buffer()
            body.writeTo(buffer)
            println("  Body: ${buffer.readString(Charset.defaultCharset())}")
        }
    }
    
    private fun logResponse(response: Response, duration: Long) {
        println("← ${response.code} ${response.message} (${duration}ms)")
        response.headers.forEach { name, value ->
            println("  $name: $value")
        }
        
        response.body?.let { body ->
            val source = body.source()
            source.request(Long.MAX_VALUE)
            val buffer = source.buffer
            println("  Body: ${buffer.clone().readString(Charset.defaultCharset())}")
        }
    }
}

Важные рекомендации по логированию

Безопасность и конфиденциальность

  • Никогда не логируйте конфиденциальные данные (токены авторизации, пароли, персональные данные) в продакшене
  • Используйте разные уровни логирования для debug и release сборок:
val loggingInterceptor = HttpLoggingInterceptor { message ->
    // Фильтрация конфиденциальных данных
    val filteredMessage = message.replace(
        Regex("(Authorization|Bearer|password|token): .+"),
        "$1: [FILTERED]"
    )
    Log.d("HTTP", filteredMessage)
}.apply {
    level = if (BuildConfig.DEBUG) {
        HttpLoggingInterceptor.Level.HEADERS
    } else {
        HttpLoggingInterceptor.Level.NONE
    }
}

Производительность

  • Логирование уровня BODY может существенно замедлить работу приложения, особенно при больших ответах
  • В продакшене рекомендуется отключать логирование или использовать минимальный уровень

Форматирование JSON в логах

Для более читаемого вывода JSON-ответов можно использовать кастомный логирующий интерцептор:

class JsonFormattingInterceptor : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val response = chain.proceed(chain.request())
        
        val contentType = response.header("Content-Type") ?: ""
        if (contentType.contains("application/json")) {
            val responseBody = response.body
            val source = responseBody?.source()
            source?.request(Long.MAX_VALUE)
            val buffer = source?.buffer?.clone()
            val json = buffer?.readUtf8()
            
            // Форматирование JSON с отступами
            val formattedJson = try {
                JSONObject(json).toString(2)
            } catch (e: Exception) {
                try {
                    JSONArray(json).toString(2)
                } catch (e: Exception) {
                    json
                }
            }
            
            Log.d("FormattedJSON", formattedJson ?: "")
        }
        
        return response
    }
}

Конфигурация для разных сред

Для управления логированием в разных средах рекомендуется использовать конфигурационный класс:

object NetworkLogger {
    
    fun createHttpLogger(): HttpLoggingInterceptor {
        return HttpLoggingInterceptor { message ->
            when {
                message.startsWith("{") || message.startsWith("[") -> 
                    logFormattedJson(message)
                else -> 
                    Log.d("Network", message)
            }
        }.apply {
            level = when (BuildConfig.BUILD_TYPE) {
                "debug" -> HttpLoggingInterceptor.Level.BODY
                "staging" -> HttpLoggingInterceptor.Level.HEADERS
                else -> HttpLoggingInterceptor.Level.NONE
            }
        }
    }
    
    private fun logFormattedJson(jsonString: String) {
        // Кастомная логика форматирования JSON
    }
}

// Использование
val okHttpClient = OkHttpClient.Builder()
    .addInterceptor(NetworkLogger.createHttpLogger())
    .build()

Вывод

Для эффективного логирования в Retrofit/OkHttp рекомендуется:

  1. Использовать HttpLoggingInterceptor для базовых нужд
  2. Создавать кастомные интерцепторы для специфических требований
  3. Всегда фильтровать конфиденциальные данные
  4. Настраивать разные уровни логирования для разных типов сборок
  5. Мониторить влияние логирования на производительность приложения

Правильно настроенное логирование значительно ускоряет отладку сетевых запросов и помогает быстро выявлять проблемы интеграции с бэкендом.

Как сделать логирование в Retrofit и OkHttp | PrepBro