001/**
002 * Logback: the reliable, generic, fast and flexible logging framework.
003 * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
004 *
005 * This program and the accompanying materials are dual-licensed under
006 * either the terms of the Eclipse Public License v1.0 as published by
007 * the Eclipse Foundation
008 *
009 *   or (per the licensee's choosing)
010 *
011 * under the terms of the GNU Lesser General Public License version 2.1
012 * as published by the Free Software Foundation.
013 */
014package ch.qos.logback.access.common;
015
016import ch.qos.logback.access.common.pattern.ContentLengthConverter;
017import ch.qos.logback.access.common.pattern.DateConverter;
018import ch.qos.logback.access.common.pattern.ElapsedSecondsConverter;
019import ch.qos.logback.access.common.pattern.ElapsedTimeConverter;
020import ch.qos.logback.access.common.pattern.EnsureLineSeparation;
021import ch.qos.logback.access.common.pattern.FullRequestConverter;
022import ch.qos.logback.access.common.pattern.FullResponseConverter;
023import ch.qos.logback.access.common.pattern.LineSeparatorConverter;
024import ch.qos.logback.access.common.pattern.LocalIPAddressConverter;
025import ch.qos.logback.access.common.pattern.LocalPortConverter;
026import ch.qos.logback.access.common.pattern.NAConverter;
027import ch.qos.logback.access.common.pattern.QueryStringConverter;
028import ch.qos.logback.access.common.pattern.RemoteHostConverter;
029import ch.qos.logback.access.common.pattern.RemoteIPAddressConverter;
030import ch.qos.logback.access.common.pattern.RemoteUserConverter;
031import ch.qos.logback.access.common.pattern.RequestAttributeConverter;
032import ch.qos.logback.access.common.pattern.RequestContentConverter;
033import ch.qos.logback.access.common.pattern.RequestCookieConverter;
034import ch.qos.logback.access.common.pattern.RequestHeaderConverter;
035import ch.qos.logback.access.common.pattern.RequestMethodConverter;
036import ch.qos.logback.access.common.pattern.RequestParameterConverter;
037import ch.qos.logback.access.common.pattern.RequestProtocolConverter;
038import ch.qos.logback.access.common.pattern.RequestURIConverter;
039import ch.qos.logback.access.common.pattern.RequestURLConverter;
040import ch.qos.logback.access.common.pattern.ResponseContentConverter;
041import ch.qos.logback.access.common.pattern.ResponseHeaderConverter;
042import ch.qos.logback.access.common.pattern.ServerNameConverter;
043import ch.qos.logback.access.common.pattern.SessionIDConverter;
044import ch.qos.logback.access.common.pattern.StatusCodeConverter;
045import ch.qos.logback.access.common.pattern.ThreadNameConverter;
046import ch.qos.logback.access.common.spi.IAccessEvent;
047import ch.qos.logback.core.pattern.DynamicConverter;
048import ch.qos.logback.core.pattern.PatternLayoutBase;
049import ch.qos.logback.core.pattern.color.*;
050import ch.qos.logback.core.pattern.parser.Parser;
051
052import java.util.HashMap;
053import java.util.Map;
054import java.util.function.Supplier;
055
056/**
057 * <p>
058 * This class is a module-specific implementation of
059 * {@link PatternLayout} to allow http-specific patterns
060 * to be used. The <code>ch.qos.logback.access.PatternLayout</code> provides a
061 * way to format the logging output that is just as easy and flexible as the
062 * usual <code>PatternLayout</code>.
063 * </p>
064 * <p/>
065 * For more information about this layout, please refer to the online manual at
066 * http://logback.qos.ch/manual/layouts.html#AccessPatternLayout
067 *
068 * @author Ceki G&uuml;lc&uuml;
069 * @author S&eacute;bastien Pennec
070 */
071public class PatternLayout extends PatternLayoutBase<IAccessEvent> {
072
073    public static final Map<String, Supplier<DynamicConverter>> ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP = new HashMap<>();
074    public static final String HEADER_PREFIX = "#logback.access pattern: ";
075
076    public static final String CLF_PATTERN = "%h %l %u [%t] \"%r\" %s %b";
077    public static final String CLF_PATTERN_NAME = "common";
078    public static final String CLF_PATTERN_NAME_2 = "clf";
079    public static final String COMBINED_PATTERN = "%h %l %u [%t] \"%r\" %s %b \"%i{Referer}\" \"%i{User-Agent}\"";
080    public static final String COMBINED_PATTERN_NAME = "combined";
081
082    static {
083        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.putAll(Parser.DEFAULT_COMPOSITE_CONVERTER_MAP);
084
085        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("a", RemoteIPAddressConverter::new);
086        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("remoteIP", RemoteIPAddressConverter::new);
087
088        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("A", LocalIPAddressConverter::new);
089        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("localIP", LocalIPAddressConverter::new);
090
091        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("b", ContentLengthConverter::new);
092        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("B", ContentLengthConverter::new);
093        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("bytesSent", ContentLengthConverter::new);
094
095        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("h", RemoteHostConverter::new);
096        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("clientHost", RemoteHostConverter::new);
097
098        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("H", RequestProtocolConverter::new);
099        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("protocol", RequestProtocolConverter::new);
100
101        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("i", RequestHeaderConverter::new);
102        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("header", RequestHeaderConverter::new);
103
104        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("I", ThreadNameConverter::new);
105        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("threadName", ThreadNameConverter::new);
106
107        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("l", NAConverter::new);
108
109        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("m", RequestMethodConverter::new);
110        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("requestMethod", RequestMethodConverter::new);
111
112        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("q", QueryStringConverter::new);
113        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("queryString", QueryStringConverter::new);
114
115        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("r", RequestURLConverter::new);
116        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("requestURL", RequestURLConverter::new);
117
118        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("s", StatusCodeConverter::new);
119        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("statusCode", StatusCodeConverter::new);
120
121        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("S", SessionIDConverter::new);
122        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("sessionID", SessionIDConverter::new);
123
124        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("t", DateConverter::new);
125        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("date", DateConverter::new);
126
127        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("u", RemoteUserConverter::new);
128        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("user", RemoteUserConverter::new);
129
130        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("U", RequestURIConverter::new);
131        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("requestURI", RequestURIConverter::new);
132
133        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("v", ServerNameConverter::new);
134        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("server", ServerNameConverter::new);
135
136        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("localPort", LocalPortConverter::new);
137
138        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("requestAttribute", RequestAttributeConverter::new);
139        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("reqAttribute", RequestAttributeConverter::new);
140
141        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("reqCookie", RequestCookieConverter::new);
142        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("requestCookie", RequestCookieConverter::new);
143
144        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("responseHeader", ResponseHeaderConverter::new);
145
146        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("requestParameter", RequestParameterConverter::new);
147        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("reqParameter", RequestParameterConverter::new);
148
149        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("requestContent", RequestContentConverter::new);
150
151        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("responseContent", ResponseContentConverter::new);
152
153        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("fullRequest", FullRequestConverter::new);
154        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("fullResponse", FullResponseConverter::new);
155
156        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("elapsedTime", ElapsedTimeConverter::new);
157        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("D", ElapsedTimeConverter::new);
158
159        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("elapsedSeconds", ElapsedSecondsConverter::new);
160        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("T", ElapsedSecondsConverter::new);
161
162        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("n", LineSeparatorConverter::new);
163
164        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("black", BlackCompositeConverter::new);
165        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("red", RedCompositeConverter::new);
166        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("green", GreenCompositeConverter::new);
167        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("yellow", YellowCompositeConverter::new);
168        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("blue", BlueCompositeConverter::new);
169        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("magenta", MagentaCompositeConverter::new);
170        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("cyan", CyanCompositeConverter::new);
171        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("white", WhiteCompositeConverter::new);
172        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("gray", GrayCompositeConverter::new);
173        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("boldRed", BoldRedCompositeConverter::new);
174        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("boldGreen", BoldGreenCompositeConverter::new);
175        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("boldYellow", BoldYellowCompositeConverter::new);
176        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("boldBlue", BoldBlueCompositeConverter::new);
177        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("boldMagenta", BoldMagentaCompositeConverter::new);
178        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("boldCyan", BoldCyanCompositeConverter::new);
179        ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("boldWhite", BoldWhiteCompositeConverter::new);
180    }
181
182    public PatternLayout() {
183        // set a default value for pattern
184        setPattern(CLF_PATTERN);
185        // by default postCompileProcessor is an EnsureLineSeparation instance
186        this.postCompileProcessor = new EnsureLineSeparation();
187    }
188
189    /**
190     * Returns the default converter map for this instance.
191     */
192    @Override
193    public Map<String, Supplier<DynamicConverter>> getDefaultConverterSupplierMap() {
194        return ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP;
195    }
196
197    @Override
198    public Map<String, String> getDefaultConverterMap() {
199        return Map.of();
200    }
201
202    @Override
203    public String doLayout(IAccessEvent event) {
204        if (!isStarted()) {
205            return null;
206        }
207        return writeLoopOnConverters(event);
208    }
209
210    @Override
211    public void start() {
212        if (getPattern().equalsIgnoreCase(CLF_PATTERN_NAME) || getPattern().equalsIgnoreCase(CLF_PATTERN_NAME_2)) {
213            setPattern(CLF_PATTERN);
214        } else if (getPattern().equalsIgnoreCase(COMBINED_PATTERN_NAME)) {
215            setPattern(COMBINED_PATTERN);
216        }
217        super.start();
218    }
219
220    @Override
221    protected String getPresentationHeaderPrefix() {
222        return HEADER_PREFIX;
223    }
224}