Skip to content

Commit

Permalink
WFLY-5243 Support for the extended access log
Browse files Browse the repository at this point in the history
Also add support for predicated access logging
  • Loading branch information
stuartwdouglas committed Sep 6, 2015
1 parent 528494c commit 5e29555
Show file tree
Hide file tree
Showing 10 changed files with 73 additions and 20 deletions.
Expand Up @@ -601,10 +601,8 @@ private void migrateAccessLog(Map<PathAddress, ModelNode> newAddOperations, Mode
if (newAddOp.hasDefined(WebAccessLogDefinition.RESOLVE_HOSTS.getName())) {
warnings.add(WebLogger.ROOT_LOGGER.couldNotMigrateResource(WebAccessLogDefinition.RESOLVE_HOSTS.getName(), pathAddress(newAddOp.get(ADDRESS))));
}
//TODO: extended access log
if (newAddOp.hasDefined(WebAccessLogDefinition.EXTENDED.getName())) {
warnings.add(WebLogger.ROOT_LOGGER.couldNotMigrateResource(WebAccessLogDefinition.EXTENDED.getName(), pathAddress(newAddOp.get(ADDRESS))));
}

add.get(Constants.EXTENDED).set(newAddOp.get(WebAccessLogDefinition.EXTENDED.getName()).clone());

ModelNode directory = findResource(pathAddress(pathAddress(newAddOp.get(ADDRESS)), WebExtension.DIRECTORY_PATH), legacyAddOps);
if(directory != null){
Expand Down
Expand Up @@ -22,6 +22,8 @@

package org.wildfly.extension.undertow;

import io.undertow.predicate.Predicate;
import io.undertow.predicate.Predicates;
import org.jboss.as.controller.AbstractAddStepHandler;
import org.jboss.as.controller.OperationContext;
import org.jboss.as.controller.OperationFailedException;
Expand Down Expand Up @@ -57,13 +59,21 @@ protected void performRuntime(OperationContext context, ModelNode operation, Mod
final String fileSuffix = AccessLogDefinition.SUFFIX.resolveModelAttribute(context, model).asString();
final boolean useServerLog = AccessLogDefinition.USE_SERVER_LOG.resolveModelAttribute(context, model).asBoolean();
final boolean rotate = AccessLogDefinition.ROTATE.resolveModelAttribute(context, model).asBoolean();
final boolean extended = AccessLogDefinition.EXTENDED.resolveModelAttribute(context, model).asBoolean();
final ModelNode relativeToNode = AccessLogDefinition.RELATIVE_TO.resolveModelAttribute(context, model);
final String relativeTo = relativeToNode.isDefined() ? relativeToNode.asString() : null;

Predicate predicate = null;
ModelNode predicateNode = AccessLogDefinition.PREDICATE.resolveModelAttribute(context, model);
if(predicateNode.isDefined()) {
predicate = Predicates.parse(predicateNode.asString(), getClass().getClassLoader());
}

final AccessLogService service;
if (useServerLog) {
service = new AccessLogService(pattern);
service = new AccessLogService(pattern, extended, predicate);
} else {
service = new AccessLogService(pattern, directory, relativeTo, filePrefix, fileSuffix, rotate);
service = new AccessLogService(pattern, directory, relativeTo, filePrefix, fileSuffix, rotate, extended, predicate);
}

final String serverName = serverAddress.getLastElement().getValue();
Expand Down
Expand Up @@ -87,6 +87,14 @@ public class AccessLogDefinition extends PersistentResourceDefinition {
.setAllowExpression(true)
.build();

protected static final SimpleAttributeDefinition EXTENDED = new SimpleAttributeDefinitionBuilder(Constants.EXTENDED, ModelType.BOOLEAN, true)
.setDefaultValue(new ModelNode(true))
.setAllowExpression(true)
.build();

protected static final SimpleAttributeDefinition PREDICATE = new SimpleAttributeDefinitionBuilder(Constants.PREDICATE, ModelType.STRING, true)
.setAllowExpression(true)
.build();

static final Collection<SimpleAttributeDefinition> ATTRIBUTES = Arrays.asList(
// IMPORTANT -- keep these in xsd order as this order controls marshalling
Expand All @@ -97,7 +105,9 @@ public class AccessLogDefinition extends PersistentResourceDefinition {
ROTATE,
DIRECTORY,
USE_SERVER_LOG,
RELATIVE_TO
RELATIVE_TO,
EXTENDED,
PREDICATE
);
static final AccessLogDefinition INSTANCE = new AccessLogDefinition();
private final List<AccessConstraintDefinition> accessConstraints;
Expand Down
Expand Up @@ -24,10 +24,15 @@

package org.wildfly.extension.undertow;

import io.undertow.attribute.ExchangeAttribute;
import io.undertow.attribute.ExchangeAttributes;
import io.undertow.predicate.Predicate;
import io.undertow.predicate.Predicates;
import io.undertow.server.HttpHandler;
import io.undertow.server.handlers.accesslog.AccessLogHandler;
import io.undertow.server.handlers.accesslog.AccessLogReceiver;
import io.undertow.server.handlers.accesslog.DefaultAccessLogReceiver;
import io.undertow.server.handlers.accesslog.ExtendedAccessLogParser;
import io.undertow.server.handlers.accesslog.JBossLoggingAccessLogReceiver;
import org.jboss.as.controller.services.path.PathManager;
import org.jboss.msc.service.Service;
Expand All @@ -38,7 +43,10 @@
import org.wildfly.extension.undertow.logging.UndertowLogger;
import org.xnio.XnioWorker;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

/**
* @author Tomaz Cerar (c) 2013 Red Hat Inc.
Expand All @@ -53,34 +61,41 @@ class AccessLogService implements Service<AccessLogService> {
private final String fileSuffix;
private final boolean rotate;
private final boolean useServerLog;
private final boolean extended;
private final Predicate predicate;
private volatile AccessLogReceiver logReceiver;


private PathManager.Callback.Handle callbackHandle;

private File directory;
private Path directory;
private ExchangeAttribute realPattern;

private final InjectedValue<PathManager> pathManager = new InjectedValue<PathManager>();


AccessLogService(String pattern) {
AccessLogService(String pattern, boolean extended, Predicate predicate) {
this.pattern = pattern;
this.extended = extended;
this.path = null;
this.pathRelativeTo = null;
this.filePrefix = null;
this.fileSuffix = null;
this.useServerLog = true;
this.rotate = false; //doesn't really matter
this.predicate = predicate == null ? Predicates.truePredicate() : predicate;
}

AccessLogService(String pattern, String path, String pathRelativeTo, String filePrefix, String fileSuffix, boolean rotate) {
AccessLogService(String pattern, String path, String pathRelativeTo, String filePrefix, String fileSuffix, boolean rotate, boolean extended, Predicate predicate) {
this.pattern = pattern;
this.path = path;
this.pathRelativeTo = pathRelativeTo;
this.filePrefix = filePrefix;
this.fileSuffix = fileSuffix;
this.rotate = rotate;
this.extended = extended;
this.useServerLog = false;
this.predicate = predicate == null ? Predicates.truePredicate() : predicate;
}

@Override
Expand All @@ -91,14 +106,27 @@ public void start(StartContext context) throws StartException {
if (pathRelativeTo != null) {
callbackHandle = pathManager.getValue().registerCallback(pathRelativeTo, PathManager.ReloadServerCallback.create(), PathManager.Event.UPDATED, PathManager.Event.REMOVED);
}
directory = new File(pathManager.getValue().resolveRelativePathEntry(path, pathRelativeTo));
if (!directory.exists()) {
if (!directory.mkdirs()) {
throw UndertowLogger.ROOT_LOGGER.couldNotCreateLogDirectory(directory);
directory = Paths.get(pathManager.getValue().resolveRelativePathEntry(path, pathRelativeTo));
if (!Files.exists(directory)) {
try {
Files.createDirectories(directory);
} catch (IOException e) {
throw UndertowLogger.ROOT_LOGGER.couldNotCreateLogDirectory(directory, e);
}
}
try {
logReceiver = new DefaultAccessLogReceiver(worker.getValue(), directory, filePrefix, fileSuffix, rotate);
DefaultAccessLogReceiver.Builder builder = DefaultAccessLogReceiver.builder().setLogWriteExecutor(worker.getValue())
.setOutputDirectory(directory)
.setLogBaseName(filePrefix)
.setLogNameSuffix(fileSuffix)
.setRotate(rotate);
if(extended) {
builder.setLogFileHeaderGenerator(new ExtendedAccessLogParser.ExtendedAccessLogHeaderGenerator(pattern));
realPattern = new ExtendedAccessLogParser(getClass().getClassLoader()).parse(pattern);
} else {
realPattern = ExchangeAttributes.parser(getClass().getClassLoader()).parse(pattern);
}
logReceiver = builder.build();
} catch (IllegalStateException e) {
throw new StartException(e);
}
Expand Down Expand Up @@ -129,7 +157,7 @@ InjectedValue<PathManager> getPathManager() {
}

protected AccessLogHandler configureAccessLogHandler(HttpHandler handler) {
return new AccessLogHandler(handler, logReceiver, pattern, AccessLogService.class.getClassLoader());
return new AccessLogHandler(handler, logReceiver, pattern, realPattern, predicate);
}

public InjectedValue<Host> getHost() {
Expand Down
Expand Up @@ -212,4 +212,5 @@ public interface Constants {
String ELECTED = "elected";
String PROACTIVE_AUTHENTICATION = "proactive-authentication";
String SESSION_ID_LENGTH = "session-id-length";
String EXTENDED = "extended";
}
Expand Up @@ -105,7 +105,7 @@ public class UndertowSubsystemParser_3_0 extends PersistentResourceXMLParser {
)
).addChild(
builder(AccessLogDefinition.INSTANCE)
.addAttributes(AccessLogDefinition.PATTERN, AccessLogDefinition.DIRECTORY, AccessLogDefinition.RELATIVE_TO, AccessLogDefinition.PREFIX, AccessLogDefinition.SUFFIX, AccessLogDefinition.WORKER, AccessLogDefinition.ROTATE, AccessLogDefinition.USE_SERVER_LOG)
.addAttributes(AccessLogDefinition.PATTERN, AccessLogDefinition.DIRECTORY, AccessLogDefinition.RELATIVE_TO, AccessLogDefinition.PREFIX, AccessLogDefinition.SUFFIX, AccessLogDefinition.WORKER, AccessLogDefinition.ROTATE, AccessLogDefinition.USE_SERVER_LOG, AccessLogDefinition.EXTENDED, AccessLogDefinition.PREDICATE)
).addChild(
builder(FilterRefDefinition.INSTANCE)
.addAttributes(FilterRefDefinition.PREDICATE, FilterRefDefinition.PRIORITY)
Expand Down
Expand Up @@ -27,7 +27,9 @@
import static org.jboss.logging.Logger.Level.WARN;

import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.file.Path;
import java.util.List;

import org.jboss.as.server.deployment.DeploymentUnit;
Expand Down Expand Up @@ -279,7 +281,7 @@ public interface UndertowLogger extends BasicLogger {
StartException failedToCreatePersistentSessionDir(File baseDir);

@Message(id = 62, value = "Could not create log directory: %s")
StartException couldNotCreateLogDirectory(File directory);
StartException couldNotCreateLogDirectory(Path directory, @Cause IOException e);

@Message(id = 63, value = "Could not find the port number listening for protocol %s")
IllegalStateException noPortListeningForProtocol(final String protocol);
Expand Down
Expand Up @@ -101,6 +101,8 @@ undertow.access-log.rotate=Rotate the access log every day.
undertow.access-log.worker=Name of the worker to use for logging
undertow.access-log.use-server-log=If the log should be written to the server log, rather than a separate file. Defaults to false.
undertow.access-log.relative-to=The directory the path is relative to
undertow.access-log.extended=If the log uses the extended log file format
undertow.access-log.predicate=Predicate that determines if the request should be logged
undertow.single-sign-on=The SSO configuration for this virtual server.
undertow.single-sign-on.add=Add a SSO configuration for this virtual server.
undertow.single-sign-on.remove=Erase the SSO configuration from the virtual server.
Expand Down
2 changes: 2 additions & 0 deletions undertow/src/main/resources/schema/wildfly-undertow_3_0.xsd
Expand Up @@ -338,6 +338,8 @@
<xs:attribute name="suffix" use="optional" type="xs:string" default=".log"/>
<xs:attribute name="rotate" use="optional" type="xs:string" default="true"/>
<xs:attribute name="use-server-log" use="optional" type="xs:string" default="false"/>
<xs:attribute name="extended" use="optional" type="xs:string" default="false" />
<xs:attribute name="predicate" use="optional" type="xs:string" />
</xs:complexType>
<xs:complexType name="errorPageType">
<xs:attribute name="name" use="required" type="xs:string"/>
Expand Down
Expand Up @@ -42,7 +42,7 @@
<filter-ref name="404-handler"/>
<filter-ref name="static-gzip" predicate="path-suffix['.js'] or path-suffix ['.css'] or path-prefix['/resources']"/>
</location>
<access-log pattern="REQ %{i,test-header}" directory="${jboss.server.server.dir}" prefix="access" rotate="false"/>
<access-log pattern="REQ %{i,test-header}" directory="${jboss.server.server.dir}" prefix="access" rotate="false" extended="false" predicate="not path-suffix[*.css]"/>
<single-sign-on domain="${prop.domain:myDomain}" http-only="true" secure="true" path="/path" cookie-name="SSOID"/>
</host>
<host name="other-host" alias="www.mysite.com, ${prop.value:default-alias}" default-web-module="something.war" disable-console-redirect="true">
Expand Down

0 comments on commit 5e29555

Please sign in to comment.