CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-eclipse-jetty--jetty-servlet

Eclipse Jetty servlet container providing comprehensive servlet, filter, and listener integration with lifecycle management and dynamic registration support.

Pending
Overview
Eval results
Files

monitoring.mddocs/

Monitoring and Statistics

Eclipse Jetty provides comprehensive monitoring and statistics capabilities through the StatisticsServlet for runtime metrics and JMX support for management and monitoring integration with enterprise management systems.

StatisticsServlet

The StatisticsServlet provides HTTP access to server runtime statistics and performance metrics.

public class StatisticsServlet extends HttpServlet {
    // Constructor
    public StatisticsServlet();
    
    // Servlet lifecycle
    public void init(ServletConfig config);
    
    // Request handling
    protected void doGet(HttpServletRequest req, HttpServletResponse resp);
    protected void doPost(HttpServletRequest req, HttpServletResponse resp);
}

JMX Support Classes

Eclipse Jetty provides JMX management beans for comprehensive monitoring and management.

HolderMBean

// JMX management bean for holders (ServletHolder, FilterHolder, ListenerHolder)
public class HolderMBean extends ObjectMBean {
    // Provides JMX access to holder properties and lifecycle
}

FilterMappingMBean

// JMX management bean for filter mappings
public class FilterMappingMBean extends ObjectMBean {
    // Provides JMX access to filter mapping configuration
}

ServletMappingMBean

// JMX management bean for servlet mappings
public class ServletMappingMBean extends ObjectMBean {
    // Provides JMX access to servlet mapping configuration
}

DefaultServlet Monitoring

The DefaultServlet provides resource serving capabilities with built-in monitoring support.

public class DefaultServlet extends HttpServlet implements ResourceFactory, WelcomeFactory {
    // Initialization and configuration
    public void init();
    public String getInitParameter(String name);
    
    // Resource access with monitoring
    public Resource getResource(String pathInContext);
    public String getWelcomeFile(String pathInContext);
    
    // HTTP method handlers with performance tracking
    protected void doGet(HttpServletRequest request, HttpServletResponse response);
    protected void doPost(HttpServletRequest request, HttpServletResponse response);
    protected void doPut(HttpServletRequest request, HttpServletResponse response);
    protected void doDelete(HttpServletRequest request, HttpServletResponse response);
    protected void doOptions(HttpServletRequest request, HttpServletResponse response);
    protected void doTrace(HttpServletRequest request, HttpServletResponse response);
}

Usage Examples

Basic StatisticsServlet Configuration

import org.eclipse.jetty.servlet.StatisticsServlet;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.server.Server;

// Configure statistics servlet
ServletContextHandler context = new ServletContextHandler("/app");

// Add statistics servlet
ServletHolder statsServlet = new ServletHolder("statistics", StatisticsServlet.class);
context.addServlet(statsServlet, "/stats");

// Optional: Restrict access to statistics
FilterHolder securityFilter = new FilterHolder(AdminSecurityFilter.class);
context.addFilter(securityFilter, "/stats", EnumSet.of(DispatcherType.REQUEST));

// Add to server
Server server = new Server(8080);
server.setHandler(context);
server.start();

// Access statistics at: http://localhost:8080/app/stats

Custom Statistics Collection

import org.eclipse.jetty.server.handler.StatisticsHandler;
import org.eclipse.jetty.servlet.ServletContextHandler;

// Add statistics handler to collect metrics
StatisticsHandler statsHandler = new StatisticsHandler();
ServletContextHandler context = new ServletContextHandler("/app");

// Wrap context with statistics handler
statsHandler.setHandler(context);

// Add application servlets
context.addServlet(MyApplicationServlet.class, "/api/*");
context.addServlet(StatisticsServlet.class, "/admin/stats");

// Configure server with statistics collection
Server server = new Server(8080);
server.setHandler(statsHandler);
server.start();

// Custom statistics servlet that exposes StatisticsHandler metrics
public class CustomStatisticsServlet extends HttpServlet {
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
            throws IOException {
        
        // Find statistics handler in the handler hierarchy
        StatisticsHandler statsHandler = findStatisticsHandler();
        
        if (statsHandler == null) {
            resp.sendError(503, "Statistics not available");
            return;
        }
        
        // Generate statistics response
        resp.setContentType("application/json");
        PrintWriter out = resp.getWriter();
        
        out.println("{");
        out.println("  \"requests\": " + statsHandler.getRequests() + ",");
        out.println("  \"requestsActive\": " + statsHandler.getRequestsActive() + ",");
        out.println("  \"requestTimeMax\": " + statsHandler.getRequestTimeMax() + ",");
        out.println("  \"requestTimeMean\": " + statsHandler.getRequestTimeMean() + ",");
        out.println("  \"requestTimeStdDev\": " + statsHandler.getRequestTimeStdDev() + ",");
        out.println("  \"responses1xx\": " + statsHandler.getResponses1xx() + ",");
        out.println("  \"responses2xx\": " + statsHandler.getResponses2xx() + ",");
        out.println("  \"responses3xx\": " + statsHandler.getResponses3xx() + ",");
        out.println("  \"responses4xx\": " + statsHandler.getResponses4xx() + ",");
        out.println("  \"responses5xx\": " + statsHandler.getResponses5xx() + ",");
        out.println("  \"bytesReceived\": " + statsHandler.getBytesReceived() + ",");
        out.println("  \"bytesSent\": " + statsHandler.getBytesSent() + ",");
        out.println("  \"statsOnMs\": " + statsHandler.getStatsOnMs());
        out.println("}");
    }
    
    private StatisticsHandler findStatisticsHandler() {
        // Navigate handler hierarchy to find StatisticsHandler
        ServletContext context = getServletContext();
        ServletContextHandler contextHandler = 
            ServletContextHandler.getServletContextHandler(context);
        
        Handler handler = contextHandler;
        while (handler != null) {
            if (handler instanceof StatisticsHandler) {
                return (StatisticsHandler) handler;
            }
            if (handler instanceof HandlerWrapper) {
                handler = ((HandlerWrapper) handler).getHandler();
            } else {
                break;
            }
        }
        return null;
    }
}

JMX Integration

import org.eclipse.jetty.jmx.MBeanContainer;
import org.eclipse.jetty.server.Server;
import javax.management.MBeanServer;
import java.lang.management.ManagementFactory;

// Enable JMX monitoring
public class JMXMonitoringSetup {
    
    public static Server createServerWithJMX() throws Exception {
        // Get platform MBean server
        MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
        
        // Create MBean container
        MBeanContainer mbeanContainer = new MBeanContainer(mbeanServer);
        
        // Create server
        Server server = new Server(8080);
        
        // Add MBean container to server
        server.addBean(mbeanContainer);
        
        // Configure servlet context with JMX
        ServletContextHandler context = new ServletContextHandler("/app");
        
        // Add servlets and filters - they will be automatically exposed via JMX
        ServletHolder dataServlet = new ServletHolder("dataServlet", DataServlet.class);
        dataServlet.setDisplayName("Data Processing Servlet");
        context.addServlet(dataServlet, "/data/*");
        
        FilterHolder loggingFilter = new FilterHolder("loggingFilter", LoggingFilter.class);
        loggingFilter.setDisplayName("Request Logging Filter");
        context.addFilter(loggingFilter, "/*", EnumSet.of(DispatcherType.REQUEST));
        
        // Add statistics servlet for HTTP access to metrics
        context.addServlet(StatisticsServlet.class, "/admin/stats");
        
        server.setHandler(context);
        return server;
    }
}

// Custom MBean for application-specific metrics
public interface ApplicationMetricsMBean {
    long getActiveUserCount();
    long getTotalTransactions();
    double getAverageResponseTime();
    String getHealthStatus();
    void resetCounters();
}

public class ApplicationMetrics implements ApplicationMetricsMBean {
    private final AtomicLong activeUsers = new AtomicLong();
    private final AtomicLong totalTransactions = new AtomicLong();
    private final AtomicLong totalResponseTime = new AtomicLong();
    private volatile String healthStatus = "HEALTHY";
    
    @Override
    public long getActiveUserCount() {
        return activeUsers.get();
    }
    
    @Override
    public long getTotalTransactions() {
        return totalTransactions.get();
    }
    
    @Override
    public double getAverageResponseTime() {
        long transactions = totalTransactions.get();
        return transactions > 0 ? (double) totalResponseTime.get() / transactions : 0.0;
    }
    
    @Override
    public String getHealthStatus() {
        return healthStatus;
    }
    
    @Override
    public void resetCounters() {
        totalTransactions.set(0);
        totalResponseTime.set(0);
        // Don't reset active users as it's current state
    }
    
    // Methods for internal use
    public void incrementActiveUsers() {
        activeUsers.incrementAndGet();
    }
    
    public void decrementActiveUsers() {
        activeUsers.decrementAndGet();
    }
    
    public void recordTransaction(long responseTimeMs) {
        totalTransactions.incrementAndGet();
        totalResponseTime.addAndGet(responseTimeMs);
    }
    
    public void setHealthStatus(String status) {
        this.healthStatus = status;
    }
}

// Register custom MBean
public class ApplicationMetricsSetup {
    
    public static void registerApplicationMetrics(Server server, ApplicationMetrics metrics) 
            throws Exception {
        MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
        ObjectName objectName = new ObjectName("org.eclipse.jetty.servlet:type=ApplicationMetrics");
        mbeanServer.registerMBean(metrics, objectName);
        
        // Make metrics available to servlets via servlet context
        ServletContextHandler context = (ServletContextHandler) server.getHandler();
        context.getServletContext().setAttribute("applicationMetrics", metrics);
    }
}

Performance Monitoring Filter

import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

public class PerformanceMonitoringFilter implements Filter {
    private ApplicationMetrics metrics;
    
    @Override
    public void init(FilterConfig filterConfig) {
        ServletContext context = filterConfig.getServletContext();
        metrics = (ApplicationMetrics) context.getAttribute("applicationMetrics");
    }
    
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, 
                        FilterChain chain) throws IOException, ServletException {
        
        HttpServletRequest httpReq = (HttpServletRequest) request;
        HttpServletResponse httpResp = (HttpServletResponse) response;
        
        long startTime = System.currentTimeMillis();
        
        // Track active users (sessions)
        HttpSession session = httpReq.getSession(false);
        boolean newSession = false;
        if (session == null) {
            session = httpReq.getSession(true);
            newSession = true;
            if (metrics != null) {
                metrics.incrementActiveUsers();
            }
        }
        
        try {
            chain.doFilter(request, response);
        } finally {
            long responseTime = System.currentTimeMillis() - startTime;
            
            // Record performance metrics
            if (metrics != null) {
                metrics.recordTransaction(responseTime);
                
                // Check for error conditions
                int status = httpResp.getStatus();
                if (status >= 500) {
                    metrics.setHealthStatus("DEGRADED");
                }
            }
            
            // Log slow requests
            if (responseTime > 5000) { // 5 seconds
                System.err.println("SLOW REQUEST: " + httpReq.getRequestURI() + 
                                 " took " + responseTime + "ms");
            }
        }
    }
    
    @Override
    public void destroy() {
        // Cleanup
    }
}

// Session listener to track user sessions
public class UserSessionListener implements HttpSessionListener {
    private ApplicationMetrics metrics;
    
    public UserSessionListener(ApplicationMetrics metrics) {
        this.metrics = metrics;
    }
    
    @Override
    public void sessionCreated(HttpSessionEvent se) {
        // Already tracked in filter when session is created
    }
    
    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        if (metrics != null) {
            metrics.decrementActiveUsers();
        }
    }
}

Health Check Servlet

public class HealthCheckServlet extends HttpServlet {
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
            throws IOException {
        
        ServletContext context = getServletContext();
        ApplicationMetrics metrics = (ApplicationMetrics) context.getAttribute("applicationMetrics");
        
        // Perform health checks
        HealthStatus status = performHealthChecks();
        
        // Set response status based on health
        if (status.isHealthy()) {
            resp.setStatus(200);
        } else {
            resp.setStatus(503); // Service Unavailable
        }
        
        // Generate health report
        resp.setContentType("application/json");
        PrintWriter out = resp.getWriter();
        
        out.println("{");
        out.println("  \"status\": \"" + status.getOverallStatus() + "\",");
        out.println("  \"timestamp\": " + System.currentTimeMillis() + ",");
        
        if (metrics != null) {
            out.println("  \"activeUsers\": " + metrics.getActiveUserCount() + ",");
            out.println("  \"totalTransactions\": " + metrics.getTotalTransactions() + ",");
            out.println("  \"averageResponseTime\": " + metrics.getAverageResponseTime() + ",");
            out.println("  \"applicationStatus\": \"" + metrics.getHealthStatus() + "\",");
        }
        
        out.println("  \"checks\": {");
        
        Map<String, Boolean> checks = status.getChecks();
        boolean first = true;
        for (Map.Entry<String, Boolean> check : checks.entrySet()) {
            if (!first) out.println(",");
            out.println("    \"" + check.getKey() + "\": " + check.getValue());
            first = false;
        }
        
        out.println("  }");
        out.println("}");
    }
    
    private HealthStatus performHealthChecks() {
        Map<String, Boolean> checks = new HashMap<>();
        
        // Database connectivity check
        checks.put("database", checkDatabaseConnection());
        
        // External service checks
        checks.put("externalAPI", checkExternalService());
        
        // File system checks
        checks.put("fileSystem", checkFileSystemAccess());
        
        // Memory check
        checks.put("memory", checkMemoryUsage());
        
        // Determine overall status
        boolean allHealthy = checks.values().stream().allMatch(Boolean::booleanValue);
        String overallStatus = allHealthy ? "HEALTHY" : "UNHEALTHY";
        
        return new HealthStatus(overallStatus, checks);
    }
    
    private boolean checkDatabaseConnection() {
        try {
            // Attempt database connection
            // Return true if successful, false otherwise
            return true; // Placeholder
        } catch (Exception e) {
            return false;
        }
    }
    
    private boolean checkExternalService() {
        try {
            // Check external service availability
            // Return true if reachable, false otherwise
            return true; // Placeholder
        } catch (Exception e) {
            return false;
        }
    }
    
    private boolean checkFileSystemAccess() {
        try {
            // Check file system read/write access
            File tempFile = File.createTempFile("health", ".check");
            boolean canWrite = tempFile.exists();
            tempFile.delete();
            return canWrite;
        } catch (Exception e) {
            return false;
        }
    }
    
    private boolean checkMemoryUsage() {
        Runtime runtime = Runtime.getRuntime();
        long maxMemory = runtime.maxMemory();
        long totalMemory = runtime.totalMemory();
        long freeMemory = runtime.freeMemory();
        long usedMemory = totalMemory - freeMemory;
        
        // Consider unhealthy if using more than 90% of max memory
        double memoryUsage = (double) usedMemory / maxMemory;
        return memoryUsage < 0.90;
    }
    
    // Helper class for health status
    private static class HealthStatus {
        private final String overallStatus;
        private final Map<String, Boolean> checks;
        
        public HealthStatus(String overallStatus, Map<String, Boolean> checks) {
            this.overallStatus = overallStatus;
            this.checks = new HashMap<>(checks);
        }
        
        public boolean isHealthy() {
            return "HEALTHY".equals(overallStatus);
        }
        
        public String getOverallStatus() {
            return overallStatus;
        }
        
        public Map<String, Boolean> getChecks() {
            return checks;
        }
    }
}

Complete Monitoring Setup

// Complete monitoring and statistics setup
public class MonitoringConfiguration {
    
    public static Server createMonitoredServer() throws Exception {
        // Enable JMX
        MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
        MBeanContainer mbeanContainer = new MBeanContainer(mbeanServer);
        
        // Create server with statistics
        Server server = new Server(8080);
        server.addBean(mbeanContainer);
        
        // Add statistics handler
        StatisticsHandler statsHandler = new StatisticsHandler();
        
        // Create application context
        ServletContextHandler context = new ServletContextHandler("/app");
        
        // Create and register application metrics
        ApplicationMetrics appMetrics = new ApplicationMetrics();
        registerApplicationMetrics(server, appMetrics);
        context.getServletContext().setAttribute("applicationMetrics", appMetrics);
        
        // Add performance monitoring filter
        FilterHolder perfFilter = new FilterHolder(PerformanceMonitoringFilter.class);
        context.addFilter(perfFilter, "/*", EnumSet.of(DispatcherType.REQUEST));
        
        // Add session listener
        context.addEventListener(new UserSessionListener(appMetrics));
        
        // Add application servlets
        context.addServlet(MyApplicationServlet.class, "/api/*");
        
        // Add monitoring endpoints
        addMonitoringEndpoints(context);
        
        // Wire handlers together
        statsHandler.setHandler(context);
        server.setHandler(statsHandler);
        
        return server;
    }
    
    private static void addMonitoringEndpoints(ServletContextHandler context) {
        // Statistics servlet (built-in Jetty statistics)
        context.addServlet(StatisticsServlet.class, "/admin/stats");
        
        // Custom statistics servlet (application + server metrics)
        context.addServlet(CustomStatisticsServlet.class, "/admin/metrics");
        
        // Health check endpoint
        context.addServlet(HealthCheckServlet.class, "/admin/health");
        
        // JMX servlet (if needed for HTTP access to JMX)
        context.addServlet(JMXServlet.class, "/admin/jmx");
        
        // Restrict access to admin endpoints
        FilterHolder adminFilter = new FilterHolder(AdminSecurityFilter.class);
        context.addFilter(adminFilter, "/admin/*", EnumSet.of(DispatcherType.REQUEST));
    }
    
    private static void registerApplicationMetrics(Server server, ApplicationMetrics metrics) 
            throws Exception {
        MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
        ObjectName objectName = new ObjectName("org.eclipse.jetty.servlet:type=ApplicationMetrics");
        mbeanServer.registerMBean(metrics, objectName);
    }
}

// Usage
public class MonitoredApplication {
    public static void main(String[] args) throws Exception {
        Server server = MonitoringConfiguration.createMonitoredServer();
        server.start();
        
        System.out.println("Server started with monitoring:");
        System.out.println("  Application: http://localhost:8080/app/");
        System.out.println("  Statistics: http://localhost:8080/app/admin/stats");
        System.out.println("  Metrics: http://localhost:8080/app/admin/metrics");  
        System.out.println("  Health: http://localhost:8080/app/admin/health");
        System.out.println("  JMX: Available via JConsole or similar tools");
        
        server.join();
    }
}

Install with Tessl CLI

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

docs

error-handling.md

filter-handling.md

index.md

listeners.md

monitoring.md

servlet-context.md

servlet-handling.md

testing.md

tile.json