or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

content-streaming.mdhttp-clients.mdhttp-messages.mdindex.mdmetrics.mdservice-discovery.mdtls-configuration.md

metrics.mddocs/

0

# Metrics and Monitoring

1

2

Built-in metrics collection capabilities for HTTP client implementations. Provides standardized metrics for HTTP/1.1 and HTTP/2 operations including connection pooling, performance monitoring, and protocol-specific statistics.

3

4

## Capabilities

5

6

### HttpMetric

7

8

Defines standard metrics that HTTP client implementations should collect for HTTP/1.1 and HTTP/2 operations. These metrics provide insights into client performance and resource utilization.

9

10

```java { .api }

11

/**

12

* Metrics collected by HTTP clients for HTTP/1 and HTTP/2 operations.

13

* Implementations should collect these metrics to provide visibility

14

* into client performance and resource utilization.

15

*/

16

public final class HttpMetric {

17

/**

18

* Name of the HTTP client implementation

19

*/

20

public static final SdkMetric<String> HTTP_CLIENT_NAME;

21

22

/**

23

* Maximum number of concurrent requests supported by the client

24

*/

25

public static final SdkMetric<Integer> MAX_CONCURRENCY;

26

27

/**

28

* Current number of available concurrent request slots

29

*/

30

public static final SdkMetric<Integer> AVAILABLE_CONCURRENCY;

31

32

/**

33

* Current number of requests actively being executed

34

*/

35

public static final SdkMetric<Integer> LEASED_CONCURRENCY;

36

37

/**

38

* Number of requests currently waiting to acquire concurrency

39

*/

40

public static final SdkMetric<Integer> PENDING_CONCURRENCY_ACQUIRES;

41

42

/**

43

* HTTP response status code for completed requests

44

*/

45

public static final SdkMetric<Integer> HTTP_STATUS_CODE;

46

47

/**

48

* Time taken to acquire a connection or channel from the pool

49

*/

50

public static final SdkMetric<Duration> CONCURRENCY_ACQUIRE_DURATION;

51

}

52

```

53

54

**Usage Example:**

55

56

```java

57

// HTTP client implementation collecting metrics

58

public class MyHttpClient implements SdkHttpClient {

59

private final MetricCollector metricCollector;

60

private final ConnectionPool connectionPool;

61

62

@Override

63

public ExecutableHttpRequest prepareRequest(HttpExecuteRequest request) {

64

return new MetricsAwareExecutableRequest(request, metricCollector, connectionPool);

65

}

66

67

// Collect periodic metrics

68

private void collectPoolMetrics() {

69

metricCollector.reportMetric(HttpMetric.HTTP_CLIENT_NAME, clientName());

70

metricCollector.reportMetric(HttpMetric.MAX_CONCURRENCY, connectionPool.maxConnections());

71

metricCollector.reportMetric(HttpMetric.AVAILABLE_CONCURRENCY, connectionPool.availableConnections());

72

metricCollector.reportMetric(HttpMetric.LEASED_CONCURRENCY, connectionPool.activeConnections());

73

metricCollector.reportMetric(HttpMetric.PENDING_CONCURRENCY_ACQUIRES, connectionPool.pendingAcquires());

74

}

75

}

76

77

// Metrics-aware request execution

78

public class MetricsAwareExecutableRequest implements ExecutableHttpRequest {

79

private final HttpExecuteRequest request;

80

private final MetricCollector metricCollector;

81

private final ConnectionPool connectionPool;

82

83

@Override

84

public HttpExecuteResponse call() throws IOException {

85

long acquireStart = System.nanoTime();

86

87

try (Connection connection = connectionPool.acquire()) {

88

long acquireDuration = System.nanoTime() - acquireStart;

89

metricCollector.reportMetric(HttpMetric.CONCURRENCY_ACQUIRE_DURATION,

90

Duration.ofNanos(acquireDuration));

91

92

HttpExecuteResponse response = connection.execute(request);

93

94

// Report response status

95

metricCollector.reportMetric(HttpMetric.HTTP_STATUS_CODE,

96

response.httpResponse().statusCode());

97

98

return response;

99

}

100

}

101

}

102

```

103

104

### Http2Metric

105

106

Defines HTTP/2 specific metrics that provide insights into HTTP/2 protocol behavior, stream management, and flow control.

107

108

```java { .api }

109

/**

110

* Metrics specific to HTTP/2 operations.

111

* These metrics provide insights into HTTP/2 stream management,

112

* flow control, and protocol-specific performance characteristics.

113

*/

114

public final class Http2Metric {

115

/**

116

* Local HTTP/2 stream window size in bytes.

117

* Indicates how much data the local endpoint can receive.

118

*/

119

public static final SdkMetric<Integer> LOCAL_STREAM_WINDOW_SIZE_IN_BYTES;

120

121

/**

122

* Remote HTTP/2 stream window size in bytes.

123

* Indicates how much data can be sent to the remote endpoint.

124

*/

125

public static final SdkMetric<Integer> REMOTE_STREAM_WINDOW_SIZE_IN_BYTES;

126

}

127

```

128

129

**Usage Example:**

130

131

```java

132

// HTTP/2 client implementation with flow control metrics

133

public class Http2Client implements SdkAsyncHttpClient {

134

private final MetricCollector metricCollector;

135

136

public void reportStreamMetrics(Http2Stream stream) {

137

// Report flow control window sizes

138

metricCollector.reportMetric(Http2Metric.LOCAL_STREAM_WINDOW_SIZE_IN_BYTES,

139

stream.getLocalWindowSize());

140

141

metricCollector.reportMetric(Http2Metric.REMOTE_STREAM_WINDOW_SIZE_IN_BYTES,

142

stream.getRemoteWindowSize());

143

}

144

145

@Override

146

public CompletableFuture<Void> execute(AsyncExecuteRequest request) {

147

return http2Connection.createStream()

148

.thenCompose(stream -> {

149

// Report initial window sizes

150

reportStreamMetrics(stream);

151

152

// Execute request and monitor flow control

153

return stream.sendRequest(request)

154

.thenRun(() -> {

155

// Report final window sizes

156

reportStreamMetrics(stream);

157

});

158

});

159

}

160

}

161

```

162

163

## Metric Collection Integration

164

165

### SdkMetric Type System

166

167

The metric system uses type-safe metric definitions:

168

169

```java { .api }

170

/**

171

* Type-safe metric definition

172

*/

173

public interface SdkMetric<T> {

174

/**

175

* @return Metric name for identification

176

*/

177

String name();

178

179

/**

180

* @return Expected value type for this metric

181

*/

182

Class<T> valueType();

183

}

184

```

185

186

### MetricCollector Integration

187

188

HTTP clients should integrate with the AWS SDK metric collection system:

189

190

```java

191

// Metric collection during request execution

192

public class MetricsIntegratedClient implements SdkHttpClient {

193

@Override

194

public ExecutableHttpRequest prepareRequest(HttpExecuteRequest request) {

195

Optional<MetricCollector> collector = request.metricCollector();

196

197

return new ExecutableHttpRequest() {

198

@Override

199

public HttpExecuteResponse call() throws IOException {

200

long startTime = System.nanoTime();

201

202

try {

203

// Report client name

204

collector.ifPresent(c ->

205

c.reportMetric(HttpMetric.HTTP_CLIENT_NAME, clientName()));

206

207

// Execute request

208

HttpExecuteResponse response = executeHttpRequest(request);

209

210

// Report success metrics

211

collector.ifPresent(c -> {

212

c.reportMetric(HttpMetric.HTTP_STATUS_CODE,

213

response.httpResponse().statusCode());

214

215

long duration = System.nanoTime() - startTime;

216

c.reportMetric(HttpMetric.CONCURRENCY_ACQUIRE_DURATION,

217

Duration.ofNanos(duration));

218

});

219

220

return response;

221

} catch (IOException e) {

222

// Report error metrics

223

collector.ifPresent(c -> {

224

// Could report error-specific metrics here

225

});

226

throw e;

227

}

228

}

229

};

230

}

231

}

232

```

233

234

## Connection Pool Metrics

235

236

### Real-time Pool Monitoring

237

238

HTTP clients should provide real-time visibility into connection pool state:

239

240

```java

241

public class MonitoredConnectionPool implements ConnectionPool {

242

private final AtomicInteger maxConnections;

243

private final AtomicInteger activeConnections;

244

private final AtomicInteger availableConnections;

245

private final AtomicInteger pendingAcquires;

246

private final MetricCollector metricCollector;

247

248

public MonitoredConnectionPool(int maxConnections, MetricCollector metricCollector) {

249

this.maxConnections = new AtomicInteger(maxConnections);

250

this.activeConnections = new AtomicInteger(0);

251

this.availableConnections = new AtomicInteger(maxConnections);

252

this.pendingAcquires = new AtomicInteger(0);

253

this.metricCollector = metricCollector;

254

255

// Start periodic metric reporting

256

startMetricReporting();

257

}

258

259

@Override

260

public Connection acquire() throws IOException {

261

pendingAcquires.incrementAndGet();

262

long acquireStart = System.nanoTime();

263

264

try {

265

Connection connection = doAcquire();

266

267

// Update counters

268

activeConnections.incrementAndGet();

269

availableConnections.decrementAndGet();

270

pendingAcquires.decrementAndGet();

271

272

// Report acquire duration

273

long acquireDuration = System.nanoTime() - acquireStart;

274

metricCollector.reportMetric(HttpMetric.CONCURRENCY_ACQUIRE_DURATION,

275

Duration.ofNanos(acquireDuration));

276

277

return new MetricsAwareConnection(connection, this);

278

} catch (IOException e) {

279

pendingAcquires.decrementAndGet();

280

throw e;

281

}

282

}

283

284

public void releaseConnection(Connection connection) {

285

activeConnections.decrementAndGet();

286

availableConnections.incrementAndGet();

287

doRelease(connection);

288

}

289

290

private void startMetricReporting() {

291

ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();

292

scheduler.scheduleAtFixedRate(() -> {

293

metricCollector.reportMetric(HttpMetric.MAX_CONCURRENCY, maxConnections.get());

294

metricCollector.reportMetric(HttpMetric.AVAILABLE_CONCURRENCY, availableConnections.get());

295

metricCollector.reportMetric(HttpMetric.LEASED_CONCURRENCY, activeConnections.get());

296

metricCollector.reportMetric(HttpMetric.PENDING_CONCURRENCY_ACQUIRES, pendingAcquires.get());

297

}, 0, 10, TimeUnit.SECONDS);

298

}

299

}

300

301

// Connection wrapper that reports metrics on release

302

public class MetricsAwareConnection implements Connection {

303

private final Connection delegate;

304

private final MonitoredConnectionPool pool;

305

306

@Override

307

public void close() {

308

delegate.close();

309

pool.releaseConnection(delegate);

310

}

311

312

// Delegate all other methods to the wrapped connection

313

}

314

```

315

316

### HTTP/2 Stream Metrics

317

318

For HTTP/2 implementations, track stream-specific metrics:

319

320

```java

321

public class Http2StreamManager {

322

private final MetricCollector metricCollector;

323

private final Map<Integer, Http2Stream> activeStreams = new ConcurrentHashMap<>();

324

325

public Http2Stream createStream() {

326

Http2Stream stream = new Http2Stream();

327

activeStreams.put(stream.getId(), stream);

328

329

// Report initial flow control state

330

reportStreamFlowControl(stream);

331

332

return stream;

333

}

334

335

public void reportStreamFlowControl(Http2Stream stream) {

336

metricCollector.reportMetric(Http2Metric.LOCAL_STREAM_WINDOW_SIZE_IN_BYTES,

337

stream.getLocalFlowControlWindow());

338

339

metricCollector.reportMetric(Http2Metric.REMOTE_STREAM_WINDOW_SIZE_IN_BYTES,

340

stream.getRemoteFlowControlWindow());

341

}

342

343

public void onWindowUpdate(int streamId, int windowSizeIncrement) {

344

Http2Stream stream = activeStreams.get(streamId);

345

if (stream != null) {

346

stream.updateRemoteWindow(windowSizeIncrement);

347

reportStreamFlowControl(stream);

348

}

349

}

350

351

public void onStreamData(int streamId, int dataSize) {

352

Http2Stream stream = activeStreams.get(streamId);

353

if (stream != null) {

354

stream.consumeLocalWindow(dataSize);

355

reportStreamFlowControl(stream);

356

}

357

}

358

}

359

```

360

361

## Metrics Best Practices

362

363

### Efficient Metric Collection

364

365

1. **Avoid High-Frequency Metrics**:

366

```java

367

// Don't report metrics for every byte transferred

368

// Instead, report periodically or on significant events

369

370

public class EfficientMetricReporting {

371

private volatile long lastMetricReport = 0;

372

private static final long METRIC_REPORT_INTERVAL_MS = 10_000; // 10 seconds

373

374

public void maybeReportMetrics() {

375

long now = System.currentTimeMillis();

376

if (now - lastMetricReport > METRIC_REPORT_INTERVAL_MS) {

377

reportCurrentMetrics();

378

lastMetricReport = now;

379

}

380

}

381

}

382

```

383

384

2. **Batch Metric Updates**:

385

```java

386

// Collect multiple metrics in a single call

387

public void reportBatchMetrics(MetricCollector collector) {

388

collector.reportMetrics(Map.of(

389

HttpMetric.AVAILABLE_CONCURRENCY, connectionPool.available(),

390

HttpMetric.LEASED_CONCURRENCY, connectionPool.active(),

391

HttpMetric.PENDING_CONCURRENCY_ACQUIRES, connectionPool.pending()

392

));

393

}

394

```

395

396

3. **Conditional Metric Collection**:

397

```java

398

public HttpExecuteResponse call() throws IOException {

399

Optional<MetricCollector> collector = request.metricCollector();

400

401

// Only collect metrics if a collector is provided

402

if (collector.isPresent()) {

403

return executeWithMetrics(collector.get());

404

} else {

405

return executeWithoutMetrics();

406

}

407

}

408

```

409

410

### Error and Performance Metrics

411

412

Track both success and failure scenarios:

413

414

```java

415

public class ComprehensiveMetricsClient implements SdkHttpClient {

416

@Override

417

public ExecutableHttpRequest prepareRequest(HttpExecuteRequest request) {

418

return new ExecutableHttpRequest() {

419

@Override

420

public HttpExecuteResponse call() throws IOException {

421

Optional<MetricCollector> collector = request.metricCollector();

422

long startTime = System.nanoTime();

423

424

try {

425

HttpExecuteResponse response = executeRequest(request);

426

427

// Report success metrics

428

collector.ifPresent(c -> {

429

c.reportMetric(HttpMetric.HTTP_STATUS_CODE,

430

response.httpResponse().statusCode());

431

432

// Report timing

433

long duration = System.nanoTime() - startTime;

434

c.reportMetric(HttpMetric.CONCURRENCY_ACQUIRE_DURATION,

435

Duration.ofNanos(duration));

436

});

437

438

return response;

439

} catch (IOException e) {

440

// Report error metrics

441

collector.ifPresent(c -> {

442

// Report error count or type

443

c.reportMetric(createErrorMetric(e.getClass().getSimpleName()), 1);

444

445

// Still report timing for failed requests

446

long duration = System.nanoTime() - startTime;

447

c.reportMetric(HttpMetric.CONCURRENCY_ACQUIRE_DURATION,

448

Duration.ofNanos(duration));

449

});

450

451

throw e;

452

}

453

}

454

};

455

}

456

457

private SdkMetric<Integer> createErrorMetric(String errorType) {

458

// Create custom metrics for different error types

459

return new SdkMetric<Integer>() {

460

@Override

461

public String name() {

462

return "http.client.error." + errorType.toLowerCase();

463

}

464

465

@Override

466

public Class<Integer> valueType() {

467

return Integer.class;

468

}

469

};

470

}

471

}

472

```

473

474

## Monitoring and Observability

475

476

### Integration with Monitoring Systems

477

478

HTTP client metrics can be integrated with various monitoring systems:

479

480

```java

481

// Example integration with Micrometer/Prometheus

482

public class MicrometerIntegratedClient implements SdkHttpClient {

483

private final MeterRegistry meterRegistry;

484

private final Counter requestCounter;

485

private final Timer requestTimer;

486

private final Gauge connectionGauge;

487

488

public MicrometerIntegratedClient(MeterRegistry meterRegistry) {

489

this.meterRegistry = meterRegistry;

490

this.requestCounter = Counter.builder("http.client.requests")

491

.description("Total HTTP requests")

492

.register(meterRegistry);

493

this.requestTimer = Timer.builder("http.client.request.duration")

494

.description("HTTP request duration")

495

.register(meterRegistry);

496

this.connectionGauge = Gauge.builder("http.client.connections.active")

497

.description("Active HTTP connections")

498

.register(meterRegistry, this, client -> getActiveConnectionCount());

499

}

500

501

// Implementation integrates AWS SDK metrics with Micrometer

502

}

503

```

504

505

The metrics system provides comprehensive visibility into HTTP client behavior, enabling effective monitoring, troubleshooting, and performance optimization of AWS SDK HTTP operations.