or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

index.md

index.mddocs/

0

# OkHttp Logging Interceptor

1

2

An OkHttp interceptor which logs HTTP request and response data with configurable logging levels and custom logger support. Provides comprehensive HTTP traffic monitoring for development and debugging.

3

4

## Package Information

5

6

- **Package Name**: logging-interceptor

7

- **Package Type**: Maven

8

- **Language**: Kotlin (with Java interop)

9

- **Installation**: `implementation("com.squareup.okhttp3:logging-interceptor:4.12.0")`

10

11

## Core Imports

12

13

```kotlin

14

import okhttp3.logging.HttpLoggingInterceptor

15

import okhttp3.logging.LoggingEventListener

16

```

17

18

Java:

19

```java

20

import okhttp3.logging.HttpLoggingInterceptor;

21

import okhttp3.logging.LoggingEventListener;

22

```

23

24

## Basic Usage

25

26

```kotlin

27

import okhttp3.OkHttpClient

28

import okhttp3.logging.HttpLoggingInterceptor

29

30

// Basic logging interceptor

31

val logging = HttpLoggingInterceptor()

32

logging.level = HttpLoggingInterceptor.Level.BODY

33

34

val client = OkHttpClient.Builder()

35

.addInterceptor(logging)

36

.build()

37

38

// Custom logger with header redaction

39

val customLogger = HttpLoggingInterceptor { message ->

40

println("HTTP: $message")

41

}

42

customLogger.level = HttpLoggingInterceptor.Level.HEADERS

43

customLogger.redactHeader("Authorization")

44

customLogger.redactHeader("Cookie")

45

46

val secureClient = OkHttpClient.Builder()

47

.addInterceptor(customLogger)

48

.build()

49

```

50

51

Java equivalent:

52

```java

53

import okhttp3.OkHttpClient;

54

import okhttp3.logging.HttpLoggingInterceptor;

55

56

// Basic logging interceptor

57

HttpLoggingInterceptor logging = new HttpLoggingInterceptor();

58

logging.setLevel(HttpLoggingInterceptor.Level.BODY);

59

60

OkHttpClient client = new OkHttpClient.Builder()

61

.addInterceptor(logging)

62

.build();

63

64

// Custom logger with header redaction

65

HttpLoggingInterceptor customLogger = new HttpLoggingInterceptor(message -> {

66

System.out.println("HTTP: " + message);

67

});

68

customLogger.setLevel(HttpLoggingInterceptor.Level.HEADERS);

69

customLogger.redactHeader("Authorization");

70

customLogger.redactHeader("Cookie");

71

72

OkHttpClient secureClient = new OkHttpClient.Builder()

73

.addInterceptor(customLogger)

74

.build();

75

```

76

77

## Architecture

78

79

The library consists of two main components:

80

81

- **HttpLoggingInterceptor**: The primary interceptor that logs HTTP request/response data at configurable detail levels

82

- **LoggingEventListener**: An EventListener that provides detailed timing and connection-level event logging

83

- **Logger Interface**: Pluggable logging interface allowing custom output destinations

84

- **Level Configuration**: Four logging levels from silent to full body logging with header redaction

85

86

## Capabilities

87

88

### HTTP Request/Response Logging

89

90

Core interceptor functionality for logging HTTP traffic with configurable detail levels and header security.

91

92

```kotlin { .api }

93

class HttpLoggingInterceptor @JvmOverloads constructor(

94

private val logger: Logger = Logger.DEFAULT

95

) : Interceptor {

96

97

@set:JvmName("level")

98

@Volatile var level: Level

99

100

fun redactHeader(name: String): Unit

101

fun setLevel(level: Level): HttpLoggingInterceptor

102

103

@JvmName("-deprecated_level")

104

@Deprecated(

105

message = "moved to var",

106

replaceWith = ReplaceWith(expression = "level"),

107

level = DeprecationLevel.ERROR

108

)

109

fun getLevel(): Level

110

111

@Throws(IOException::class)

112

override fun intercept(chain: Interceptor.Chain): Response

113

}

114

```

115

116

**Logging Levels:**

117

118

```kotlin { .api }

119

enum class Level {

120

/** No logs. */

121

NONE,

122

123

/** Logs request and response lines only. */

124

BASIC,

125

126

/** Logs request and response lines and their respective headers. */

127

HEADERS,

128

129

/** Logs request and response lines, headers, and bodies (if present). */

130

BODY

131

}

132

```

133

134

**Usage Examples:**

135

136

```kotlin

137

// Different logging levels

138

val interceptor = HttpLoggingInterceptor()

139

140

// No logging

141

interceptor.level = HttpLoggingInterceptor.Level.NONE

142

143

// Basic: --> POST /api/users http/1.1 (45-byte body)

144

// <-- 201 Created (123ms, 78-byte body)

145

interceptor.level = HttpLoggingInterceptor.Level.BASIC

146

147

// Headers: includes all request/response headers

148

interceptor.level = HttpLoggingInterceptor.Level.HEADERS

149

150

// Body: includes request/response bodies (be careful with sensitive data)

151

interceptor.level = HttpLoggingInterceptor.Level.BODY

152

153

// Header redaction for security

154

interceptor.redactHeader("Authorization")

155

interceptor.redactHeader("Set-Cookie")

156

157

// Fluent API (useful for Java)

158

val configuredInterceptor = HttpLoggingInterceptor()

159

.setLevel(HttpLoggingInterceptor.Level.HEADERS)

160

```

161

162

### Custom Logger Implementation

163

164

Interface for directing log output to custom destinations like files, logging frameworks, or analytics systems.

165

166

```kotlin { .api }

167

fun interface Logger {

168

fun log(message: String): Unit

169

170

companion object {

171

/** A Logger that outputs to platform-appropriate default location. */

172

@JvmField

173

val DEFAULT: Logger

174

}

175

}

176

```

177

178

**Usage Examples:**

179

180

```kotlin

181

// File logging

182

val fileLogger = HttpLoggingInterceptor { message ->

183

File("http.log").appendText("$message\n")

184

}

185

186

// Integration with logging frameworks

187

val timberLogger = HttpLoggingInterceptor { message ->

188

Timber.tag("OkHttp").d(message)

189

}

190

191

// Structured logging

192

val structuredLogger = HttpLoggingInterceptor { message ->

193

logger.info("http_traffic") {

194

"message" to message

195

"timestamp" to Instant.now()

196

}

197

}

198

199

// Conditional logging

200

val debugLogger = HttpLoggingInterceptor { message ->

201

if (BuildConfig.DEBUG) {

202

println("HTTP: $message")

203

}

204

}

205

```

206

207

### Event-Level HTTP Logging

208

209

Detailed connection and call lifecycle event logging for advanced debugging and performance monitoring.

210

211

```kotlin { .api }

212

class LoggingEventListener private constructor(

213

private val logger: HttpLoggingInterceptor.Logger

214

) : EventListener() {

215

// Private constructor - use Factory to create instances

216

217

// Connection lifecycle events

218

override fun callStart(call: Call): Unit

219

override fun callEnd(call: Call): Unit

220

override fun callFailed(call: Call, ioe: IOException): Unit

221

override fun canceled(call: Call): Unit

222

223

// DNS and proxy events

224

override fun proxySelectStart(call: Call, url: HttpUrl): Unit

225

override fun proxySelectEnd(call: Call, url: HttpUrl, proxies: List<Proxy>): Unit

226

override fun dnsStart(call: Call, domainName: String): Unit

227

override fun dnsEnd(call: Call, domainName: String, inetAddressList: List<InetAddress>): Unit

228

229

// Connection events

230

override fun connectStart(call: Call, inetSocketAddress: InetSocketAddress, proxy: Proxy): Unit

231

override fun connectEnd(call: Call, inetSocketAddress: InetSocketAddress, proxy: Proxy, protocol: Protocol?): Unit

232

override fun connectFailed(call: Call, inetSocketAddress: InetSocketAddress, proxy: Proxy, protocol: Protocol?, ioe: IOException): Unit

233

override fun secureConnectStart(call: Call): Unit

234

override fun secureConnectEnd(call: Call, handshake: Handshake?): Unit

235

236

// Connection pool events

237

override fun connectionAcquired(call: Call, connection: Connection): Unit

238

override fun connectionReleased(call: Call, connection: Connection): Unit

239

240

// Request events

241

override fun requestHeadersStart(call: Call): Unit

242

override fun requestHeadersEnd(call: Call, request: Request): Unit

243

override fun requestBodyStart(call: Call): Unit

244

override fun requestBodyEnd(call: Call, byteCount: Long): Unit

245

override fun requestFailed(call: Call, ioe: IOException): Unit

246

247

// Response events

248

override fun responseHeadersStart(call: Call): Unit

249

override fun responseHeadersEnd(call: Call, response: Response): Unit

250

override fun responseBodyStart(call: Call): Unit

251

override fun responseBodyEnd(call: Call, byteCount: Long): Unit

252

override fun responseFailed(call: Call, ioe: IOException): Unit

253

254

// Cache events

255

override fun satisfactionFailure(call: Call, response: Response): Unit

256

override fun cacheHit(call: Call, response: Response): Unit

257

override fun cacheMiss(call: Call): Unit

258

override fun cacheConditionalHit(call: Call, cachedResponse: Response): Unit

259

}

260

```

261

262

**Factory for Event Listener Creation:**

263

264

```kotlin { .api }

265

open class Factory @JvmOverloads constructor(

266

private val logger: HttpLoggingInterceptor.Logger = HttpLoggingInterceptor.Logger.DEFAULT

267

) : EventListener.Factory {

268

override fun create(call: Call): EventListener

269

}

270

```

271

272

**Usage Examples:**

273

274

```kotlin

275

// Basic event logging

276

val eventLogger = LoggingEventListener.Factory()

277

val client = OkHttpClient.Builder()

278

.eventListenerFactory(eventLogger)

279

.build()

280

281

// Custom event logger

282

val customEventLogger = LoggingEventListener.Factory { message ->

283

println("Event: $message")

284

}

285

286

// Combined interceptor and event logging

287

val interceptor = HttpLoggingInterceptor()

288

interceptor.level = HttpLoggingInterceptor.Level.BASIC

289

290

val eventListener = LoggingEventListener.Factory()

291

292

val client = OkHttpClient.Builder()

293

.addInterceptor(interceptor)

294

.eventListenerFactory(eventListener)

295

.build()

296

297

// Performance monitoring

298

val performanceLogger = LoggingEventListener.Factory { message ->

299

if (message.contains("ms")) {

300

// Log timing events to analytics

301

analytics.track("http_timing", message)

302

}

303

}

304

```

305

306

## Types

307

308

```kotlin { .api }

309

// From OkHttp core (referenced types)

310

interface Interceptor {

311

@Throws(IOException::class)

312

fun intercept(chain: Chain): Response

313

314

interface Chain {

315

fun request(): Request

316

@Throws(IOException::class)

317

fun proceed(request: Request): Response

318

fun connection(): Connection?

319

}

320

}

321

322

abstract class EventListener {

323

interface Factory {

324

fun create(call: Call): EventListener

325

}

326

}

327

328

// Standard Java/Kotlin types used

329

import java.io.IOException

330

import java.net.InetAddress

331

import java.net.InetSocketAddress

332

import java.net.Proxy

333

import okhttp3.Call

334

import okhttp3.Connection

335

import okhttp3.Handshake

336

import okhttp3.HttpUrl

337

import okhttp3.Protocol

338

import okhttp3.Request

339

import okhttp3.Response

340

```

341

342

## Security Considerations

343

344

**Header Redaction:**

345

- Always redact sensitive headers like `Authorization`, `Cookie`, `Set-Cookie`

346

- Use `redactHeader()` method to prevent credential leakage

347

- Headers are redacted with `"██"` in logs

348

349

**Body Logging Security:**

350

- `Level.BODY` exposes full request/response content

351

- Only use in development/debugging environments

352

- Consider data privacy and compliance requirements

353

- Request bodies containing binary data are omitted automatically

354

355

**Production Usage:**

356

- Use `Level.NONE` or `Level.BASIC` in production

357

- Implement custom Logger to control log destination

358

- Be aware that logs may contain sensitive URLs and headers

359

360

```kotlin

361

// Secure production configuration

362

val productionLogger = HttpLoggingInterceptor { message ->

363

// Only log to secure, encrypted storage

364

secureLogger.info(message)

365

}

366

productionLogger.level = HttpLoggingInterceptor.Level.BASIC

367

productionLogger.redactHeader("Authorization")

368

productionLogger.redactHeader("Cookie")

369

productionLogger.redactHeader("Set-Cookie")

370

productionLogger.redactHeader("X-API-Key")

371

```