From aa1f6a9dd31f6d86fc5534a64e0899b4e165066d Mon Sep 17 00:00:00 2001 From: Justin Bertram Date: Thu, 7 Jun 2018 16:59:47 -0500 Subject: [PATCH] ARTEMIS-1917 support logging HTTP access --- .../activemq/artemis/dto/RequestLogDTO.java | 105 ++++++++++++++++++ .../activemq/artemis/dto/WebServerDTO.java | 3 + .../artemis/component/WebServerComponent.java | 71 ++++++++++++ docs/user-manual/en/SUMMARY.md | 1 + docs/user-manual/en/web-server.md | 82 ++++++++++++++ 5 files changed, 262 insertions(+) create mode 100644 artemis-dto/src/main/java/org/apache/activemq/artemis/dto/RequestLogDTO.java create mode 100644 docs/user-manual/en/web-server.md diff --git a/artemis-dto/src/main/java/org/apache/activemq/artemis/dto/RequestLogDTO.java b/artemis-dto/src/main/java/org/apache/activemq/artemis/dto/RequestLogDTO.java new file mode 100644 index 0000000000..b2522e6890 --- /dev/null +++ b/artemis-dto/src/main/java/org/apache/activemq/artemis/dto/RequestLogDTO.java @@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.activemq.artemis.dto; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement(name = "request-log") +@XmlAccessorType(XmlAccessType.FIELD) +public class RequestLogDTO { + + /** + * the output file name of the request log + */ + @XmlAttribute(required = true) + public String filename; + + /** + * append to log + */ + @XmlAttribute + public Boolean append; + + /** + * the extended request log format flag + */ + @XmlAttribute + public Boolean extended; + + /** + * logging of the request cookies + */ + @XmlAttribute + public Boolean logCookies; + + /** + * the output file name of the request log + */ + @XmlAttribute + public String logTimeZone; + + /** + * the log file name date format + */ + @XmlAttribute + public String filenameDateFormat; + + /** + * the number of days before rotated log files are deleted + */ + @XmlAttribute + public Integer retainDays; + + /** + * request paths that will not be logged + */ + @XmlAttribute + public String ignorePaths; + + /** + * the timestamp format string for request log entries + */ + @XmlAttribute + public String logDateFormat; + + /** + * the locale of the request log + */ + @XmlAttribute + public String logLocale; + + /** + * logging of request processing time + */ + @XmlAttribute + public Boolean logLatency; + + /** + * logging of the request hostname + */ + @XmlAttribute + public Boolean logServer; + + /** + * whether the actual IP address of the connection or the IP address from the X-Forwarded-For header will be logged + */ + @XmlAttribute + public Boolean preferProxiedForAddress; +} diff --git a/artemis-dto/src/main/java/org/apache/activemq/artemis/dto/WebServerDTO.java b/artemis-dto/src/main/java/org/apache/activemq/artemis/dto/WebServerDTO.java index 3e1526184f..8987b42e0d 100644 --- a/artemis-dto/src/main/java/org/apache/activemq/artemis/dto/WebServerDTO.java +++ b/artemis-dto/src/main/java/org/apache/activemq/artemis/dto/WebServerDTO.java @@ -50,6 +50,9 @@ public class WebServerDTO extends ComponentDTO { @XmlElementRef public List apps; + @XmlElementRef(required = false) + public RequestLogDTO requestLog; + @XmlAttribute private String keyStorePassword; diff --git a/artemis-web/src/main/java/org/apache/activemq/artemis/component/WebServerComponent.java b/artemis-web/src/main/java/org/apache/activemq/artemis/component/WebServerComponent.java index 0a2b231679..05a9202596 100644 --- a/artemis-web/src/main/java/org/apache/activemq/artemis/component/WebServerComponent.java +++ b/artemis-web/src/main/java/org/apache/activemq/artemis/component/WebServerComponent.java @@ -23,6 +23,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import org.apache.activemq.artemis.ActiveMQWebLogger; import org.apache.activemq.artemis.components.ExternalComponent; @@ -35,6 +36,7 @@ import org.eclipse.jetty.server.ConnectionFactory; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.HttpConnectionFactory; +import org.eclipse.jetty.server.NCSARequestLog; import org.eclipse.jetty.server.SecureRequestCustomizer; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; @@ -42,6 +44,7 @@ import org.eclipse.jetty.server.SslConnectionFactory; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.DefaultHandler; import org.eclipse.jetty.server.handler.HandlerList; +import org.eclipse.jetty.server.handler.RequestLogHandler; import org.eclipse.jetty.server.handler.ResourceHandler; import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.webapp.WebAppContext; @@ -143,12 +146,80 @@ public class WebServerComponent implements ExternalComponent { DefaultHandler defaultHandler = new DefaultHandler(); defaultHandler.setServeIcon(false); + if (webServerConfig.requestLog != null) { + handlers.addHandler(getLogHandler()); + } handlers.addHandler(homeContext); handlers.addHandler(instanceContext); handlers.addHandler(defaultHandler); server.setHandler(handlers); } + private RequestLogHandler getLogHandler() { + RequestLogHandler requestLogHandler = new RequestLogHandler(); + NCSARequestLog requestLog = new NCSARequestLog(); + + // required via config so no check necessary + requestLog.setFilename(webServerConfig.requestLog.filename); + + if (webServerConfig.requestLog.append != null) { + requestLog.setAppend(webServerConfig.requestLog.append); + } + + if (webServerConfig.requestLog.extended != null) { + requestLog.setExtended(webServerConfig.requestLog.extended); + } + + if (webServerConfig.requestLog.logCookies != null) { + requestLog.setLogCookies(webServerConfig.requestLog.logCookies); + } + + if (webServerConfig.requestLog.logTimeZone != null) { + requestLog.setLogTimeZone(webServerConfig.requestLog.logTimeZone); + } + + if (webServerConfig.requestLog.filenameDateFormat != null) { + requestLog.setFilenameDateFormat(webServerConfig.requestLog.filenameDateFormat); + } + + if (webServerConfig.requestLog.retainDays != null) { + requestLog.setRetainDays(webServerConfig.requestLog.retainDays); + } + + if (webServerConfig.requestLog.ignorePaths != null && webServerConfig.requestLog.ignorePaths.length() > 0) { + String[] split = webServerConfig.requestLog.ignorePaths.split(","); + String[] ignorePaths = new String[split.length]; + for (int i = 0; i < ignorePaths.length; i++) { + ignorePaths[i] = split[i].trim(); + } + requestLog.setIgnorePaths(ignorePaths); + } + + if (webServerConfig.requestLog.logDateFormat != null) { + requestLog.setLogDateFormat(webServerConfig.requestLog.logDateFormat); + } + + if (webServerConfig.requestLog.logLocale != null) { + requestLog.setLogLocale(Locale.forLanguageTag(webServerConfig.requestLog.logLocale)); + } + + if (webServerConfig.requestLog.logLatency != null) { + requestLog.setLogLatency(webServerConfig.requestLog.logLatency); + } + + if (webServerConfig.requestLog.logServer != null) { + requestLog.setLogServer(webServerConfig.requestLog.logServer); + } + + if (webServerConfig.requestLog.preferProxiedForAddress != null) { + requestLog.setPreferProxiedForAddress(webServerConfig.requestLog.preferProxiedForAddress); + } + + requestLogHandler.setRequestLog(requestLog); + + return requestLogHandler; + } + @Override public void start() throws Exception { if (isStarted()) { diff --git a/docs/user-manual/en/SUMMARY.md b/docs/user-manual/en/SUMMARY.md index 86273cc82f..d86ed8582c 100644 --- a/docs/user-manual/en/SUMMARY.md +++ b/docs/user-manual/en/SUMMARY.md @@ -58,6 +58,7 @@ * [Graceful Server Shutdown](graceful-shutdown.md) * [Libaio Native Libraries](libaio.md) * [Thread management](thread-pooling.md) +* [Embedded Web Server](web-server.md) * [Logging](logging.md) * [REST Interface](rest.md) * [Embedding the Broker](embedding-activemq.md) diff --git a/docs/user-manual/en/web-server.md b/docs/user-manual/en/web-server.md new file mode 100644 index 0000000000..2a403adb18 --- /dev/null +++ b/docs/user-manual/en/web-server.md @@ -0,0 +1,82 @@ +# Embedded Web Server + +Apache ActiveMQ Artemis embeds the [Jetty web +server](https://www.eclipse.org/jetty/). Its main purpose is to host the [Management +Console](management-console.md). However, it can also host other web +applications like the [REST interface](rest.md) or even Spring-based web +applications (e.g. using Camel). + +## Configuration + +The embedded Jetty instance is configured in `etc/bootstrap.xml` via the `web` +element, e.g.: + +```xml + + + + + +``` + +The `web` element has the following attributes: + +- `bind` The protocol to use (i.e. `http` or `https`) as well as the host and + port on which to listen. +- `path` The name of the subdirectory in which to find the web application + archives (i.e. WAR files). This is a subdirectory of the broker's home or + instance directory. +- `clientAuth` Whether or not clients should present an SSL certificate when + they connect. Only applicable when using `https`. +- `passwordCodec` The custom coded to use for unmasking the `keystorePassword` + and `truststorePassword`. +- `keystorePath` The location on disk of the keystore. Only applicable when + using `https`. +- `keystorePassword` The password to the keystore. Only applicable when using + `https`. Can be masked using `ENC()` syntax or by defining `passwordCodec`. + See more in the [password masking](masking-passwords.md) chapter. +- `truststorePath` The location on disk fo the truststore. Only applicable when + using `https`. +- `truststorePassword` The password to the truststore. Only applicable when + using `https`. Can be masked using `ENC()` syntax or by defining + `passwordCodec`. See more in the [password masking](masking-passwords.md) + chapter. + +Each web application should be defined in an `app` element. The `app` element +has the following attributes: + +- `url` The context to use for the web application. +- `war` The name of the web application archive on disk. + +It's also possible to configure HTTP/S request logging via the `request-log` +element which has the following attributes: + +- `filename` The full path of the request log. This attribute is required. +- `append` Whether or not to append to the existing log or truncate it. Boolean flag. +- `extended` Whether or not to use the extended request log format. Boolean flag. +- `logCookies` Logging of the request cookies. Boolean flag. +- `logTimeZone` The output file name of the request log. +- `filenameDateFormat` The log file name date format. +- `retainDays` The number of days before rotated log files are deleted. +- `ignorePaths` Request paths that will not be logged. Comma delimited list. +- `logDateFormat` The timestamp format string for request log entries. +- `logLocale` The locale of the request log. +- `logLatency` Logging of request processing time. Boolean flag. +- `logServer` Logging of the request hostname. Boolean flag. +- `preferProxiedForAddress` Whether the actual IP address of the connection or + the IP address from the `X-Forwarded-For` header will be logged. Boolean flag. + +These attributes are essentially passed straight through to the underlying +[`org.eclipse.jetty.server.NCSARequestLog`](https://www.eclipse.org/jetty/javadoc/current/org/eclipse/jetty/server/NCSARequestLog.html) +instance. Default values are based on this implementation. + +Here is an example configuration: + +```xml + + + + + + +``` \ No newline at end of file