net.logstash.logback.LogstashAccessFormatter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of logstash-logback-encoder Show documentation
Show all versions of logstash-logback-encoder Show documentation
Provides logback encoders, layouts, and appenders to log in JSON and other formats supported by Jackson
/*
* Copyright 2013-2022 the original author or authors.
*
* Licensed 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 net.logstash.logback;
import net.logstash.logback.composite.ContextJsonProvider;
import net.logstash.logback.composite.FieldNamesAware;
import net.logstash.logback.composite.GlobalCustomFieldsJsonProvider;
import net.logstash.logback.composite.JsonProvider;
import net.logstash.logback.composite.JsonProviders;
import net.logstash.logback.composite.LogstashVersionJsonProvider;
import net.logstash.logback.composite.accessevent.AccessEventCompositeJsonFormatter;
import net.logstash.logback.composite.accessevent.AccessEventFormattedTimestampJsonProvider;
import net.logstash.logback.composite.accessevent.AccessEventJsonProviders;
import net.logstash.logback.composite.accessevent.AccessEventPatternJsonProvider;
import net.logstash.logback.composite.accessevent.AccessMessageJsonProvider;
import net.logstash.logback.composite.accessevent.ContentLengthJsonProvider;
import net.logstash.logback.composite.accessevent.ElapsedTimeJsonProvider;
import net.logstash.logback.composite.accessevent.HeaderFilter;
import net.logstash.logback.composite.accessevent.IncludeExcludeHeaderFilter;
import net.logstash.logback.composite.accessevent.MethodJsonProvider;
import net.logstash.logback.composite.accessevent.ProtocolJsonProvider;
import net.logstash.logback.composite.accessevent.RemoteHostJsonProvider;
import net.logstash.logback.composite.accessevent.RemoteUserJsonProvider;
import net.logstash.logback.composite.accessevent.RequestHeadersJsonProvider;
import net.logstash.logback.composite.accessevent.RequestedUriJsonProvider;
import net.logstash.logback.composite.accessevent.RequestedUrlJsonProvider;
import net.logstash.logback.composite.accessevent.ResponseHeadersJsonProvider;
import net.logstash.logback.composite.accessevent.StatusCodeJsonProvider;
import net.logstash.logback.fieldnames.LogstashAccessFieldNames;
import ch.qos.logback.access.spi.IAccessEvent;
import ch.qos.logback.core.joran.spi.DefaultClass;
import ch.qos.logback.core.spi.ContextAware;
import com.fasterxml.jackson.databind.JsonNode;
/**
* A {@link AccessEventCompositeJsonFormatter} that contains a common
* pre-defined set of {@link JsonProvider}s.
*
* The included providers are configured via properties on this
* formatter, rather than configuring the providers directly.
* This leads to a somewhat simpler configuration definitions.
*
* You cannot remove any of the pre-defined providers, but
* you can add additional providers via {@link #addProvider(JsonProvider)}.
*
* If you would like full control over the providers, you
* should instead use {@link AccessEventCompositeJsonFormatter} directly.
*/
public class LogstashAccessFormatter extends AccessEventCompositeJsonFormatter {
/**
* The field names to use when writing the access event fields
*/
protected LogstashAccessFieldNames fieldNames = new LogstashAccessFieldNames();
private final AccessEventFormattedTimestampJsonProvider timestampProvider = new AccessEventFormattedTimestampJsonProvider();
private final LogstashVersionJsonProvider versionProvider = new LogstashVersionJsonProvider<>();
private final MethodJsonProvider methodProvider = new MethodJsonProvider();
private final ProtocolJsonProvider protocolProvider = new ProtocolJsonProvider();
private final StatusCodeJsonProvider statusCodeProvider = new StatusCodeJsonProvider();
private final RequestedUrlJsonProvider requestedUrlProvider = new RequestedUrlJsonProvider();
private final RequestedUriJsonProvider requestedUriProvider = new RequestedUriJsonProvider();
private final RemoteHostJsonProvider remoteHostProvider = new RemoteHostJsonProvider();
private final RemoteUserJsonProvider remoteUserProvider = new RemoteUserJsonProvider();
private final ContentLengthJsonProvider contentLengthProvider = new ContentLengthJsonProvider();
private final ElapsedTimeJsonProvider elapsedTimeProvider = new ElapsedTimeJsonProvider();
private final RequestHeadersJsonProvider requestHeadersProvider = new RequestHeadersJsonProvider();
private final ResponseHeadersJsonProvider responseHeadersProvider = new ResponseHeadersJsonProvider();
private JsonProvider messageProvider;
private ContextJsonProvider contextProvider = new ContextJsonProvider<>();
private GlobalCustomFieldsJsonProvider globalCustomFieldsProvider;
private String messagePattern;
public LogstashAccessFormatter(ContextAware declaredOrigin) {
super(declaredOrigin);
getProviders().addTimestamp(this.timestampProvider);
getProviders().addVersion(this.versionProvider);
getProviders().addMethod(this.methodProvider);
getProviders().addProtocol(this.protocolProvider);
getProviders().addStatusCode(this.statusCodeProvider);
getProviders().addRequestedUrl(this.requestedUrlProvider);
getProviders().addRequestedUri(this.requestedUriProvider);
getProviders().addRemoteHost(this.remoteHostProvider);
getProviders().addRemoteUser(this.remoteUserProvider);
getProviders().addContentLength(this.contentLengthProvider);
getProviders().addElapsedTime(this.elapsedTimeProvider);
getProviders().addRequestHeaders(this.requestHeadersProvider);
getProviders().addResponseHeaders(this.responseHeadersProvider);
getProviders().addContext(this.contextProvider);
}
@Override
public void start() {
updateMessageProvider();
configureProviderFieldNames();
super.start();
}
private void updateMessageProvider() {
getProviders().removeProvider(this.messageProvider);
if (this.messagePattern != null) {
// Build JSON object of the form:
//
// { "fieldName": "messagePattern" }
//
String accessEventPattern = new StringBuilder("{\"")
.append(this.fieldNames.getMessage())
.append("\": \"")
.append(escapeJson(this.messagePattern))
.append("\"}")
.toString();
AccessEventPatternJsonProvider messagePatternProvider = new AccessEventPatternJsonProvider();
messagePatternProvider.setPattern(accessEventPattern);
this.messageProvider = messagePatternProvider;
} else {
AccessMessageJsonProvider accessMessageJsonProvider = new AccessMessageJsonProvider();
accessMessageJsonProvider.setTimeZone(this.timestampProvider.getTimeZone());
this.messageProvider = accessMessageJsonProvider;
}
getProviders().addProvider(this.messageProvider);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
protected void configureProviderFieldNames() {
for (JsonProvider provider : getProviders().getProviders()) {
if (provider instanceof FieldNamesAware) {
((FieldNamesAware) provider).setFieldNames(fieldNames);
}
}
}
public void addProvider(JsonProvider provider) {
getProviders().addProvider(provider);
}
@Override
public AccessEventJsonProviders getProviders() {
return (AccessEventJsonProviders) super.getProviders();
}
public LogstashAccessFieldNames getFieldNames() {
return fieldNames;
}
public void setFieldNames(LogstashAccessFieldNames fieldNames) {
this.fieldNames = fieldNames;
}
public String getTimeZone() {
return timestampProvider.getTimeZone();
}
public void setTimeZone(String timeZoneId) {
this.timestampProvider.setTimeZone(timeZoneId);
}
public String getTimestampPattern() {
return timestampProvider.getPattern();
}
public void setTimestampPattern(String pattern) {
timestampProvider.setPattern(pattern);
}
public String getCustomFieldsAsString() {
return globalCustomFieldsProvider == null
? null
: globalCustomFieldsProvider.getCustomFields();
}
public void setCustomFieldsFromString(String customFields) {
if (customFields == null || customFields.length() == 0) {
getProviders().removeProvider(globalCustomFieldsProvider);
globalCustomFieldsProvider = null;
} else {
if (globalCustomFieldsProvider == null) {
globalCustomFieldsProvider = new GlobalCustomFieldsJsonProvider<>();
getProviders().addGlobalCustomFields(globalCustomFieldsProvider);
}
globalCustomFieldsProvider.setCustomFields(customFields);
}
}
public void setCustomFields(JsonNode customFields) {
if (customFields == null) {
getProviders().removeProvider(globalCustomFieldsProvider);
globalCustomFieldsProvider = null;
} else {
if (globalCustomFieldsProvider == null) {
globalCustomFieldsProvider = new GlobalCustomFieldsJsonProvider<>();
getProviders().addGlobalCustomFields(globalCustomFieldsProvider);
}
globalCustomFieldsProvider.setCustomFieldsNode(customFields);
}
}
public JsonNode getCustomFields() {
return globalCustomFieldsProvider == null
? null
: globalCustomFieldsProvider.getCustomFieldsNode();
}
public boolean getLowerCaseHeaderNames() {
return this.requestHeadersProvider.getLowerCaseHeaderNames();
}
/**
* When true, names of headers will be written to JSON output in lower case.
*
* @param lowerCaseHeaderNames When true, names of headers will be written to JSON output in lower case.
*/
public void setLowerCaseHeaderNames(boolean lowerCaseHeaderNames) {
this.requestHeadersProvider.setLowerCaseHeaderNames(lowerCaseHeaderNames);
this.responseHeadersProvider.setLowerCaseHeaderNames(lowerCaseHeaderNames);
}
public HeaderFilter getRequestHeaderFilter() {
return this.requestHeadersProvider.getFilter();
}
@DefaultClass(IncludeExcludeHeaderFilter.class)
public void setRequestHeaderFilter(HeaderFilter filter) {
this.requestHeadersProvider.setFilter(filter);
}
public HeaderFilter getResponseHeaderFilter() {
return this.responseHeadersProvider.getFilter();
}
@DefaultClass(IncludeExcludeHeaderFilter.class)
public void setResponseHeaderFilter(HeaderFilter filter) {
this.responseHeadersProvider.setFilter(filter);
}
public boolean isIncludeContext() {
return contextProvider != null;
}
public void setIncludeContext(boolean includeContext) {
if (isIncludeContext() != includeContext) {
getProviders().removeProvider(contextProvider);
if (includeContext) {
contextProvider = new ContextJsonProvider<>();
getProviders().addContext(contextProvider);
} else {
contextProvider = null;
}
}
}
public String getMessagePattern() {
return messagePattern;
}
public void setMessagePattern(String messagePattern) {
this.messagePattern = messagePattern;
}
public String getVersion() {
return this.versionProvider.getVersion();
}
public void setVersion(String version) {
this.versionProvider.setVersion(version);
}
public boolean isWriteVersionAsInteger() {
return this.versionProvider.isWriteAsInteger();
}
public void setWriteVersionAsInteger(boolean writeVersionAsInteger) {
this.versionProvider.setWriteAsInteger(writeVersionAsInteger);
}
@Override
public void setProviders(JsonProviders jsonProviders) {
if (super.getProviders() != null && !super.getProviders().getProviders().isEmpty()) {
addError("Unable to set providers when using predefined composites.");
} else {
super.setProviders(jsonProviders);
}
}
private static String escapeJson(String str) {
return str.replace("\"", "\\\"");
}
}