1
2
3
4
5
6
7
8
9
10
11
12
13 package org.abstracthorizon.danube.support.logging;
14
15 import org.abstracthorizon.danube.connection.Connection;
16 import org.abstracthorizon.danube.connection.ConnectionHandler;
17 import org.abstracthorizon.danube.connection.ConnectionWrapper;
18 import org.abstracthorizon.danube.support.logging.patternsupport.CurrentDateTimeProcessor;
19 import org.abstracthorizon.danube.support.logging.patternsupport.HandlingTimeProcessor;
20 import org.abstracthorizon.danube.support.logging.patternsupport.PatternProcessor;
21 import org.abstracthorizon.danube.support.logging.patternsupport.SocketDetailsProcessor;
22 import org.abstracthorizon.danube.support.logging.util.LogFileRotator;
23
24 import java.io.IOException;
25 import java.io.OutputStream;
26 import java.text.MessageFormat;
27 import java.util.ArrayList;
28 import java.util.List;
29
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57 public class AccessLogConnectionHandler implements ConnectionHandler {
58
59
60 protected final Logger logger = LoggerFactory.getLogger(getClass());
61
62
63 private LogFileRotator logFileRotator;
64
65
66 private ConnectionHandler connectionHandler;
67
68
69 private String logPattern;
70
71
72 private List<String> customProcessors = new ArrayList<String>();
73
74
75 protected String logPatternString;
76
77
78 protected PatternProcessor[] selectedProcessors;
79
80
81 protected int argumentNumber;
82
83
84
85
86 public AccessLogConnectionHandler() {
87 String defaultLogPattern = getDefaultLogPattern();
88 if (defaultLogPattern != null) {
89 setLogPattern(defaultLogPattern);
90 }
91 }
92
93
94
95
96
97 protected String getDefaultLogPattern() {
98 return "%a %h %A %p %t %D %T";
99 }
100
101
102
103
104
105 public ConnectionHandler getConnectionHandler() {
106 return connectionHandler;
107 }
108
109
110
111
112
113 public void setConnectionHandler(ConnectionHandler connectionHandler) {
114 this.connectionHandler = connectionHandler;
115 }
116
117
118
119
120
121 public List<String> getCustomProcessors() {
122 return customProcessors;
123 }
124
125
126
127
128
129 public void setCustomProcessors(List<String> customProcessors) {
130 this.customProcessors = customProcessors;
131 }
132
133
134
135
136
137 public LogFileRotator getLogFileRotator() {
138 return logFileRotator;
139 }
140
141
142
143
144
145 public void setLogFileRotator(LogFileRotator logFileRotator) {
146 this.logFileRotator = logFileRotator;
147 }
148
149
150
151
152
153 public String getLogPattern() {
154 return logPatternString;
155 }
156
157
158
159
160
161 public void setLogPattern(String logPattern) {
162 this.logPatternString = logPattern;
163 StringBuffer message = new StringBuffer(logPattern);
164
165 int index = 0;
166 ArrayList<String> providerClasses = new ArrayList<String>(getCustomProcessors());
167 addPredefinedProcessors(providerClasses);
168
169 ArrayList<PatternProcessor> providers = new ArrayList<PatternProcessor>();
170 for (String className : providerClasses) {
171 try {
172 ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
173 Class<?> cls = classLoader.loadClass(className);
174 PatternProcessor processor = (PatternProcessor)cls.newInstance();
175 int newIndex = processor.init(index, message);
176 if (newIndex > index) {
177 providers.add(processor);
178 }
179 index = newIndex;
180 } catch (Exception e) {
181 logger.error("Problem with processing provider " + className, e);
182 }
183 }
184
185 this.argumentNumber = index;
186 this.selectedProcessors = new PatternProcessor[providers.size()];
187 this.selectedProcessors = providers.toArray(this.selectedProcessors);
188
189 this.logPattern = message.toString();
190 }
191
192
193
194
195
196
197
198
199
200
201
202 protected void addPredefinedProcessors(List<String> providerClasses) {
203 if (!providerClasses.contains(HandlingTimeProcessor.class.getName())) {
204 providerClasses.add(HandlingTimeProcessor.class.getName());
205 }
206 if (!providerClasses.contains(CurrentDateTimeProcessor.class.getName())) {
207 providerClasses.add(CurrentDateTimeProcessor.class.getName());
208 }
209 if (!providerClasses.contains(SocketDetailsProcessor.class.getName())) {
210 providerClasses.add(SocketDetailsProcessor.class.getName());
211 }
212 }
213
214
215
216
217
218
219
220 public void handleConnection(Connection connection) {
221 long start = System.currentTimeMillis();
222 try {
223 connectionHandler.handleConnection(connection);
224 } finally {
225 String logLine = createLogLine(connection, start);
226 if (logLine != null) {
227 outputLogLine(logLine);
228 }
229
230 }
231 }
232
233
234
235
236
237 protected void outputLogLine(String logLine) {
238 try {
239 OutputStream out = logFileRotator.logFile();
240 synchronized (out) {
241 out.write(logLine.getBytes());
242 out.write('\r');
243 out.write('\n');
244 }
245 } catch (IOException e) {
246 logger.error("Problem writing to access log", e);
247 try {
248 logFileRotator.rotate();
249 } catch (IOException e1) {
250 logger.error("Problem rotating access log", e);
251 }
252 }
253 }
254
255
256
257
258
259
260
261
262
263 protected String createLogLine(Connection connection, long start) {
264 String logLine;
265
266 if (selectedProcessors.length > 0) {
267 DateWrapper dateWrappedConnection = new DateWrapper(connection, start);
268
269 Object[] arguments = new Object[argumentNumber];
270 for (PatternProcessor provider : selectedProcessors) {
271 provider.process(dateWrappedConnection, arguments);
272 }
273 logLine = MessageFormat.format(logPattern, arguments);
274 } else {
275 logLine = logPattern;
276 }
277
278 return logLine;
279 }
280
281
282
283
284
285
286 public static class DateWrapper extends ConnectionWrapper {
287
288 long handlingStarted;
289
290
291
292
293
294
295 public DateWrapper(Connection connection, long handlingStarted) {
296 super(connection);
297 this.handlingStarted = handlingStarted;
298 }
299
300
301
302
303
304 public long getHandlingStarted() {
305 return handlingStarted;
306 }
307
308
309
310
311
312
313 @SuppressWarnings("unchecked")
314 public <T> T adapt(Class<T> cls) {
315 if (cls == DateWrapper.class) {
316 return (T)this;
317 } else {
318 return super.adapt(cls);
319 }
320 }
321
322 }
323
324 }