1   /**
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
4    *
5    * This program and the accompanying materials are dual-licensed under
6    * either the terms of the Eclipse Public License v1.0 as published by
7    * the Eclipse Foundation
8    *
9    *   or (per the licensee's choosing)
10   *
11   * under the terms of the GNU Lesser General Public License version 2.1
12   * as published by the Free Software Foundation.
13   */
14  package ch.qos.logback.access.common;
15  
16  import ch.qos.logback.access.common.pattern.ContentLengthConverter;
17  import ch.qos.logback.access.common.pattern.DateConverter;
18  import ch.qos.logback.access.common.pattern.ElapsedSecondsConverter;
19  import ch.qos.logback.access.common.pattern.ElapsedTimeConverter;
20  import ch.qos.logback.access.common.pattern.EnsureLineSeparation;
21  import ch.qos.logback.access.common.pattern.FullRequestConverter;
22  import ch.qos.logback.access.common.pattern.FullResponseConverter;
23  import ch.qos.logback.access.common.pattern.LineSeparatorConverter;
24  import ch.qos.logback.access.common.pattern.LocalIPAddressConverter;
25  import ch.qos.logback.access.common.pattern.LocalPortConverter;
26  import ch.qos.logback.access.common.pattern.NAConverter;
27  import ch.qos.logback.access.common.pattern.QueryStringConverter;
28  import ch.qos.logback.access.common.pattern.RemoteHostConverter;
29  import ch.qos.logback.access.common.pattern.RemoteIPAddressConverter;
30  import ch.qos.logback.access.common.pattern.RemoteUserConverter;
31  import ch.qos.logback.access.common.pattern.RequestAttributeConverter;
32  import ch.qos.logback.access.common.pattern.RequestContentConverter;
33  import ch.qos.logback.access.common.pattern.RequestCookieConverter;
34  import ch.qos.logback.access.common.pattern.RequestHeaderConverter;
35  import ch.qos.logback.access.common.pattern.RequestMethodConverter;
36  import ch.qos.logback.access.common.pattern.RequestParameterConverter;
37  import ch.qos.logback.access.common.pattern.RequestProtocolConverter;
38  import ch.qos.logback.access.common.pattern.RequestURIConverter;
39  import ch.qos.logback.access.common.pattern.RequestURLConverter;
40  import ch.qos.logback.access.common.pattern.ResponseContentConverter;
41  import ch.qos.logback.access.common.pattern.ResponseHeaderConverter;
42  import ch.qos.logback.access.common.pattern.ServerNameConverter;
43  import ch.qos.logback.access.common.pattern.SessionIDConverter;
44  import ch.qos.logback.access.common.pattern.StatusCodeConverter;
45  import ch.qos.logback.access.common.pattern.ThreadNameConverter;
46  import ch.qos.logback.access.common.spi.IAccessEvent;
47  import ch.qos.logback.core.pattern.DynamicConverter;
48  import ch.qos.logback.core.pattern.PatternLayoutBase;
49  import ch.qos.logback.core.pattern.color.*;
50  import ch.qos.logback.core.pattern.parser.Parser;
51  
52  import java.util.HashMap;
53  import java.util.Map;
54  import java.util.function.Supplier;
55  
56  /**
57   * <p>
58   * This class is a module-specific implementation of
59   * {@link PatternLayout} to allow http-specific patterns
60   * to be used. The <code>ch.qos.logback.access.PatternLayout</code> provides a
61   * way to format the logging output that is just as easy and flexible as the
62   * usual <code>PatternLayout</code>.
63   * </p>
64   * <p/>
65   * For more information about this layout, please refer to the online manual at
66   * http://logback.qos.ch/manual/layouts.html#AccessPatternLayout
67   *
68   * @author Ceki G&uuml;lc&uuml;
69   * @author S&eacute;bastien Pennec
70   */
71  public class PatternLayout extends PatternLayoutBase<IAccessEvent> {
72  
73      public static final Map<String, Supplier<DynamicConverter>> ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP = new HashMap<>();
74      public static final String HEADER_PREFIX = "#logback.access pattern: ";
75  
76      public static final String CLF_PATTERN = "%h %l %u [%t] \"%r\" %s %b";
77      public static final String CLF_PATTERN_NAME = "common";
78      public static final String CLF_PATTERN_NAME_2 = "clf";
79      public static final String COMBINED_PATTERN = "%h %l %u [%t] \"%r\" %s %b \"%i{Referer}\" \"%i{User-Agent}\"";
80      public static final String COMBINED_PATTERN_NAME = "combined";
81  
82      static {
83          ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.putAll(Parser.DEFAULT_COMPOSITE_CONVERTER_MAP);
84  
85          ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("a", RemoteIPAddressConverter::new);
86          ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("remoteIP", RemoteIPAddressConverter::new);
87  
88          ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("A", LocalIPAddressConverter::new);
89          ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("localIP", LocalIPAddressConverter::new);
90  
91          ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("b", ContentLengthConverter::new);
92          ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("B", ContentLengthConverter::new);
93          ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("bytesSent", ContentLengthConverter::new);
94  
95          ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("h", RemoteHostConverter::new);
96          ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("clientHost", RemoteHostConverter::new);
97  
98          ACCESS_DEFAULT_CONVERTER_SUPPLIER_MAP.put("H", RequestProtocolConverter::new);
99          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 }