If you develop Java EE web services, I’m sure you’ve found yourself in a situation when you’d like to see HTTP requests coming to your application for a moment in order to help you debug an issue. Sure, you could extend ContainerRequestFilter and write a nice logging filter based on JAX-RS, but you just need something temporarily to help you diagnose this one issue you’re investigating. Luckily, WildFly provides a tool exactly for this purpose.

Undertow is a lightweight open-source Java web server, and the default web server in WildFly. It comes with several handlers, one of which is RequestDumpingHandler for logging HTTP exchanges.

For runtime activation of RequestDumpingHandler, execute the following CLI script:

/subsystem=undertow/configuration=filter/custom-filter=request-logging-filter:\
 add(class-name=io.undertow.server.handlers.RequestDumpingHandler,\
  module=io.undertow.core)
/subsystem=undertow/server=default-server/host=default-host/\
 filter-ref=request-logging-filter:add

Alternatively, you can adjust your WildFly configuration (e.g. standalone.xml) as follows:

...
<profile>
    ...
    <subsystem xmlns="urn:jboss:domain:undertow:3.0">
        ...
        <server name="default-server">
            ...
            <host name="default-host" alias="localhost">
                ...
                <filter-ref name="request-dumper"/>
            </host>
        </server>
        ...
        <filters>
            ...
            <filter name="request-dumper" module="io.undertow.core"
              class-name="io.undertow.server.handlers.RequestDumpingHandler"/>
        </filters>
    </subsystem>
    ...
</profile>
...

If the filter is set up correctly, curl localhost:8080 (assuming a local WildFly instance listening on localhost:8080) makes a message similar to the following snippet appear in the server log:

20:35:44,466 INFO  [io.undertow.request.dump] (default task-1)
----------------------------REQUEST---------------------------
               URI=/
 characterEncoding=null
     contentLength=-1
       contentType=null
            header=Accept=*/*
            header=User-Agent=curl/7.43.0
            header=Host=localhost:8080
            locale=[]
            method=GET
          protocol=HTTP/1.1
       queryString=
        remoteAddr=/127.0.0.1:65365
        remoteHost=localhost
            scheme=http
              host=localhost:8080
        serverPort=8080
--------------------------RESPONSE--------------------------
     contentLength=2438
       contentType=text/html
            header=Connection=keep-alive
            header=Last-Modified=Fri, 29 Jan 2016 21:12:32 GMT
            header=X-Powered-By=Undertow/1
            header=Server=WildFly/10
            header=Content-Length=2438
            header=Content-Type=text/html
            header=Date=Thu, 04 Aug 2016 00:35:44 GMT
            status=200
==============================================================

The full CLI script is available as a gist on GitHub. Note that RequestDumpingHandler is verbose and offers basically no customization options. As such, it’s suitable for one-off debugging activities rather than continuous usage. Definitely consider turning it off for your production deployment.

If you’re looking for something like the access log from Apache HTTP Server, something more concise, customizable, and suitable for production, Undertow has you covered. To set up a simple access log, execute the following CLI command:

/subsystem=undertow/server=default-server/host=default-host/setting=access-log:\
  add(pattern="%h %t \"%r\" %s \"%{i,User-Agent}\"", use-server-log=true)

Alternatively, you can adjust your WildFly configuration (e.g. standalone.xml) as follows:

...
<profile>
    ...
    <subsystem xmlns="urn:jboss:domain:undertow:3.0">
        ...
        <server name="default-server">
            ...
            <host name="default-host" alias="localhost">
                ...
                <access-log use-server-log="true" 
                  pattern="%h %t &quot;%r&quot; %s &quot;%{i,User-Agent}&quot;"/>
                ...
            </host>
        </server>
        ...
    </subsystem>
    ...
</profile>
...

Afterwards, a curl request to the server root leads to the following message in the log:

11:24:20,338 INFO  [io.undertow.accesslog] (default task-8) localhost\
 [04/Aug/2016:11:24:20 -0400] "GET / HTTP/1.1" 200 "curl/7.43.0"

The full CLI script is available as a gist on GitHub. The use-server-log option ensures the output is written to the server log instead of a separate file. Omitting it would result in requests being logged to a file located at $JBOSS_HOME/standalone/log/access_log.log by default. The format of the log messages is configurable through the pattern parameter. Several other configuration options are supported as well:

[standalone@localhost:9990 /] /subsystem=undertow/server=default-server/\
  host=default-host/setting=access-log:read-resource-description
{
    "outcome" => "success",
    "result" => {
        "description" => "The access log configuration for this virtual\
          server.",
        "access-constraints" => {"sensitive" => {"web-access-log" =>\
          {"type" => "undertow"}}},
        "attributes" => {
            "directory" => {
                "type" => STRING,
                "description" => "Directory in which to save logs",
                "expressions-allowed" => true,
                "nillable" => true,
                "default" => expression "${jboss.server.log.dir}",
                "min-length" => 1L,
                "max-length" => 2147483647L,
                "access-type" => "read-write",
                "storage" => "configuration",
                "restart-required" => "no-services"
            },
            "extended" => {
                "type" => BOOLEAN,
                "description" => "If the log uses the extended log file\
                   format",
                "expressions-allowed" => true,
                "nillable" => true,
                "default" => false,
                "access-type" => "read-write",
                "storage" => "configuration",
                "restart-required" => "no-services"
            },
            "pattern" => {
                "type" => STRING,
                "description" => "The access log pattern.",
                "expressions-allowed" => false,
                "nillable" => true,
                "default" => "common",
                "min-length" => 1L,
                "max-length" => 2147483647L,
                "access-type" => "read-write",
                "storage" => "configuration",
                "restart-required" => "no-services"
            },
            "predicate" => {
                "type" => STRING,
                "description" => "Predicate that determines if the request\
                  should be logged",
                "expressions-allowed" => true,
                "nillable" => true,
                "min-length" => 1L,
                "max-length" => 2147483647L,
                "access-type" => "read-write",
                "storage" => "configuration",
                "restart-required" => "no-services"
            },
            "prefix" => {
                "type" => STRING,
                "description" => "Prefix for the log file name.",
                "expressions-allowed" => true,
                "nillable" => true,
                "default" => "access_log.",
                "min-length" => 1L,
                "max-length" => 2147483647L,
                "access-type" => "read-write",
                "storage" => "configuration",
                "restart-required" => "no-services"
            },
            "relative-to" => {
                "type" => STRING,
                "description" => "The directory the path is relative to",
                "expressions-allowed" => true,
                "nillable" => true,
                "min-length" => 1L,
                "max-length" => 2147483647L,
                "access-type" => "read-write",
                "storage" => "configuration",
                "restart-required" => "no-services"
            },
            "rotate" => {
                "type" => BOOLEAN,
                "description" => "Rotate the access log every day.",
                "expressions-allowed" => true,
                "nillable" => true,
                "default" => true,
                "access-type" => "read-write",
                "storage" => "configuration",
                "restart-required" => "no-services"
            },
            "suffix" => {
                "type" => STRING,
                "description" => "Suffix for the log file name.",
                "expressions-allowed" => true,
                "nillable" => true,
                "default" => "log",
                "min-length" => 1L,
                "max-length" => 2147483647L,
                "access-type" => "read-write",
                "storage" => "configuration",
                "restart-required" => "no-services"
            },
            "use-server-log" => {
                "type" => BOOLEAN,
                "description" => "If the log should be written to the server\
                  log, rather than a separate file. Defaults to false.",
                "expressions-allowed" => true,
                "nillable" => true,
                "default" => false,
                "access-type" => "read-write",
                "storage" => "configuration",
                "restart-required" => "no-services"
            },
            "worker" => {
                "type" => STRING,
                "description" => "Name of the worker to use for logging",
                "expressions-allowed" => false,
                "nillable" => true,
                "default" => "default",
                "min-length" => 1L,
                "max-length" => 2147483647L,
                "access-type" => "read-write",
                "storage" => "configuration",
                "restart-required" => "all-services"
            }
        },
        "operations" => undefined,
        "notifications" => undefined,
        "children" => {}
    }
}

The examples in this post were tested using WildFly 10.0.0.Final and Undertow 1.3.15.Final.