* Fixes #7369 - Document CustomRequestLog Introduced `JavadocIncludeExtension` to include javadoc snippets in the documentation. Added documentation about request logging. Updated `CustomRequestLog` javadocs. Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
This commit is contained in:
parent
95f5773cb8
commit
b51465f91a
|
@ -0,0 +1,235 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2021 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.docs;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Deque;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
|
||||
import org.asciidoctor.Asciidoctor;
|
||||
import org.asciidoctor.ast.Document;
|
||||
import org.asciidoctor.extension.IncludeProcessor;
|
||||
import org.asciidoctor.extension.PreprocessorReader;
|
||||
import org.asciidoctor.jruby.extension.spi.ExtensionRegistry;
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
/**
|
||||
* <p>Asciidoctor <em>include</em> extension that includes into
|
||||
* the document the output produced by an XSL transformation of
|
||||
* parts of the javadoc of a file.</p>
|
||||
* <p>Example usage in an Asciidoc page:</p>
|
||||
* <pre>
|
||||
* include::javadoc[file=Source.java,xsl=source.xsl,tags=docs]
|
||||
* </pre>
|
||||
* <p>Available configuration parameters are:</p>
|
||||
* <dl>
|
||||
* <dt>file</dt>
|
||||
* <dd>Mandatory, specifies the file to read the javadoc from, relative to the root of the Jetty Project source.</dd>
|
||||
* <dt>xsl</dt>
|
||||
* <dd>Mandatory, specifies the XSL file to use to transform the javadoc, relative to the root of the documentation source.</dd>
|
||||
* <dt>tags</dt>
|
||||
* <dd>Optional, specifies the name of the tagged regions of the javadoc to include.</dd>
|
||||
* <dt>replace</dt>
|
||||
* <dd>Optional, specifies a comma-separated pair where the first element is a regular
|
||||
* expression and the second is the string replacement, applied to each included line.</dd>
|
||||
* </dl>
|
||||
* <p>An example javadoc could be:</p>
|
||||
* <pre>
|
||||
* /**
|
||||
* * <p>Class description.</p>
|
||||
* * <!-- tag::docs -->
|
||||
* * <p>Parameters</p>
|
||||
* * <table>
|
||||
* * <tr>
|
||||
* * <td>param</td>
|
||||
* * <td>value</td>
|
||||
* * </tr>
|
||||
* * </table>
|
||||
* * <!-- end::docs -->
|
||||
* */
|
||||
* public class A
|
||||
* {
|
||||
* }
|
||||
* </pre>
|
||||
* <p>The javadoc lines included in the tagged region "docs" (between {@code tag::docs} and {@code end::docs})
|
||||
* will be stripped of the asterisk at the beginning of the line and wrapped
|
||||
* into a {@code <root>} element, so that it becomes a well-formed XML document.</p>
|
||||
* <p>Each line of the XML document is then passed through the regular expression specified by the {@code replace}
|
||||
* parameter (if any), and then transformed using the XSL file specified by the {@code xsl} parameter,
|
||||
* which should produce a valid Asciidoc block which is then included in the Asciidoc documentation page.</p>
|
||||
*/
|
||||
public class JavadocIncludeExtension implements ExtensionRegistry
|
||||
{
|
||||
@Override
|
||||
public void register(Asciidoctor asciidoctor)
|
||||
{
|
||||
asciidoctor.javaExtensionRegistry().includeProcessor(JavadocIncludeExtension.JavadocIncludeProcessor.class);
|
||||
}
|
||||
|
||||
public static class JavadocIncludeProcessor extends IncludeProcessor
|
||||
{
|
||||
private static final Pattern JAVADOC_INITIAL_ASTERISK = Pattern.compile("^\\s*\\*\\s*(.*)$");
|
||||
private static final Pattern JAVADOC_INLINE_CODE = Pattern.compile("\\{@code ([^\\}]+)\\}");
|
||||
|
||||
@Override
|
||||
public boolean handles(String target)
|
||||
{
|
||||
return "javadoc".equals(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(Document document, PreprocessorReader reader, String target, Map<String, Object> attributes)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Document attributes are converted by Asciidoctor to lowercase.
|
||||
Path jettyDocsPath = Path.of((String)document.getAttribute("project-basedir"));
|
||||
Path jettyRoot = jettyDocsPath.resolve("../..").normalize();
|
||||
|
||||
String file = (String)attributes.get("file");
|
||||
if (file == null)
|
||||
throw new IllegalArgumentException("Missing 'file' attribute");
|
||||
Path filePath = jettyRoot.resolve(file.trim());
|
||||
|
||||
String xsl = (String)attributes.get("xsl");
|
||||
if (xsl == null)
|
||||
throw new IllegalArgumentException("Missing 'xsl' attribute");
|
||||
Path xslPath = jettyDocsPath.resolve(xsl.trim());
|
||||
|
||||
List<Tag> tagList = new ArrayList<>();
|
||||
String tags = (String)attributes.get("tags");
|
||||
if (tags != null)
|
||||
{
|
||||
for (String tag : tags.split(","))
|
||||
{
|
||||
tag = tag.trim();
|
||||
boolean exclude = tag.startsWith("!");
|
||||
if (exclude)
|
||||
tag = tag.substring(1);
|
||||
if (tag.isEmpty())
|
||||
throw new IllegalArgumentException("Invalid tag in 'tags' attribute: " + tags);
|
||||
tagList.add(new Tag(tag, exclude));
|
||||
}
|
||||
}
|
||||
|
||||
String replace = (String)attributes.get("replace");
|
||||
|
||||
List<String> contentLines = new ArrayList<>();
|
||||
contentLines.add("<root>");
|
||||
Iterator<String> lines = Files.lines(filePath, StandardCharsets.UTF_8).iterator();
|
||||
Deque<Tag> tagStack = new ArrayDeque<>();
|
||||
while (lines.hasNext())
|
||||
{
|
||||
String line = lines.next();
|
||||
|
||||
// Strip the initial Javadoc asterisk.
|
||||
Matcher matcher = JAVADOC_INITIAL_ASTERISK.matcher(line);
|
||||
if (matcher.matches())
|
||||
line = matcher.group(1);
|
||||
|
||||
// Convert {@code X} into <code>X</code>
|
||||
line = JAVADOC_INLINE_CODE.matcher(line).replaceAll("<code>$1</code>");
|
||||
|
||||
boolean keepLine = tagList.isEmpty() || tagList.stream().allMatch(tag -> tag.exclude);
|
||||
|
||||
if (tagStack.isEmpty())
|
||||
{
|
||||
for (Tag tag : tagList)
|
||||
{
|
||||
if (line.contains("tag::" + tag.name))
|
||||
tagStack.push(tag);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Tag currentTag = tagStack.peek();
|
||||
keepLine = !currentTag.exclude;
|
||||
if (line.contains("end::" + currentTag.name))
|
||||
{
|
||||
tagStack.pop();
|
||||
keepLine = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (keepLine)
|
||||
{
|
||||
if (replace == null)
|
||||
contentLines.add(line);
|
||||
else
|
||||
contentLines.addAll(replace(line, replace));
|
||||
}
|
||||
}
|
||||
contentLines.add("</root>");
|
||||
|
||||
String content = String.join("\n", contentLines);
|
||||
|
||||
// Run the XML stylesheet over the remaining lines.
|
||||
DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
|
||||
org.w3c.dom.Document xml = builder.parse(new InputSource(new StringReader(content)));
|
||||
Transformer transformer = TransformerFactory.newInstance().newTransformer(new StreamSource(xslPath.toFile()));
|
||||
StringWriter output = new StringWriter(content.length());
|
||||
transformer.transform(new DOMSource(xml), new StreamResult(output));
|
||||
String asciidoc = output.toString();
|
||||
asciidoc = Arrays.stream(asciidoc.split("\n")).map(String::stripLeading).collect(Collectors.joining("\n"));
|
||||
|
||||
reader.pushInclude(asciidoc, "javadoc", target, 1, attributes);
|
||||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
reader.pushInclude(x.toString(), "javadoc", target, 1, attributes);
|
||||
x.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> replace(String line, String replace)
|
||||
{
|
||||
// Format is: (regexp,replacement).
|
||||
String[] parts = replace.split(",");
|
||||
String regExp = parts[0];
|
||||
String replacement = parts[1].replace("\\n", "\n");
|
||||
return List.of(line.replaceAll(regExp, replacement).split("\n"));
|
||||
}
|
||||
|
||||
private static class Tag
|
||||
{
|
||||
private final String name;
|
||||
private final boolean exclude;
|
||||
|
||||
private Tag(String name, boolean exclude)
|
||||
{
|
||||
this.name = name;
|
||||
this.exclude = exclude;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -127,12 +127,12 @@ public class JettyIncludeExtension implements ExtensionRegistry
|
|||
{
|
||||
run.awaitFor(15, TimeUnit.SECONDS);
|
||||
String output = captureOutput(document, attributes, run);
|
||||
reader.push_include(output, "jettyHome_run", target, 1, attributes);
|
||||
reader.pushInclude(output, "jettyHome_run", target, 1, attributes);
|
||||
}
|
||||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
reader.push_include(x.toString(), "jettyHome_run", target, 1, attributes);
|
||||
reader.pushInclude(x.toString(), "jettyHome_run", target, 1, attributes);
|
||||
x.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
org.eclipse.jetty.docs.JettyIncludeExtension
|
||||
org.eclipse.jetty.docs.JavadocIncludeExtension
|
||||
|
|
|
@ -14,4 +14,49 @@
|
|||
[[og-logging-request]]
|
||||
==== Request Logging
|
||||
|
||||
TODO
|
||||
HTTP requests and responses can be logged to provide data that can be later analyzed with other tools, that can provide information such as the most frequently accessed request URIs, the response status codes, the request/response content lengths, geographical information about the clients, etc.
|
||||
|
||||
Request logging is enabled by enabling the `requestlog` Jetty module.
|
||||
In the example below, both the `http` Jetty module and the `requestlog` module are enabled, so that you can make HTTP requests to the server and have them logged:
|
||||
|
||||
----
|
||||
$ cd $JETTY_BASE
|
||||
$ java -jar $JETTY_HOME/start.jar --add-modules=http,requestlog
|
||||
----
|
||||
|
||||
The `$JETTY_BASE` directory looks like this:
|
||||
|
||||
[source]
|
||||
----
|
||||
$JETTY_BASE
|
||||
├── logs
|
||||
├── resources
|
||||
│ └── jetty-logging.properties
|
||||
└── start.d
|
||||
├── http.ini
|
||||
└── requestlog.ini
|
||||
----
|
||||
|
||||
The `$JETTY_BASE/start.d/requestlog.ini` file is the Jetty module configuration file that allows you to configure the `requestlog` module, see xref:og-module-requestlog[this section] for more details.
|
||||
|
||||
By default the `requestlog` Jetty module produces the `$JETTY_BASE/logs/yyyy_MM_dd.request.log`, where the pattern `yyyy_MM_dd` is replaced with the current date, for example `2020_01_31`.
|
||||
|
||||
The format of the request log lines is the result of a _format string_ that uses formatting symbols to log relevant request/response data.
|
||||
|
||||
The default format is the link:https://en.wikipedia.org/wiki/Common_Log_Format[NCSA Format] extended with referrer data and user-agent data.
|
||||
A typical log line looks like this:
|
||||
|
||||
[source,options=nowrap]
|
||||
----
|
||||
192.168.0.100 - - [31/Jan/2020:20:30:40 +0000] "GET / HTTP/1.1" 200 6789 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36"
|
||||
----
|
||||
|
||||
The line above (that uses fake values) shows `192.168.0.100` for the client IP address, a hard-coded `-` for the identity, `-` for the authenticated user name, `[31/Jan/2020:20:30:40 +0000]` for the date and time with timezone, `"GET / HTTP/1.1"` for the HTTP request line, `200` for the HTTP response status code, `6789` for the HTTP response content length, `"-"` for the referrer and `"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36"` for the user-agent.
|
||||
|
||||
The format string can be customized as described in xref:og-module-requestlog[this section].
|
||||
Request log files are rolled every day, and retained for customizable number of days, by default 90 days.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
When Jetty is behind a load balancer, you want to log the remote client IP address, not the load balancer IP address. Refer to xref:og-protocols-proxy[this section] to configure the load balancer and Jetty to retain the remote client IP address information.
|
||||
====
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2021 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
[[og-module-requestlog]]
|
||||
===== Module `requestlog`
|
||||
|
||||
The `requestlog` module provides HTTP request/response logging in the standard link:https://en.wikipedia.org/wiki/Common_Log_Format[NCSA format], or in a custom format of your choice.
|
||||
|
||||
The module properties are:
|
||||
|
||||
----
|
||||
include::{JETTY_HOME}/modules/requestlog.mod[tags=documentation]
|
||||
----
|
||||
|
||||
The property `jetty.requestlog.formatString` can be customized using format codes.
|
||||
|
||||
include::javadoc[file=jetty-server/src/main/java/org/eclipse/jetty/server/CustomRequestLog.java,xsl=src/main/asciidoc/operations-guide/modules/module-requestlog.xsl,tags=documentation,replace="\|,\\|"]
|
|
@ -0,0 +1,48 @@
|
|||
<?xml version="1.0"?>
|
||||
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:output method="text" indent="no"/>
|
||||
<xsl:strip-space elements="*" />
|
||||
|
||||
<xsl:template match="//table">
|
||||
<xsl:text> </xsl:text>
|
||||
<xsl:if test="caption != ''">
|
||||
.<xsl:value-of select="caption" />
|
||||
</xsl:if>
|
||||
[cols="1,3a"]
|
||||
|===
|
||||
<xsl:apply-templates select="tr/th" />
|
||||
<xsl:apply-templates select="tr" />
|
||||
|===
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="th">|<xsl:value-of select="." /></xsl:template>
|
||||
|
||||
<xsl:template match="tr">
|
||||
<xsl:apply-templates select="td" />
|
||||
<xsl:text> </xsl:text>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="td">|<xsl:apply-templates /></xsl:template>
|
||||
|
||||
<xsl:template match="p"><xsl:apply-templates />
|
||||
<xsl:if test="count(following-sibling::p) > 0"><xsl:text> </xsl:text></xsl:if>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="dl">
|
||||
<xsl:text> </xsl:text>
|
||||
<xsl:for-each select="dt|dd">
|
||||
<xsl:apply-templates select="." />
|
||||
</xsl:for-each>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="dt">
|
||||
`<xsl:value-of select="." />`::
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="dd">
|
||||
<xsl:apply-templates />
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="code">`<xsl:value-of select="." />`</xsl:template>
|
||||
|
||||
</xsl:stylesheet>
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
include::module-alpn.adoc[]
|
||||
include::module-bytebufferpool.adoc[]
|
||||
include::module-console-capture.adoc[]
|
||||
include::module-deploy.adoc[]
|
||||
include::module-http.adoc[]
|
||||
include::module-http2.adoc[]
|
||||
|
@ -24,10 +25,10 @@ include::module-http3.adoc[]
|
|||
include::module-http-forwarded.adoc[]
|
||||
include::module-https.adoc[]
|
||||
include::module-jmx-remote.adoc[]
|
||||
include::module-requestlog.adoc[]
|
||||
include::module-server.adoc[]
|
||||
include::module-ssl.adoc[]
|
||||
include::module-ssl-reload.adoc[]
|
||||
include::module-test-keystore.adoc[]
|
||||
include::module-threadpool.adoc[]
|
||||
include::module-console-capture.adoc[]
|
||||
include::module-well-known.adoc[]
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
<Arg>
|
||||
<Property name="jetty.requestlog.filePath">
|
||||
<Default>
|
||||
<Property name="jetty.requestlog.dir" default="logs"/>/yyyy_mm_dd.request.log
|
||||
<Property name="jetty.requestlog.dir" default="logs"/>/yyyy_MM_dd.request.log
|
||||
</Default>
|
||||
</Property>
|
||||
</Arg>
|
||||
|
|
|
@ -16,27 +16,26 @@ etc/jetty-requestlog.xml
|
|||
[files]
|
||||
logs/
|
||||
|
||||
[ini]
|
||||
jetty.requestlog.dir?=logs
|
||||
|
||||
[ini-template]
|
||||
## Format string
|
||||
# tag::documentation[]
|
||||
## Request log line format string.
|
||||
# jetty.requestlog.formatString=%a - %u %{dd/MMM/yyyy:HH:mm:ss ZZZ|GMT}t "%r" %s %B "%{Referer}i" "%{User-Agent}i" "%C"
|
||||
|
||||
## Logging directory (relative to $jetty.base)
|
||||
## The logging directory (relative to $JETTY_BASE).
|
||||
# jetty.requestlog.dir=logs
|
||||
|
||||
## File path
|
||||
# jetty.requestlog.filePath=${jetty.requestlog.dir}/yyyy_mm_dd.request.log
|
||||
## The request log file path (may be absolute and/or outside $JETTY_BASE).
|
||||
# jetty.requestlog.filePath=${jetty.requestlog.dir}/yyyy_MM_dd.request.log
|
||||
|
||||
## Date format for rollovered files (uses SimpleDateFormat syntax)
|
||||
## Date format for the files that are rolled over (uses SimpleDateFormat syntax).
|
||||
# jetty.requestlog.filenameDateFormat=yyyy_MM_dd
|
||||
|
||||
## How many days to retain old log files
|
||||
## How many days to retain old log files.
|
||||
# jetty.requestlog.retainDays=90
|
||||
|
||||
## Whether to append to existing file
|
||||
## Whether to append to existing file or create a new one.
|
||||
# jetty.requestlog.append=false
|
||||
|
||||
## Timezone of the log file rollover
|
||||
## The timezone of the log file name.
|
||||
# jetty.requestlog.timezone=GMT
|
||||
# end::documentation[]
|
||||
|
|
|
@ -29,7 +29,6 @@ import java.util.regex.Matcher;
|
|||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.QuotedCSV;
|
||||
|
@ -48,223 +47,274 @@ import static java.lang.invoke.MethodHandles.foldArguments;
|
|||
import static java.lang.invoke.MethodType.methodType;
|
||||
|
||||
/**
|
||||
* A flexible RequestLog, which produces log strings in a customizable format.
|
||||
* The Logger takes a format string where request characteristics can be added using "%" format codes which are
|
||||
* replaced by the corresponding value in the log output.
|
||||
* <p>
|
||||
* The terms server, client, local and remote are used to refer to the different addresses and ports
|
||||
* <p>A flexible RequestLog, which produces log strings in a customizable format.</p>
|
||||
* <p>The Logger takes a format string where request characteristics can be added using "%" format codes which are
|
||||
* replaced by the corresponding value in the log output.</p>
|
||||
* <p>The terms server, client, local and remote are used to refer to the different addresses and ports
|
||||
* which can be logged. Server and client refer to the logical addresses which can be modified in the request
|
||||
* headers. Where local and remote refer to the physical addresses which may be a proxy between the
|
||||
* end-user and the server.
|
||||
* end-user and the server.</p>
|
||||
*
|
||||
*
|
||||
* <br><br>Percent codes are specified in the format %MODIFIERS{PARAM}CODE
|
||||
* <pre>
|
||||
* MODIFIERS:
|
||||
* Optional list of comma separated HTTP status codes which may be preceded by a single "!" to indicate
|
||||
* negation. If the status code is not in the list the literal string "-" will be logged instead of
|
||||
* the resulting value from the percent code.
|
||||
* {PARAM}:
|
||||
* Parameter string which may be optional depending on the percent code used.
|
||||
* CODE:
|
||||
* A one or two character code specified by the {@link CustomRequestLog} table of format codes.
|
||||
* </pre>
|
||||
* <!-- tag::documentation[] -->
|
||||
* <p>Format codes are specified with the syntax <code>%MODIFIERS{PARAM}CODE</code> as follows:</p>
|
||||
* <dl>
|
||||
* <dt>MODIFIERS</dt>
|
||||
* <dd>Optional list of comma separated HTTP status codes which may be preceded by a single "!" to indicate
|
||||
* negation. If the status code is not in the list the literal string "-" will be logged instead of
|
||||
* the resulting value from the percent code.</dd>
|
||||
* <dt>{PARAM}</dt>
|
||||
* <dd>Parameter string which may be optional depending on the percent code used.</dd>
|
||||
* <dt>CODE</dt>
|
||||
* <dd>A one or two character code specified by the table of format codes below.</dd>
|
||||
* </dl>
|
||||
*
|
||||
* <table>
|
||||
* <caption>Format Codes</caption>
|
||||
* <tr>
|
||||
* <td><b>Format String</b></td>
|
||||
* <td><b>Description</b></td>
|
||||
* <th>Format String</th>
|
||||
* <th>Description</th>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>X</td>
|
||||
* <td>
|
||||
* <p>The X character.</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%%</td>
|
||||
* <td>The percent sign.</td>
|
||||
* <td>
|
||||
* <p>The percent character.</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%{format}a</td>
|
||||
* <td>
|
||||
* Address or Hostname. Valid formats are {server, client, local, remote}
|
||||
* Optional format parameter which will be server by default.
|
||||
* <br>
|
||||
* Where server and client are the logical addresses which can be modified in the request headers, while local and
|
||||
* remote are the physical addresses so may be a proxy between the end-user and the server.
|
||||
* <p>The address or host name.</p>
|
||||
* <p>Valid format values are: "server", "client", "local", "remote".
|
||||
* The format parameter is optional and defaults to "server".</p>
|
||||
* <p>Values "server" and "client" are the logical addresses which can be modified in the request headers,
|
||||
* while "local" and "remote" are the physical addresses so may be the addresses of a proxy between
|
||||
* the end-user and the server.</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%{format}p</td>
|
||||
* <td>
|
||||
* Port. Valid formats are {server, client, local, remote}
|
||||
* Optional format parameter which will be server by default.
|
||||
* <br>
|
||||
* Where server and client are the logical ports which can be modified in the request headers, while local and
|
||||
* remote are the physical ports so may be to a proxy between the end-user and the server.
|
||||
* <p>The port.</p>
|
||||
* <p>Valid format values are: "server", "client", "local", "remote".
|
||||
* The format parameter is optional and defaults to "server".</p>
|
||||
* <p>Values "server" and "client" are the logical ports which can be modified in the request headers,
|
||||
* while "local" and "remote" are the physical ports so may be the ports of a proxy between
|
||||
* the end-user and the server.</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%{CLF}I</td>
|
||||
* <td>
|
||||
* Size of request in bytes, excluding HTTP headers.
|
||||
* Optional parameter with value of "CLF" to use CLF format, i.e. a '-' rather than a 0 when no bytes are sent.
|
||||
* <p>The size of request in bytes, excluding HTTP headers.</p>
|
||||
* <p>The parameter is optional.
|
||||
* When the parameter value is "CLF" the Common Log Format is used, i.e. a {@code -} rather than a {@code 0}
|
||||
* when no bytes are present.</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%{CLF}O</td>
|
||||
* <td>
|
||||
* Size of response in bytes, excluding HTTP headers.
|
||||
* Optional parameter with value of "CLF" to use CLF format, i.e. a '-' rather than a 0 when no bytes are sent.
|
||||
* <p>The size of response in bytes, excluding HTTP headers.</p>
|
||||
* <p>The parameter is optional.
|
||||
* When the parameter value is "CLF" the Common Log Format is used, i.e. a {@code -} rather than a {@code 0}
|
||||
* when no bytes are present.</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%{CLF}S</td>
|
||||
* <td>
|
||||
* Bytes transferred (received and sent). This is the combination of %I and %O.
|
||||
* Optional parameter with value of "CLF" to use CLF format, i.e. a '-' rather than a 0 when no bytes are sent.
|
||||
* <p>The bytes transferred (received and sent). This is the combination of {@code %I} and {@code %O}.</p>
|
||||
* <p>The parameter is optional.
|
||||
* When the parameter value is "CLF" the Common Log Format is used, i.e. a {@code -} rather than a {@code 0}
|
||||
* when no bytes are present.</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%{VARNAME}C</td>
|
||||
* <td>
|
||||
* The contents of cookie VARNAME in the request sent to the server. Only version 0 cookies are fully supported.
|
||||
* Optional VARNAME parameter, without this parameter %C will log all cookies from the request.
|
||||
* <p>The value of the request cookie VARNAME.</p>
|
||||
* <p>The parameter is optional.
|
||||
* Only version 0 cookies are fully supported.
|
||||
* When the parameter is missing, all request cookies will be logged.</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%D</td>
|
||||
* <td>The time taken to serve the request, in microseconds.</td>
|
||||
* <td>
|
||||
* <p>The time taken to serve the request, in microseconds.</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%{VARNAME}e</td>
|
||||
* <td>The contents of the environment variable VARNAME.</td>
|
||||
* <td>
|
||||
* <p>The value of the environment variable VARNAME.</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%f</td>
|
||||
* <td>Filename.</td>
|
||||
* <td>
|
||||
* <p>The file system path of the requested resource.</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%H</td>
|
||||
* <td>The name and version of the request protocol, such as "HTTP/1.1".</td>
|
||||
* <td>
|
||||
* <p>The name and version of the request protocol, such as "HTTP/1.1".</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%{VARNAME}i</td>
|
||||
* <td>The contents of VARNAME: header line(s) in the request sent to the server.</td>
|
||||
* <td>
|
||||
* <p>The value of the VARNAME request header.</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%k</td>
|
||||
* <td>Number of keepalive requests handled on this connection.
|
||||
* Interesting if KeepAlive is being used, so that, for example, a '1' means the first keepalive request
|
||||
* after the initial one, '2' the second, etc...; otherwise this is always 0 (indicating the initial request).</td>
|
||||
* <td>
|
||||
* <p>The number of requests handled on a connection.</p>
|
||||
* <p>The initial request on a connection yields a value 0, the first request after the initial on the same connection
|
||||
* yields the value 1, the second request on the same connection yields the value 2, etc.</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%m</td>
|
||||
* <td>The request method.</td>
|
||||
* <td>
|
||||
* <p>The HTTP request method.</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%{VARNAME}o</td>
|
||||
* <td>The contents of VARNAME: header line(s) in the response.</td>
|
||||
* <td>
|
||||
* <p>The value of the VARNAME response header.</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%q</td>
|
||||
* <td>The query string (prepended with a ? if a query string exists, otherwise an empty string).</td>
|
||||
* <td>
|
||||
* <p>The query string, prepended with a ? if a query string exists, otherwise an empty string.</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%r</td>
|
||||
* <td>First line of request.</td>
|
||||
* <td>
|
||||
* <p>First line of an HTTP/1.1 request (or equivalent information for HTTP/2 or later).</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%R</td>
|
||||
* <td>The handler generating the response (if any).</td>
|
||||
* <td>
|
||||
* <p>The name of the Handler or Servlet generating the response (if any).</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%s</td>
|
||||
* <td>Response status.</td>
|
||||
* <td>
|
||||
* <p>The HTTP response status code.</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%{format|timeZone|locale}t</td>
|
||||
* <td>
|
||||
* The time that the request was received.
|
||||
* Optional parameter in one of the following formats {format}, {format|timeZone} or {format|timeZone|locale}.<br><br>
|
||||
*
|
||||
* <pre>
|
||||
* Format Parameter: (default format [18/Sep/2011:19:18:28 -0400] where the last number indicates the timezone offset from GMT.)
|
||||
* Must be in a format supported by {@link DateCache}
|
||||
*
|
||||
* TimeZone Parameter:
|
||||
* Default timeZone GMT
|
||||
* Must be in a format supported by {@link TimeZone#getTimeZone(String)}
|
||||
*
|
||||
* Locale Parameter:
|
||||
* Default locale {@link Locale#getDefault()}
|
||||
* Must be in a format supported by {@link Locale#forLanguageTag(String)}</pre>
|
||||
* <p>The time at which the request was received.</p>
|
||||
* <p>The parameter is optional and may have the following values: {format}, {format|timeZone} or {format|timeZone|locale}.</p>
|
||||
* <dl>
|
||||
* <dt>format</dt>
|
||||
* <dd>Default is e.g. [18/Sep/2011:19:18:28 -0400] where the last number indicates the timezone offset from GMT.
|
||||
* Must be in a format supported by the {@code java.time} package.</dd>
|
||||
* <dt>timeZone</dt>
|
||||
* <dd>Default is GMT.
|
||||
* Must be in a format supported by the {@code java.time} package.</dd>
|
||||
* <dt>locale</dt>
|
||||
* <dd>Default is the JVM default locale.
|
||||
* Must be in a format supported by {@code java.util.Locale.forLanguageTag()}.</dd>
|
||||
* </dl>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%T</td>
|
||||
* <td>The time taken to serve the request, in seconds.</td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%{UNIT}T</td>
|
||||
* <td>The time taken to serve the request, in a time unit given by UNIT.
|
||||
* Valid units are ms for milliseconds, us for microseconds, and s for seconds.
|
||||
* Using s gives the same result as %T without any format; using us gives the same result as %D.</td>
|
||||
* <td>
|
||||
* <p>The time taken to serve the request.</p>
|
||||
* <p>The parameter UNIT is optional and defaults to "s".
|
||||
* The parameter UNIT indicates the unit of time: "s" for seconds, "ms" for milliseconds, "us" for microseconds.
|
||||
* <code>%{us}T</code> is identical to {@code %D}.</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%{d}u</td>
|
||||
* <td>
|
||||
* Remote user if the request was authenticated with servlet authentication. May be bogus if return status (%s) is 401 (unauthorized).
|
||||
* Optional parameter d, with this parameter deferred authentication will also be checked,
|
||||
* this is equivalent to {@link HttpServletRequest#getRemoteUser()}.
|
||||
* <p>The remote user if the request was authenticated with servlet authentication.</p>
|
||||
* <p>May be an invalid value if response status code ({@code %s}) is 401 (unauthorized).</p>
|
||||
* <p>The parameter is optional.
|
||||
* When the parameter value is "d", deferred authentication will also be checked.</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%U</td>
|
||||
* <td>The URL path requested, not including any query string.</td>
|
||||
* <td>
|
||||
* <p>The URL path requested, not including any query string.</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%X</td>
|
||||
* <td>
|
||||
* Connection status when response is completed:
|
||||
* <pre>
|
||||
* X = Connection aborted before the response completed.
|
||||
* + = Connection may be kept alive after the response is sent.
|
||||
* - = Connection will be closed after the response is sent.</pre>
|
||||
* <p>The connection status when response is completed:</p>
|
||||
* <dl>
|
||||
* <dt>X</dt>
|
||||
* <dd>The connection is aborted before the response completed.</dd>
|
||||
* <dt>+</dt>
|
||||
* <dd>The connection may be kept alive after the response is sent.</dd>
|
||||
* <dt>-</dt>
|
||||
* <dd>The connection will be closed after the response is sent.</dd>
|
||||
* </dl>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%{VARNAME}^ti</td>
|
||||
* <td>The contents of VARNAME: trailer line(s) in the request sent to the server.</td>
|
||||
* <td>%{VARNAME}ti</td>
|
||||
* <td>
|
||||
* <p>The value of the VARNAME request trailer.</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%{VARNAME}^to</td>
|
||||
* <td>The contents of VARNAME: trailer line(s) in the response sent from the server.</td>
|
||||
* <td>%{VARNAME}to</td>
|
||||
* <td>
|
||||
* <p>The value of the VARNAME response trailer.</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
* </table>
|
||||
* <!-- end::documentation[] -->
|
||||
*/
|
||||
@ManagedObject("Custom format request log")
|
||||
public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
|
||||
|
|
Loading…
Reference in New Issue