CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-eclipse-jetty--jetty-server

Core server component of Eclipse Jetty web server providing HTTP server functionality, request handling, and connection management

Pending
Overview
Eval results
Files

request-logging.mddocs/

Request Logging

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

RequestLog Interface

The core interface for logging HTTP requests and responses.

public interface RequestLog {
    // Log a request/response pair
    void log(Request request, Response response);
    
    // Nested interface for log writers
    interface Writer {
        void write(String requestEntry) throws IOException;
    }
}

CustomRequestLog

Flexible request logger with customizable log formats and output destinations.

public class CustomRequestLog extends ContainerLifeCycle implements RequestLog {
    // Constructors
    public CustomRequestLog();
    public CustomRequestLog(RequestLog.Writer writer);
    public CustomRequestLog(RequestLog.Writer writer, String format);
    public CustomRequestLog(String filename);
    public CustomRequestLog(String filename, String format);
    
    // Format configuration
    public void setLogFormat(String format);
    public String getLogFormat();
    public void setLogTimeZone(String timeZone);
    public String getLogTimeZone();
    
    // Writer configuration
    public RequestLog.Writer getWriter();
    public void setWriter(RequestLog.Writer writer);
    
    // Cookie logging
    public String[] getLogCookies();
    public void setLogCookies(String[] logCookies);
    
    // Latency logging
    public boolean isLogLatency();
    public void setLogLatency(boolean logLatency);
    
    // Server information
    public boolean isLogServer();
    public void setLogServer(boolean logServer);
    
    // Request logging
    public void log(Request request, Response response);
}

Basic Request Logging Setup

public class BasicRequestLogging {
    
    public void setupRequestLogging(Server server) {
        // Create request log writer to file
        RequestLogWriter logWriter = new RequestLogWriter("logs/access.log");
        
        // Configure log rotation
        logWriter.setRetainDays(30);        // Keep 30 days of logs
        logWriter.setAppend(true);          // Append to existing log
        
        // Create custom request log with NCSA format
        CustomRequestLog requestLog = new CustomRequestLog(logWriter);
        requestLog.setLogFormat(CustomRequestLog.NCSA_FORMAT);
        
        // Set timezone for timestamps
        requestLog.setLogTimeZone("UTC");
        
        // Configure what to log
        requestLog.setLogLatency(true);     // Include response time
        requestLog.setLogServer(true);      // Include server info
        requestLog.setLogCookies(new String[]{"JSESSIONID"}); // Log specific cookies
        
        // Assign to server
        server.setRequestLog(requestLog);
    }
}

Log Formats

Standard Log Formats

public class LogFormatExamples {
    
    public void demonstrateLogFormats() {
        // NCSA Common Log Format
        String ncsaFormat = CustomRequestLog.NCSA_FORMAT;
        // %{client}a - %u %t "%r" %>s %O
        
        // Extended NCSA format
        String extendedFormat = CustomRequestLog.EXTENDED_NCSA_FORMAT;
        // %{client}a - %u %t "%r" %>s %O "%{Referer}i" "%{User-Agent}i"
        
        // Custom format with response time and additional fields
        String customFormat = "%{client}a - %u %t \"%r\" %>s %O %D \"%{Referer}i\" \"%{User-Agent}i\"";
        
        CustomRequestLog requestLog = new CustomRequestLog();
        requestLog.setLogFormat(customFormat);
    }
    
    public void explainFormatTokens() {
        /*
         * Format tokens:
         * %a - Remote IP address
         * %{client}a - Client IP address (real client behind proxy)
         * %A - Local IP address
         * %b - Bytes sent (CLF format)
         * %B - Bytes sent  
         * %D - Time taken to process request (microseconds)
         * %h - Remote host name
         * %H - Request protocol
         * %l - Remote logical username (identd)
         * %m - Request method
         * %O - Bytes sent including headers
         * %q - Query string (prepended with ?)
         * %r - First line of request
         * %s - Response status
         * %>s - Final response status
         * %t - Time (CLF format)
         * %{format}t - Time with custom format
         * %T - Time taken (seconds)
         * %u - Remote user
         * %U - Requested URL path
         * %v - Server name
         * %{header}i - Request header
         * %{header}o - Response header
         * %{cookie}C - Request cookie
         * %{cookie}c - Response cookie
         */
    }
}

Custom Log Format Examples

// Detailed access log with timing and security info
String detailedFormat = "%{client}a %l %u %t \"%r\" %>s %b %D " +
                       "\"%{Referer}i\" \"%{User-Agent}i\" " +
                       "\"%{X-Forwarded-For}i\" \"%{Authorization}i\"";

// JSON-style log format
String jsonFormat = "{\"timestamp\":\"%t\", \"client\":\"%{client}a\", " +
                   "\"method\":\"%m\", \"uri\":\"%U\", \"query\":\"%q\", " +
                   "\"status\":%>s, \"bytes\":%b, \"duration\":%D, " +
                   "\"referer\":\"%{Referer}i\", \"userAgent\":\"%{User-Agent}i\"}";

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

// Security audit format
String securityFormat = "%t %{client}a \"%r\" %>s \"%{Authorization}i\" " +
                       "\"%{X-Forwarded-For}i\" \"%{X-Real-IP}i\"";

Request Log Writers

RequestLogWriter

File-based request log writer with rotation support.

public class RequestLogWriter extends AbstractLifeCycle implements RequestLog.Writer {
    // Constructors
    public RequestLogWriter();
    public RequestLogWriter(String filename);
    
    // File configuration
    public void setFilename(String filename);
    public String getFilename();
    public void setAppend(boolean append);
    public boolean isAppend();
    
    // Rotation configuration
    public void setRetainDays(int retainDays);
    public int getRetainDays();
    public void setFilenameDateFormat(String filenameDateFormat);
    public String getFilenameDateFormat();
    
    // Buffering
    public void setBufferedLogs(boolean bufferedLogs);
    public boolean isBufferedLogs();
    
    // Writing
    public void write(String requestEntry) throws IOException;
    public void closeWriter() throws IOException;
}

AsyncRequestLogWriter

Asynchronous request log writer for high-performance logging.

public class AsyncRequestLogWriter extends RequestLogWriter {
    // Queue configuration
    public void setQueueSize(int queueSize);
    public int getQueueSize();
    
    // Async behavior
    public boolean dispatch(String entry);
    public void flush() throws IOException;
}

Slf4jRequestLogWriter

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

public class Slf4jRequestLogWriter extends AbstractLifeCycle implements RequestLog.Writer {
    // Constructors
    public Slf4jRequestLogWriter();
    public Slf4jRequestLogWriter(Logger logger);
    
    // Logger configuration
    public void setLoggerName(String loggerName);
    public String getLoggerName();
    public Logger getLogger();
    
    // Log level
    public void setLogLevel(Level level);
    public Level getLogLevel();
    
    // Writing
    public void write(String requestEntry) throws IOException;
}

Advanced Request Logging Configuration

public class AdvancedRequestLogging {
    
    public void setupMultipleLoggers(Server server) {
        // Main access log
        RequestLogWriter mainLogWriter = new RequestLogWriter("logs/access.log");
        mainLogWriter.setRetainDays(90);
        mainLogWriter.setFilenameDateFormat("yyyy-MM-dd");
        
        CustomRequestLog mainLog = new CustomRequestLog(mainLogWriter, 
            CustomRequestLog.EXTENDED_NCSA_FORMAT);
        
        // Error log (4xx and 5xx responses only)
        RequestLogWriter errorLogWriter = new RequestLogWriter("logs/error.log");
        CustomRequestLog errorLog = new FilteredRequestLog(errorLogWriter) {
            @Override
            protected boolean shouldLog(Request request, Response response) {
                return response.getStatus() >= 400;
            }
        };
        
        // Performance log (slow requests only)
        AsyncRequestLogWriter perfLogWriter = new AsyncRequestLogWriter();
        perfLogWriter.setFilename("logs/performance.log");
        perfLogWriter.setQueueSize(10000);
        
        CustomRequestLog perfLog = new TimingRequestLog(perfLogWriter) {
            @Override
            protected boolean shouldLog(Request request, Response response) {
                return getResponseTime() > 1000; // Log requests > 1 second
            }
        };
        
        // Combine multiple loggers
        CompositeRequestLog compositeLog = new CompositeRequestLog(
            mainLog, errorLog, perfLog);
        
        server.setRequestLog(compositeLog);
    }
    
    public void setupSLF4JLogging() {
        // Use SLF4J for request logging
        Slf4jRequestLogWriter slf4jWriter = new Slf4jRequestLogWriter();
        slf4jWriter.setLoggerName("jetty.access");
        slf4jWriter.setLogLevel(Level.INFO);
        
        CustomRequestLog requestLog = new CustomRequestLog(slf4jWriter);
        requestLog.setLogFormat("%t %{client}a \"%r\" %>s %b %D");
        
        server.setRequestLog(requestLog);
    }
}

Custom Request Log Implementations

Filtered Request Log

public abstract class FilteredRequestLog extends CustomRequestLog {
    
    public FilteredRequestLog(RequestLog.Writer writer) {
        super(writer);
    }
    
    public FilteredRequestLog(RequestLog.Writer writer, String format) {
        super(writer, format);
    }
    
    @Override
    public void log(Request request, Response response) {
        if (shouldLog(request, response)) {
            super.log(request, response);
        }
    }
    
    protected abstract boolean shouldLog(Request request, Response response);
}

// Example usage
public class APIRequestLog extends FilteredRequestLog {
    
    public APIRequestLog(RequestLog.Writer writer) {
        super(writer, "%t %{client}a \"%r\" %>s %b %D \"%{Authorization}i\"");
    }
    
    @Override
    protected boolean shouldLog(Request request, Response response) {
        // Only log API requests
        return request.getHttpURI().getPath().startsWith("/api/");
    }
}

Database Request Log

public class DatabaseRequestLog implements RequestLog {
    private final DataSource dataSource;
    private final String insertSQL = 
        "INSERT INTO access_log (timestamp, client_ip, method, uri, status, " +
        "bytes_sent, response_time, user_agent, referer) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
    
    public DatabaseRequestLog(DataSource dataSource) {
        this.dataSource = dataSource;
    }
    
    @Override
    public void log(Request request, Response response) {
        try (Connection conn = dataSource.getConnection();
             PreparedStatement stmt = conn.prepareStatement(insertSQL)) {
            
            stmt.setTimestamp(1, new Timestamp(System.currentTimeMillis()));
            stmt.setString(2, request.getConnectionMetaData().getRemoteSocketAddress().toString());
            stmt.setString(3, request.getMethod());
            stmt.setString(4, request.getHttpURI().toString());
            stmt.setInt(5, response.getStatus());
            stmt.setLong(6, response.getBytesWritten());
            stmt.setLong(7, getResponseTime(request));
            stmt.setString(8, request.getHeaders().get("User-Agent"));
            stmt.setString(9, request.getHeaders().get("Referer"));
            
            stmt.executeUpdate();
            
        } catch (SQLException e) {
            System.err.println("Failed to log request to database: " + e.getMessage());
        }
    }
    
    private long getResponseTime(Request request) {
        Long startTime = (Long) request.getAttribute("startTime");
        return startTime != null ? System.currentTimeMillis() - startTime : 0;
    }
}

Composite Request Log

public class CompositeRequestLog implements RequestLog {
    private final List<RequestLog> requestLogs;
    
    public CompositeRequestLog(RequestLog... requestLogs) {
        this.requestLogs = Arrays.asList(requestLogs);
    }
    
    @Override
    public void log(Request request, Response response) {
        for (RequestLog requestLog : requestLogs) {
            try {
                requestLog.log(request, response);
            } catch (Exception e) {
                System.err.println("Error in composite request log: " + e.getMessage());
            }
        }
    }
}

Request Timing Integration

Timing Handler with Request Logging

public class TimingHandler extends Handler.Wrapper {
    
    @Override
    public boolean handle(Request request, Response response, Callback callback) 
            throws Exception {
        
        long startTime = System.nanoTime();
        request.setAttribute("startTime", startTime);
        
        // Wrap callback to capture end time
        Callback timingCallback = new Callback() {
            @Override
            public void succeeded() {
                long endTime = System.nanoTime();
                long duration = endTime - startTime;
                request.setAttribute("responseTime", duration / 1_000_000); // Convert to milliseconds
                callback.succeeded();
            }
            
            @Override
            public void failed(Throwable x) {
                long endTime = System.nanoTime();
                long duration = endTime - startTime;
                request.setAttribute("responseTime", duration / 1_000_000);
                callback.failed(x);
            }
        };
        
        return super.handle(request, response, timingCallback);
    }
}

// Custom request log that includes timing
public class TimingRequestLog extends CustomRequestLog {
    
    public TimingRequestLog(RequestLog.Writer writer) {
        super(writer, "%t %{client}a \"%r\" %>s %b %{responseTime}ra ms");
    }
    
    protected long getResponseTime() {
        // Access timing information from request attributes
        return 0; // Implementation depends on how timing is stored
    }
}

Log Analysis and Monitoring

Real-time Log Monitoring

public class LogMonitoringHandler extends Handler.Wrapper {
    private final AtomicLong requestCount = new AtomicLong();
    private final AtomicLong errorCount = new AtomicLong();
    private final Map<String, AtomicLong> statusCounts = new ConcurrentHashMap<>();
    
    @Override
    public boolean handle(Request request, Response response, Callback callback) 
            throws Exception {
        
        requestCount.incrementAndGet();
        
        Callback monitoringCallback = new Callback() {
            @Override
            public void succeeded() {
                recordResponse(response.getStatus());
                callback.succeeded();
            }
            
            @Override
            public void failed(Throwable x) {
                errorCount.incrementAndGet();
                callback.failed(x);
            }
        };
        
        return super.handle(request, response, monitoringCallback);
    }
    
    private void recordResponse(int status) {
        String statusCategory = getStatusCategory(status);
        statusCounts.computeIfAbsent(statusCategory, k -> new AtomicLong()).incrementAndGet();
        
        if (status >= 400) {
            errorCount.incrementAndGet();
        }
    }
    
    private String getStatusCategory(int status) {
        if (status < 300) return "2xx";
        if (status < 400) return "3xx";
        if (status < 500) return "4xx";
        return "5xx";
    }
    
    public long getRequestCount() { return requestCount.get(); }
    public long getErrorCount() { return errorCount.get(); }
    public Map<String, Long> getStatusCounts() {
        return statusCounts.entrySet().stream()
            .collect(Collectors.toMap(
                Map.Entry::getKey, 
                e -> e.getValue().get()
            ));
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-org-eclipse-jetty--jetty-server

docs

configuration.md

connection-management.md

context-resources.md

handlers.md

index.md

request-logging.md

request-response.md

security-ssl.md

server-core.md

session-management.md

utility-handlers.md

tile.json