Skip to content

Instantly share code, notes, and snippets.

@cdmatta
Created April 12, 2018 21:13
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save cdmatta/2a4536ab687bf7a92482faf031e8a0b5 to your computer and use it in GitHub Desktop.
Save cdmatta/2a4536ab687bf7a92482faf031e8a0b5 to your computer and use it in GitHub Desktop.
Spring boot + Undertow access log, capture/record request processing time. Customize UndertowWebServerFactory
server.undertow.accesslog.pattern=%h %l %u %t "%r" %s %b "%{i,Referer}" "%{i,User-Agent}" %D
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>io.cm</groupId>
<artifactId>undertow-accesslog</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
package io.cm.accesslog;
import io.undertow.Undertow;
import io.undertow.UndertowOptions;
import io.undertow.server.handlers.accesslog.AccessLogHandler;
import io.undertow.server.handlers.accesslog.AccessLogReceiver;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.web.embedded.undertow.ConfigurableUndertowWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
public class UndertowAccessLogApplication {
public static void main(String[] args) {
SpringApplication.run(UndertowAccessLogApplication.class, args);
}
}
@RestController
class HelloController {
@RequestMapping("/")
public String index() {
return "Hello world!";
}
}
@Component
class UndertowWebServerAccessLogTimingEnabler implements WebServerFactoryCustomizer<ConfigurableUndertowWebServerFactory> {
private final ServerProperties serverProperties;
public UndertowWebServerAccessLogTimingEnabler(ServerProperties serverProperties) {
this.serverProperties = serverProperties;
}
@Override
public void customize(ConfigurableUndertowWebServerFactory factory) {
String pattern = serverProperties.getUndertow().getAccesslog().getPattern();
// Record request timing only if the pattern
if (logRequestProcessingTiming(pattern)) {
factory.addBuilderCustomizers(builder -> builder.setServerOption(UndertowOptions.RECORD_REQUEST_START_TIME, true));
}
// Custom access log receiver.
factory.addDeploymentInfoCustomizers(deploymentInfo -> {
deploymentInfo.addInitialHandlerChainWrapper(handler -> {
Slf4jAccessLogReceiver accessLogReceiver = new Slf4jAccessLogReceiver();
return new AccessLogHandler(handler, accessLogReceiver, pattern, Undertow.class.getClassLoader());
});
});
}
private boolean logRequestProcessingTiming(String pattern) {
if (StringUtils.isBlank(pattern)) {
return false;
}
return pattern.contains("%D") || pattern.contains("%T");
}
}
/**
* Direct access logs to slf4j. Can be sent to custom location with logger configuration.
* Default undertow access logs are in the launchDirectory/logs of the process
*/
@Slf4j(topic = "ACCESS_LOG")
class Slf4jAccessLogReceiver implements AccessLogReceiver {
@Override
public void logMessage(String message) {
log.info(message);
}
}
@tobias-lehmann-aperto
Copy link

hey, there is also a property for recording the request start time:
server.undertow.options.server.record-request-start-time=true

@cdmatta
Copy link
Author

cdmatta commented Apr 25, 2022

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment