0
# Events and Monitoring
1
2
Client lifecycle events and monitoring hooks for observing request/response processing, error handling, and performance monitoring throughout the HTTP client lifecycle.
3
4
## Capabilities
5
6
### Client Events
7
8
Predefined event definitions for monitoring HTTP client operations.
9
10
```kotlin { .api }
11
/**
12
* Container for HTTP client event definitions
13
*/
14
object ClientEvents {
15
/** Fired when HTTP request is created */
16
val HttpRequestCreated: EventDefinition<HttpRequestBuilder>
17
18
/** Fired when HTTP request is ready for sending */
19
val HttpRequestIsReadyForSending: EventDefinition<HttpRequestBuilder>
20
21
/** Fired when HTTP response is received */
22
val HttpResponseReceived: EventDefinition<HttpResponse>
23
24
/** Fired when HTTP response receive fails */
25
val HttpResponseReceiveFailed: EventDefinition<HttpResponseReceiveFail>
26
27
/** Fired when HTTP response is cancelled */
28
val HttpResponseCancelled: EventDefinition<HttpResponse>
29
}
30
```
31
32
### Event Data Types
33
34
Data structures for event information.
35
36
```kotlin { .api }
37
/**
38
* Information about failed response receive
39
* @param request - The original HTTP request
40
* @param cause - Exception that caused the failure
41
*/
42
data class HttpResponseReceiveFail(
43
val request: HttpRequest,
44
val cause: Throwable
45
)
46
47
/**
48
* Event definition for typed events
49
* @param T - Type of event data
50
*/
51
interface EventDefinition<T>
52
```
53
54
### Event Monitoring
55
56
Subscribe to client events for monitoring and logging.
57
58
```kotlin { .api }
59
/**
60
* Event monitoring interface
61
*/
62
interface Events {
63
/** Subscribe to an event */
64
fun <T> subscribe(definition: EventDefinition<T>, handler: suspend (T) -> Unit)
65
66
/** Unsubscribe from an event */
67
fun <T> unsubscribe(definition: EventDefinition<T>, handler: suspend (T) -> Unit)
68
69
/** Raise an event */
70
suspend fun <T> raise(definition: EventDefinition<T>, value: T)
71
}
72
73
// Access events through HttpClient
74
val HttpClient.monitor: Events
75
```
76
77
**Usage Examples:**
78
79
```kotlin
80
import io.ktor.client.*
81
import io.ktor.client.request.*
82
import io.ktor.client.utils.*
83
84
val client = HttpClient()
85
86
// Subscribe to request creation events
87
client.monitor.subscribe(ClientEvents.HttpRequestCreated) { request ->
88
println("Request created: ${request.method.value} ${request.url}")
89
}
90
91
// Subscribe to response events
92
client.monitor.subscribe(ClientEvents.HttpResponseReceived) { response ->
93
println("Response received: ${response.status} from ${response.call.request.url}")
94
}
95
96
// Subscribe to failure events
97
client.monitor.subscribe(ClientEvents.HttpResponseReceiveFailed) { failure ->
98
println("Request failed: ${failure.request.url} - ${failure.cause.message}")
99
}
100
101
// Subscribe to cancellation events
102
client.monitor.subscribe(ClientEvents.HttpResponseCancelled) { response ->
103
println("Response cancelled: ${response.call.request.url}")
104
}
105
106
// Make requests - events will be fired automatically
107
val response = client.get("https://api.example.com/users")
108
```
109
110
### Custom Event Definitions
111
112
Create custom event definitions for application-specific monitoring.
113
114
```kotlin { .api }
115
/**
116
* Create custom event definition
117
*/
118
fun <T> EventDefinition(): EventDefinition<T>
119
```
120
121
**Custom Events Example:**
122
123
```kotlin
124
import io.ktor.client.*
125
import io.ktor.client.utils.*
126
127
// Define custom events
128
val CustomRequestStart = EventDefinition<String>()
129
val CustomRequestComplete = EventDefinition<Pair<String, Long>>()
130
131
val client = HttpClient()
132
133
// Subscribe to custom events
134
client.monitor.subscribe(CustomRequestStart) { url ->
135
println("Starting custom operation for: $url")
136
}
137
138
client.monitor.subscribe(CustomRequestComplete) { (url, duration) ->
139
println("Completed custom operation for: $url in ${duration}ms")
140
}
141
142
// Raise custom events
143
suspend fun monitoredRequest(url: String) {
144
client.monitor.raise(CustomRequestStart, url)
145
val start = System.currentTimeMillis()
146
147
try {
148
val response = client.get(url)
149
val duration = System.currentTimeMillis() - start
150
client.monitor.raise(CustomRequestComplete, url to duration)
151
} catch (e: Exception) {
152
// Handle error and still fire completion event
153
val duration = System.currentTimeMillis() - start
154
client.monitor.raise(CustomRequestComplete, url to duration)
155
throw e
156
}
157
}
158
```
159
160
### Event-Based Logging
161
162
Implement comprehensive logging using event monitoring.
163
164
```kotlin
165
import io.ktor.client.*
166
import io.ktor.client.utils.*
167
import kotlinx.coroutines.*
168
169
class HttpClientLogger(private val client: HttpClient) {
170
171
init {
172
setupEventMonitoring()
173
}
174
175
private fun setupEventMonitoring() {
176
// Log all requests
177
client.monitor.subscribe(ClientEvents.HttpRequestCreated) { request ->
178
println("[REQUEST] ${request.method.value} ${request.url}")
179
request.headers.entries().forEach { (name, values) ->
180
println("[REQUEST-HEADER] $name: ${values.joinToString(", ")}")
181
}
182
}
183
184
// Log successful responses
185
client.monitor.subscribe(ClientEvents.HttpResponseReceived) { response ->
186
println("[RESPONSE] ${response.status.value} ${response.status.description}")
187
println("[TIMING] Request: ${response.requestTime}, Response: ${response.responseTime}")
188
}
189
190
// Log failures
191
client.monitor.subscribe(ClientEvents.HttpResponseReceiveFailed) { failure ->
192
println("[ERROR] Request to ${failure.request.url} failed: ${failure.cause.message}")
193
failure.cause.printStackTrace()
194
}
195
196
// Log cancellations
197
client.monitor.subscribe(ClientEvents.HttpResponseCancelled) { response ->
198
println("[CANCELLED] Request to ${response.call.request.url} was cancelled")
199
}
200
}
201
}
202
203
// Usage
204
val client = HttpClient()
205
val logger = HttpClientLogger(client)
206
207
// All requests will now be logged automatically
208
val response = client.get("https://api.example.com/users")
209
```
210
211
### Performance Monitoring
212
213
Use events for performance tracking and metrics collection.
214
215
```kotlin
216
import io.ktor.client.*
217
import io.ktor.client.utils.*
218
219
class HttpPerformanceMonitor(private val client: HttpClient) {
220
private val requestTimes = mutableMapOf<HttpRequest, Long>()
221
222
init {
223
// Track request start times
224
client.monitor.subscribe(ClientEvents.HttpRequestIsReadyForSending) { request ->
225
requestTimes[request] = System.currentTimeMillis()
226
}
227
228
// Calculate and log response times
229
client.monitor.subscribe(ClientEvents.HttpResponseReceived) { response ->
230
val startTime = requestTimes.remove(response.call.request)
231
if (startTime != null) {
232
val duration = System.currentTimeMillis() - startTime
233
println("Request to ${response.call.request.url} took ${duration}ms")
234
235
// Could send to metrics system here
236
recordMetric("http.request.duration", duration,
237
mapOf("url" to response.call.request.url.toString(),
238
"method" to response.call.request.method.value,
239
"status" to response.status.value.toString()))
240
}
241
}
242
243
// Clean up on failures
244
client.monitor.subscribe(ClientEvents.HttpResponseReceiveFailed) { failure ->
245
requestTimes.remove(failure.request)
246
}
247
}
248
249
private fun recordMetric(name: String, value: Long, tags: Map<String, String>) {
250
// Implementation for your metrics system
251
println("METRIC: $name = $value, tags = $tags")
252
}
253
}
254
```
255
256
## Event Lifecycle
257
258
1. **HttpRequestCreated** - Fired when `HttpRequestBuilder` is created and configured
259
2. **HttpRequestIsReadyForSending** - Fired just before the request is sent to the engine
260
3. **HttpResponseReceived** - Fired when a successful response is received
261
4. **HttpResponseReceiveFailed** - Fired when response receiving fails
262
5. **HttpResponseCancelled** - Fired when response processing is cancelled
263
264
Events provide a clean way to implement cross-cutting concerns like logging, metrics, caching, and debugging without modifying core client code.