or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

configuration.mdconnection-management.mdcontext-resources.mdhandlers.mdindex.mdrequest-logging.mdrequest-response.mdsecurity-ssl.mdserver-core.mdsession-management.mdutility-handlers.md

request-logging.mddocs/

0

# Request Logging

1

2

Request logging provides comprehensive HTTP request and response logging with customizable formats, file rotation, asynchronous writing, and integration with SLF4J logging frameworks.

3

4

## RequestLog Interface

5

6

The core interface for logging HTTP requests and responses.

7

8

```java { .api }

9

public interface RequestLog {

10

// Log a request/response pair

11

void log(Request request, Response response);

12

13

// Nested interface for log writers

14

interface Writer {

15

void write(String requestEntry) throws IOException;

16

}

17

}

18

```

19

20

## CustomRequestLog

21

22

Flexible request logger with customizable log formats and output destinations.

23

24

```java { .api }

25

public class CustomRequestLog extends ContainerLifeCycle implements RequestLog {

26

// Constructors

27

public CustomRequestLog();

28

public CustomRequestLog(RequestLog.Writer writer);

29

public CustomRequestLog(RequestLog.Writer writer, String format);

30

public CustomRequestLog(String filename);

31

public CustomRequestLog(String filename, String format);

32

33

// Format configuration

34

public void setLogFormat(String format);

35

public String getLogFormat();

36

public void setLogTimeZone(String timeZone);

37

public String getLogTimeZone();

38

39

// Writer configuration

40

public RequestLog.Writer getWriter();

41

public void setWriter(RequestLog.Writer writer);

42

43

// Cookie logging

44

public String[] getLogCookies();

45

public void setLogCookies(String[] logCookies);

46

47

// Latency logging

48

public boolean isLogLatency();

49

public void setLogLatency(boolean logLatency);

50

51

// Server information

52

public boolean isLogServer();

53

public void setLogServer(boolean logServer);

54

55

// Request logging

56

public void log(Request request, Response response);

57

}

58

```

59

60

## Basic Request Logging Setup

61

62

```java

63

public class BasicRequestLogging {

64

65

public void setupRequestLogging(Server server) {

66

// Create request log writer to file

67

RequestLogWriter logWriter = new RequestLogWriter("logs/access.log");

68

69

// Configure log rotation

70

logWriter.setRetainDays(30); // Keep 30 days of logs

71

logWriter.setAppend(true); // Append to existing log

72

73

// Create custom request log with NCSA format

74

CustomRequestLog requestLog = new CustomRequestLog(logWriter);

75

requestLog.setLogFormat(CustomRequestLog.NCSA_FORMAT);

76

77

// Set timezone for timestamps

78

requestLog.setLogTimeZone("UTC");

79

80

// Configure what to log

81

requestLog.setLogLatency(true); // Include response time

82

requestLog.setLogServer(true); // Include server info

83

requestLog.setLogCookies(new String[]{"JSESSIONID"}); // Log specific cookies

84

85

// Assign to server

86

server.setRequestLog(requestLog);

87

}

88

}

89

```

90

91

## Log Formats

92

93

### Standard Log Formats

94

95

```java

96

public class LogFormatExamples {

97

98

public void demonstrateLogFormats() {

99

// NCSA Common Log Format

100

String ncsaFormat = CustomRequestLog.NCSA_FORMAT;

101

// %{client}a - %u %t "%r" %>s %O

102

103

// Extended NCSA format

104

String extendedFormat = CustomRequestLog.EXTENDED_NCSA_FORMAT;

105

// %{client}a - %u %t "%r" %>s %O "%{Referer}i" "%{User-Agent}i"

106

107

// Custom format with response time and additional fields

108

String customFormat = "%{client}a - %u %t \"%r\" %>s %O %D \"%{Referer}i\" \"%{User-Agent}i\"";

109

110

CustomRequestLog requestLog = new CustomRequestLog();

111

requestLog.setLogFormat(customFormat);

112

}

113

114

public void explainFormatTokens() {

115

/*

116

* Format tokens:

117

* %a - Remote IP address

118

* %{client}a - Client IP address (real client behind proxy)

119

* %A - Local IP address

120

* %b - Bytes sent (CLF format)

121

* %B - Bytes sent

122

* %D - Time taken to process request (microseconds)

123

* %h - Remote host name

124

* %H - Request protocol

125

* %l - Remote logical username (identd)

126

* %m - Request method

127

* %O - Bytes sent including headers

128

* %q - Query string (prepended with ?)

129

* %r - First line of request

130

* %s - Response status

131

* %>s - Final response status

132

* %t - Time (CLF format)

133

* %{format}t - Time with custom format

134

* %T - Time taken (seconds)

135

* %u - Remote user

136

* %U - Requested URL path

137

* %v - Server name

138

* %{header}i - Request header

139

* %{header}o - Response header

140

* %{cookie}C - Request cookie

141

* %{cookie}c - Response cookie

142

*/

143

}

144

}

145

```

146

147

### Custom Log Format Examples

148

149

```java

150

// Detailed access log with timing and security info

151

String detailedFormat = "%{client}a %l %u %t \"%r\" %>s %b %D " +

152

"\"%{Referer}i\" \"%{User-Agent}i\" " +

153

"\"%{X-Forwarded-For}i\" \"%{Authorization}i\"";

154

155

// JSON-style log format

156

String jsonFormat = "{\"timestamp\":\"%t\", \"client\":\"%{client}a\", " +

157

"\"method\":\"%m\", \"uri\":\"%U\", \"query\":\"%q\", " +

158

"\"status\":%>s, \"bytes\":%b, \"duration\":%D, " +

159

"\"referer\":\"%{Referer}i\", \"userAgent\":\"%{User-Agent}i\"}";

160

161

// Performance monitoring format

162

String performanceFormat = "%t %{client}a %m %U %>s %b %D %T";

163

164

// Security audit format

165

String securityFormat = "%t %{client}a \"%r\" %>s \"%{Authorization}i\" " +

166

"\"%{X-Forwarded-For}i\" \"%{X-Real-IP}i\"";

167

```

168

169

## Request Log Writers

170

171

### RequestLogWriter

172

173

File-based request log writer with rotation support.

174

175

```java { .api }

176

public class RequestLogWriter extends AbstractLifeCycle implements RequestLog.Writer {

177

// Constructors

178

public RequestLogWriter();

179

public RequestLogWriter(String filename);

180

181

// File configuration

182

public void setFilename(String filename);

183

public String getFilename();

184

public void setAppend(boolean append);

185

public boolean isAppend();

186

187

// Rotation configuration

188

public void setRetainDays(int retainDays);

189

public int getRetainDays();

190

public void setFilenameDateFormat(String filenameDateFormat);

191

public String getFilenameDateFormat();

192

193

// Buffering

194

public void setBufferedLogs(boolean bufferedLogs);

195

public boolean isBufferedLogs();

196

197

// Writing

198

public void write(String requestEntry) throws IOException;

199

public void closeWriter() throws IOException;

200

}

201

```

202

203

### AsyncRequestLogWriter

204

205

Asynchronous request log writer for high-performance logging.

206

207

```java { .api }

208

public class AsyncRequestLogWriter extends RequestLogWriter {

209

// Queue configuration

210

public void setQueueSize(int queueSize);

211

public int getQueueSize();

212

213

// Async behavior

214

public boolean dispatch(String entry);

215

public void flush() throws IOException;

216

}

217

```

218

219

### Slf4jRequestLogWriter

220

221

SLF4J-based request log writer for integration with logging frameworks.

222

223

```java { .api }

224

public class Slf4jRequestLogWriter extends AbstractLifeCycle implements RequestLog.Writer {

225

// Constructors

226

public Slf4jRequestLogWriter();

227

public Slf4jRequestLogWriter(Logger logger);

228

229

// Logger configuration

230

public void setLoggerName(String loggerName);

231

public String getLoggerName();

232

public Logger getLogger();

233

234

// Log level

235

public void setLogLevel(Level level);

236

public Level getLogLevel();

237

238

// Writing

239

public void write(String requestEntry) throws IOException;

240

}

241

```

242

243

## Advanced Request Logging Configuration

244

245

```java

246

public class AdvancedRequestLogging {

247

248

public void setupMultipleLoggers(Server server) {

249

// Main access log

250

RequestLogWriter mainLogWriter = new RequestLogWriter("logs/access.log");

251

mainLogWriter.setRetainDays(90);

252

mainLogWriter.setFilenameDateFormat("yyyy-MM-dd");

253

254

CustomRequestLog mainLog = new CustomRequestLog(mainLogWriter,

255

CustomRequestLog.EXTENDED_NCSA_FORMAT);

256

257

// Error log (4xx and 5xx responses only)

258

RequestLogWriter errorLogWriter = new RequestLogWriter("logs/error.log");

259

CustomRequestLog errorLog = new FilteredRequestLog(errorLogWriter) {

260

@Override

261

protected boolean shouldLog(Request request, Response response) {

262

return response.getStatus() >= 400;

263

}

264

};

265

266

// Performance log (slow requests only)

267

AsyncRequestLogWriter perfLogWriter = new AsyncRequestLogWriter();

268

perfLogWriter.setFilename("logs/performance.log");

269

perfLogWriter.setQueueSize(10000);

270

271

CustomRequestLog perfLog = new TimingRequestLog(perfLogWriter) {

272

@Override

273

protected boolean shouldLog(Request request, Response response) {

274

return getResponseTime() > 1000; // Log requests > 1 second

275

}

276

};

277

278

// Combine multiple loggers

279

CompositeRequestLog compositeLog = new CompositeRequestLog(

280

mainLog, errorLog, perfLog);

281

282

server.setRequestLog(compositeLog);

283

}

284

285

public void setupSLF4JLogging() {

286

// Use SLF4J for request logging

287

Slf4jRequestLogWriter slf4jWriter = new Slf4jRequestLogWriter();

288

slf4jWriter.setLoggerName("jetty.access");

289

slf4jWriter.setLogLevel(Level.INFO);

290

291

CustomRequestLog requestLog = new CustomRequestLog(slf4jWriter);

292

requestLog.setLogFormat("%t %{client}a \"%r\" %>s %b %D");

293

294

server.setRequestLog(requestLog);

295

}

296

}

297

```

298

299

## Custom Request Log Implementations

300

301

### Filtered Request Log

302

303

```java

304

public abstract class FilteredRequestLog extends CustomRequestLog {

305

306

public FilteredRequestLog(RequestLog.Writer writer) {

307

super(writer);

308

}

309

310

public FilteredRequestLog(RequestLog.Writer writer, String format) {

311

super(writer, format);

312

}

313

314

@Override

315

public void log(Request request, Response response) {

316

if (shouldLog(request, response)) {

317

super.log(request, response);

318

}

319

}

320

321

protected abstract boolean shouldLog(Request request, Response response);

322

}

323

324

// Example usage

325

public class APIRequestLog extends FilteredRequestLog {

326

327

public APIRequestLog(RequestLog.Writer writer) {

328

super(writer, "%t %{client}a \"%r\" %>s %b %D \"%{Authorization}i\"");

329

}

330

331

@Override

332

protected boolean shouldLog(Request request, Response response) {

333

// Only log API requests

334

return request.getHttpURI().getPath().startsWith("/api/");

335

}

336

}

337

```

338

339

### Database Request Log

340

341

```java

342

public class DatabaseRequestLog implements RequestLog {

343

private final DataSource dataSource;

344

private final String insertSQL =

345

"INSERT INTO access_log (timestamp, client_ip, method, uri, status, " +

346

"bytes_sent, response_time, user_agent, referer) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";

347

348

public DatabaseRequestLog(DataSource dataSource) {

349

this.dataSource = dataSource;

350

}

351

352

@Override

353

public void log(Request request, Response response) {

354

try (Connection conn = dataSource.getConnection();

355

PreparedStatement stmt = conn.prepareStatement(insertSQL)) {

356

357

stmt.setTimestamp(1, new Timestamp(System.currentTimeMillis()));

358

stmt.setString(2, request.getConnectionMetaData().getRemoteSocketAddress().toString());

359

stmt.setString(3, request.getMethod());

360

stmt.setString(4, request.getHttpURI().toString());

361

stmt.setInt(5, response.getStatus());

362

stmt.setLong(6, response.getBytesWritten());

363

stmt.setLong(7, getResponseTime(request));

364

stmt.setString(8, request.getHeaders().get("User-Agent"));

365

stmt.setString(9, request.getHeaders().get("Referer"));

366

367

stmt.executeUpdate();

368

369

} catch (SQLException e) {

370

System.err.println("Failed to log request to database: " + e.getMessage());

371

}

372

}

373

374

private long getResponseTime(Request request) {

375

Long startTime = (Long) request.getAttribute("startTime");

376

return startTime != null ? System.currentTimeMillis() - startTime : 0;

377

}

378

}

379

```

380

381

### Composite Request Log

382

383

```java

384

public class CompositeRequestLog implements RequestLog {

385

private final List<RequestLog> requestLogs;

386

387

public CompositeRequestLog(RequestLog... requestLogs) {

388

this.requestLogs = Arrays.asList(requestLogs);

389

}

390

391

@Override

392

public void log(Request request, Response response) {

393

for (RequestLog requestLog : requestLogs) {

394

try {

395

requestLog.log(request, response);

396

} catch (Exception e) {

397

System.err.println("Error in composite request log: " + e.getMessage());

398

}

399

}

400

}

401

}

402

```

403

404

## Request Timing Integration

405

406

### Timing Handler with Request Logging

407

408

```java

409

public class TimingHandler extends Handler.Wrapper {

410

411

@Override

412

public boolean handle(Request request, Response response, Callback callback)

413

throws Exception {

414

415

long startTime = System.nanoTime();

416

request.setAttribute("startTime", startTime);

417

418

// Wrap callback to capture end time

419

Callback timingCallback = new Callback() {

420

@Override

421

public void succeeded() {

422

long endTime = System.nanoTime();

423

long duration = endTime - startTime;

424

request.setAttribute("responseTime", duration / 1_000_000); // Convert to milliseconds

425

callback.succeeded();

426

}

427

428

@Override

429

public void failed(Throwable x) {

430

long endTime = System.nanoTime();

431

long duration = endTime - startTime;

432

request.setAttribute("responseTime", duration / 1_000_000);

433

callback.failed(x);

434

}

435

};

436

437

return super.handle(request, response, timingCallback);

438

}

439

}

440

441

// Custom request log that includes timing

442

public class TimingRequestLog extends CustomRequestLog {

443

444

public TimingRequestLog(RequestLog.Writer writer) {

445

super(writer, "%t %{client}a \"%r\" %>s %b %{responseTime}ra ms");

446

}

447

448

protected long getResponseTime() {

449

// Access timing information from request attributes

450

return 0; // Implementation depends on how timing is stored

451

}

452

}

453

```

454

455

## Log Analysis and Monitoring

456

457

### Real-time Log Monitoring

458

459

```java

460

public class LogMonitoringHandler extends Handler.Wrapper {

461

private final AtomicLong requestCount = new AtomicLong();

462

private final AtomicLong errorCount = new AtomicLong();

463

private final Map<String, AtomicLong> statusCounts = new ConcurrentHashMap<>();

464

465

@Override

466

public boolean handle(Request request, Response response, Callback callback)

467

throws Exception {

468

469

requestCount.incrementAndGet();

470

471

Callback monitoringCallback = new Callback() {

472

@Override

473

public void succeeded() {

474

recordResponse(response.getStatus());

475

callback.succeeded();

476

}

477

478

@Override

479

public void failed(Throwable x) {

480

errorCount.incrementAndGet();

481

callback.failed(x);

482

}

483

};

484

485

return super.handle(request, response, monitoringCallback);

486

}

487

488

private void recordResponse(int status) {

489

String statusCategory = getStatusCategory(status);

490

statusCounts.computeIfAbsent(statusCategory, k -> new AtomicLong()).incrementAndGet();

491

492

if (status >= 400) {

493

errorCount.incrementAndGet();

494

}

495

}

496

497

private String getStatusCategory(int status) {

498

if (status < 300) return "2xx";

499

if (status < 400) return "3xx";

500

if (status < 500) return "4xx";

501

return "5xx";

502

}

503

504

public long getRequestCount() { return requestCount.get(); }

505

public long getErrorCount() { return errorCount.get(); }

506

public Map<String, Long> getStatusCounts() {

507

return statusCounts.entrySet().stream()

508

.collect(Collectors.toMap(

509

Map.Entry::getKey,

510

e -> e.getValue().get()

511

));

512

}

513

}

514

```