Retrofit
Android
Logging
Request-Response
Networking

How to log request and response body with Retrofit-Android?

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

Retrofit itself delegates HTTP transport to OkHttp, so request and response body logging is normally added at the OkHttp layer. The standard tool is HttpLoggingInterceptor, which can log nothing, basic metadata, headers, or full bodies depending on the level you choose.

Add the Logging Interceptor

The typical setup is:

kotlin
1import okhttp3.OkHttpClient
2import okhttp3.logging.HttpLoggingInterceptor
3import retrofit2.Retrofit
4import retrofit2.converter.gson.GsonConverterFactory
5
6val logging = HttpLoggingInterceptor().apply {
7    level = HttpLoggingInterceptor.Level.BODY
8}
9
10val client = OkHttpClient.Builder()
11    .addInterceptor(logging)
12    .build()
13
14val retrofit = Retrofit.Builder()
15    .baseUrl("https://api.example.com/")
16    .client(client)
17    .addConverterFactory(GsonConverterFactory.create())
18    .build()

Level.BODY logs request lines, response lines, headers, and bodies. That is the most verbose setting and the one people usually want during debugging.

What the Levels Mean

The built-in levels are:

  • 'NONE'
  • 'BASIC'
  • 'HEADERS'
  • 'BODY'

BODY is convenient, but it is also the riskiest because payloads can contain sensitive data or be very large.

Use Body Logging Only Where It Makes Sense

For local debugging, BODY is often fine. For release builds, it is usually better to reduce logging or disable it entirely:

kotlin
1val logging = HttpLoggingInterceptor().apply {
2    level = if (BuildConfig.DEBUG) {
3        HttpLoggingInterceptor.Level.BODY
4    } else {
5        HttpLoggingInterceptor.Level.NONE
6    }
7}

That keeps detailed logs out of production by default.

Redact Sensitive Headers

If the requests contain tokens or credentials, redact them:

kotlin
1val logging = HttpLoggingInterceptor().apply {
2    level = HttpLoggingInterceptor.Level.BODY
3    redactHeader("Authorization")
4    redactHeader("Cookie")
5}

This is a strong default even in development, because logs have a habit of being copied into bug reports and shared chat threads.

When You Need More Than the Built-In Interceptor

Sometimes you want custom formatting, structured logging, or selective logging only for certain endpoints. In that case, write your own OkHttp interceptor:

kotlin
1import okhttp3.Interceptor
2import okhttp3.Response
3import timber.log.Timber
4
5class SimpleLoggingInterceptor : Interceptor {
6    override fun intercept(chain: Interceptor.Chain): Response {
7        val request = chain.request()
8        Timber.d("Request: ${request.method} ${request.url}")
9
10        val response = chain.proceed(request)
11        Timber.d("Response: ${response.code} ${response.request.url}")
12
13        return response
14    }
15}

This does not automatically dump request and response bodies the way HttpLoggingInterceptor does, but it gives full control over what gets logged and where it goes.

Be Careful with Body Logging in Production

Full-body logging can expose:

  • passwords
  • auth tokens
  • personal data
  • large binary payloads

It can also slow down requests slightly and clutter logs so much that important signals become harder to find. For those reasons, BODY logging is usually a debug-only tool.

Common Pitfalls

The biggest pitfall is trying to configure logging in Retrofit itself instead of in the underlying OkHttp client. Retrofit does not own the wire-level logging mechanism.

Another common mistake is leaving BODY logging enabled in release builds. That can leak sensitive data and create unnecessary overhead.

People also forget that not every response body is text. Logging large binary or compressed content may be noisy, slow, or simply not useful.

If you are debugging only one service call, a temporary custom interceptor scoped to that client is often cleaner than enabling full-body logging for the entire app.

Summary

  • Use OkHttp's HttpLoggingInterceptor to log Retrofit requests and responses.
  • Set the level to BODY when you need full request and response payloads during debugging.
  • Prefer lower logging levels or NONE outside debug builds.
  • Redact sensitive headers such as Authorization and Cookie.
  • Use a custom interceptor when you need more control than the built-in logger provides.
  • Be selective with body logging on large or sensitive APIs so the logs stay useful.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.