All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.dropwizard.logging.json.layout.AccessJsonLayout Maven / Gradle / Ivy

package io.dropwizard.logging.json.layout;

import ch.qos.logback.access.spi.IAccessEvent;
import io.dropwizard.logging.json.AccessAttribute;

import javax.annotation.Nullable;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * Builds JSON messages from access log events as {@link IAccessEvent}.
 */
public class AccessJsonLayout extends AbstractJsonLayout {
    private static final String USER_AGENT = "User-Agent";

    private Set includes;

    private SortedSet requestHeaders = Collections.emptySortedSet();
    private SortedSet responseHeaders = Collections.emptySortedSet();
    private SortedSet requestAttributes = Collections.emptySortedSet();

    @Nullable
    private String jsonProtocolVersion;

    private final TimestampFormatter timestampFormatter;
    private final Map additionalFields;
    private final Map customFieldNames;

    public AccessJsonLayout(JsonFormatter jsonFormatter, TimestampFormatter timestampFormatter,
                            Set includes, Map customFieldNames,
                            Map additionalFields) {
        super(jsonFormatter);
        this.timestampFormatter = timestampFormatter;
        this.additionalFields = new HashMap<>(additionalFields);
        this.customFieldNames = new HashMap<>(customFieldNames);
        this.includes = EnumSet.copyOf(includes);
    }

    @Override
    protected Map toJsonMap(IAccessEvent event) {
        return new MapBuilder(timestampFormatter, customFieldNames, additionalFields, includes.size())
            .addNumber("port", isIncluded(AccessAttribute.LOCAL_PORT), event::getLocalPort)
            .addNumber("contentLength", isIncluded(AccessAttribute.CONTENT_LENGTH), event::getContentLength)
            .addTimestamp("timestamp", isIncluded(AccessAttribute.TIMESTAMP), event.getTimeStamp())
            .add("method", isIncluded(AccessAttribute.METHOD), event::getMethod)
            .add("protocol", isIncluded(AccessAttribute.PROTOCOL), event::getProtocol)
            .add("requestContent", isIncluded(AccessAttribute.REQUEST_CONTENT), event::getRequestContent)
            .add("remoteAddress", isIncluded(AccessAttribute.REMOTE_ADDRESS), event::getRemoteAddr)
            .add("remoteUser", isIncluded(AccessAttribute.REMOTE_USER), event::getRemoteUser)
            .addMap("headers", !requestHeaders.isEmpty(),
                () -> filterHeaders(event.getRequestHeaderMap(), requestHeaders))
            .addMap("params", isIncluded(AccessAttribute.REQUEST_PARAMETERS), event::getRequestParameterMap)
            .addNumber("requestTime", isIncluded(AccessAttribute.REQUEST_TIME), event::getElapsedTime)
            .add("uri", isIncluded(AccessAttribute.REQUEST_URI), event::getRequestURI)
            .add("url", isIncluded(AccessAttribute.REQUEST_URL), event::getRequestURL)
            .add("pathQuery", isIncluded(AccessAttribute.PATH_QUERY), () -> event.getRequestURI() + event.getQueryString())
            .add("remoteHost", isIncluded(AccessAttribute.REMOTE_HOST), event::getRemoteHost)
            .add("responseContent", isIncluded(AccessAttribute.RESPONSE_CONTENT), event::getResponseContent)
            .addMap("responseHeaders", !responseHeaders.isEmpty(),
                () -> filterHeaders(event.getResponseHeaderMap(), responseHeaders))
            .add("serverName", isIncluded(AccessAttribute.SERVER_NAME), event::getServerName)
            .addNumber("status", isIncluded(AccessAttribute.STATUS_CODE), event::getStatusCode)
            .add("userAgent", isIncluded(AccessAttribute.USER_AGENT), () -> event.getRequestHeader(USER_AGENT))
            .add("version", jsonProtocolVersion != null, jsonProtocolVersion)
            .addMap("requestAttributes", !requestAttributes.isEmpty(),
                () -> filterRequestAttributes(requestAttributes, event))
            .build();
    }

    private boolean isIncluded(AccessAttribute attribute) {
        return includes.contains(attribute);
    }

    private Map filterRequestAttributes(Set requestAttributeNames, IAccessEvent event) {
        return requestAttributeNames.stream()
            .filter(name -> event.getAttribute(name) != null)
            .collect(Collectors.toMap(Function.identity(), event::getAttribute));
    }

    private Map filterHeaders(Map headers, Set filteredHeaderNames) {
        if (filteredHeaderNames.isEmpty()) {
            return Collections.emptyMap();
        }
        return headers.entrySet().stream()
            .filter(e -> filteredHeaderNames.contains(e.getKey()))
            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
    }

    public Set getIncludes() {
        return includes;
    }

    public void setIncludes(Set includes) {
        this.includes = EnumSet.copyOf(includes);
    }

    @Nullable
    public String getJsonProtocolVersion() {
        return jsonProtocolVersion;
    }

    public void setJsonProtocolVersion(@Nullable String jsonProtocolVersion) {
        this.jsonProtocolVersion = jsonProtocolVersion;
    }

    public Set getRequestHeaders() {
        return requestHeaders;
    }

    public void setRequestHeaders(Set requestHeaders) {
        final TreeSet headers = new TreeSet<>(String::compareToIgnoreCase);
        headers.addAll(requestHeaders);
        this.requestHeaders = headers;
    }

    public Set getResponseHeaders() {
        return responseHeaders;
    }

    public void setResponseHeaders(Set responseHeaders) {
        final TreeSet headers = new TreeSet<>(String::compareToIgnoreCase);
        headers.addAll(responseHeaders);
        this.responseHeaders = headers;
    }

    /**
     * @since 2.0
     */
    public Set getRequestAttributes() {
        return requestAttributes;
    }

    /**
     * @since 2.0
     */
    public void setRequestAttributes(Set requestAttributes) {
        final TreeSet attributes = new TreeSet<>(String::compareToIgnoreCase);
        attributes.addAll(requestAttributes);
        this.requestAttributes = attributes;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy