1
2
3
4
5
6
7
8
9
10
11
12
13
14 package ch.qos.logback.access.jetty;
15
16 import ch.qos.logback.access.common.joran.JoranConfigurator;
17 import ch.qos.logback.access.common.spi.AccessEvent;
18 import ch.qos.logback.access.common.spi.IAccessEvent;
19 import ch.qos.logback.core.Appender;
20 import ch.qos.logback.core.ContextBase;
21 import ch.qos.logback.core.CoreConstants;
22 import ch.qos.logback.core.boolex.EventEvaluator;
23 import ch.qos.logback.core.filter.Filter;
24 import ch.qos.logback.core.joran.spi.JoranException;
25 import ch.qos.logback.core.spi.AppenderAttachable;
26 import ch.qos.logback.core.spi.AppenderAttachableImpl;
27 import ch.qos.logback.core.spi.FilterAttachable;
28 import ch.qos.logback.core.spi.FilterAttachableImpl;
29 import ch.qos.logback.core.spi.FilterReply;
30 import ch.qos.logback.core.status.ErrorStatus;
31 import ch.qos.logback.core.status.InfoStatus;
32 import ch.qos.logback.core.util.FileUtil;
33 import ch.qos.logback.core.util.OptionHelper;
34 import ch.qos.logback.core.util.StatusPrinter;
35 import org.eclipse.jetty.server.Request;
36 import org.eclipse.jetty.server.RequestLog;
37 import org.eclipse.jetty.server.Response;
38 import org.eclipse.jetty.util.component.LifeCycle;
39
40 import java.io.File;
41 import java.net.URL;
42 import java.util.EventListener;
43 import java.util.HashMap;
44 import java.util.Iterator;
45 import java.util.List;
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231 public class RequestLogImpl extends ContextBase implements org.eclipse.jetty.util.component.LifeCycle, RequestLog, AppenderAttachable<IAccessEvent>, FilterAttachable<IAccessEvent> {
232
233 public final static String DEFAULT_CONFIG_FILE = "etc" + File.separatorChar + "logback-access.xml";
234
235 enum State {
236 FAILED, STOPPED, STARTING, STARTED, STOPPING
237 }
238
239 State state = State.STOPPED;
240
241 AppenderAttachableImpl<IAccessEvent> aai = new AppenderAttachableImpl<IAccessEvent>();
242 FilterAttachableImpl<IAccessEvent> fai = new FilterAttachableImpl<IAccessEvent>();
243 String fileName;
244 String resource;
245
246 boolean quiet = false;
247
248 public RequestLogImpl() {
249 putObject(CoreConstants.EVALUATOR_MAP, new HashMap<String, EventEvaluator<?>>());
250 }
251
252 @Override
253 public void log(Request jettyRequest, Response jettyResponse) {
254 JettyServerAdapter adapter = makeJettyServerAdapter(jettyRequest, jettyResponse);
255 RequestWrapper requestWrapper = new RequestWrapper(jettyRequest);
256 ResponseWrapper responseWrapper = new ResponseWrapper(jettyResponse);
257
258 IAccessEvent accessEvent = new AccessEvent(this, requestWrapper, responseWrapper, adapter);
259 if (getFilterChainDecision(accessEvent) == FilterReply.DENY) {
260 return;
261 }
262 aai.appendLoopOnAppenders(accessEvent);
263 }
264
265 private JettyServerAdapter makeJettyServerAdapter(Request jettyRequest, Response jettyResponse) {
266 return new JettyModernServerAdapter(jettyRequest, jettyResponse);
267 }
268
269 protected void addInfo(String msg) {
270 getStatusManager().add(new InfoStatus(msg, this));
271 }
272
273 private void addError(String msg) {
274 getStatusManager().add(new ErrorStatus(msg, this));
275 }
276
277 @Override
278 public void start() {
279 state = State.STARTING;
280 try {
281 configure();
282 if (!isQuiet()) {
283 StatusPrinter.print(getStatusManager());
284 }
285 state = State.STARTED;
286 } catch (Throwable t) {
287 t.printStackTrace();
288 state = State.FAILED;
289 }
290 }
291
292 protected void configure() {
293 URL configURL = getConfigurationFileURL();
294 if (configURL != null) {
295 runJoranOnFile(configURL);
296 } else {
297 addError("Could not find configuration file for logback-access");
298 }
299 }
300
301 protected URL getConfigurationFileURL() {
302 if (fileName != null) {
303 addInfo("Will use configuration file [" + fileName + "]");
304 File file = new File(fileName);
305 if (!file.exists()) return null;
306 return FileUtil.fileToURL(file);
307 }
308 if (resource != null) {
309 addInfo("Will use configuration resource [" + resource + "]");
310 return this.getClass().getResource(resource);
311 }
312
313 String defaultConfigFile = DEFAULT_CONFIG_FILE;
314
315 String jettyBaseProperty = OptionHelper.getSystemProperty("jetty.base");
316 if (!OptionHelper.isNullOrEmpty(jettyBaseProperty)) {
317 defaultConfigFile = jettyBaseProperty + File.separatorChar + DEFAULT_CONFIG_FILE;
318 }
319
320 File file = new File(defaultConfigFile);
321 if (!file.exists()) {
322
323 String jettyHomeProperty = OptionHelper.getSystemProperty("jetty.home");
324 if (!OptionHelper.isEmpty(jettyHomeProperty)) {
325 defaultConfigFile = jettyHomeProperty + File.separatorChar + DEFAULT_CONFIG_FILE;
326 } else {
327 addInfo("Neither [jetty.base] nor [jetty.home] system properties are set.");
328 }
329 }
330
331 file = new File(defaultConfigFile);
332 addInfo("Assuming default configuration file [" + defaultConfigFile + "]");
333 if (!file.exists()) return null;
334 return FileUtil.fileToURL(file);
335 }
336
337 private void runJoranOnFile(URL configURL) {
338 try {
339 JoranConfigurator jc = new JoranConfigurator();
340 jc.setContext(this);
341 jc.doConfigure(configURL);
342 if (getName() == null) {
343 setName("LogbackRequestLog");
344 }
345 } catch (JoranException e) {
346
347 }
348 }
349
350 @Override
351 public void stop() {
352 state = State.STOPPING;
353 aai.detachAndStopAllAppenders();
354 state = State.STOPPED;
355 }
356
357 @Override
358 public boolean isRunning() {
359 return state == State.STARTED;
360 }
361
362 public void setFileName(String fileName) {
363 this.fileName = fileName;
364 }
365
366 public void setResource(String resource) {
367 this.resource = resource;
368 }
369
370 @Override
371 public boolean isStarted() {
372 return state == State.STARTED;
373 }
374
375 @Override
376 public boolean isStarting() {
377 return state == State.STARTING;
378 }
379
380 @Override
381 public boolean isStopping() {
382 return state == State.STOPPING;
383 }
384
385 public boolean isStopped() {
386 return state == State.STOPPED;
387 }
388
389 @Override
390 public boolean isFailed() {
391 return state == State.FAILED;
392 }
393
394 @Override
395 public boolean addEventListener(EventListener listener) {
396 return false;
397 }
398
399 @Override
400 public boolean removeEventListener(EventListener listener) {
401 return false;
402 }
403
404
405 public boolean isQuiet() {
406 return quiet;
407 }
408
409 public void setQuiet(boolean quiet) {
410 this.quiet = quiet;
411 }
412
413 @Override
414 public void addAppender(Appender<IAccessEvent> newAppender) {
415 aai.addAppender(newAppender);
416 }
417
418 @Override
419 public Iterator<Appender<IAccessEvent>> iteratorForAppenders() {
420 return aai.iteratorForAppenders();
421 }
422
423 @Override
424 public Appender<IAccessEvent> getAppender(String name) {
425 return aai.getAppender(name);
426 }
427
428 @Override
429 public boolean isAttached(Appender<IAccessEvent> appender) {
430 return aai.isAttached(appender);
431 }
432
433 @Override
434 public void detachAndStopAllAppenders() {
435 aai.detachAndStopAllAppenders();
436 }
437
438 @Override
439 public boolean detachAppender(Appender<IAccessEvent> appender) {
440 return aai.detachAppender(appender);
441 }
442
443 @Override
444 public boolean detachAppender(String name) {
445 return aai.detachAppender(name);
446 }
447
448 @Override
449 public void addFilter(Filter<IAccessEvent> newFilter) {
450 fai.addFilter(newFilter);
451 }
452
453 @Override
454 public void clearAllFilters() {
455 fai.clearAllFilters();
456 }
457
458 @Override
459 public List<Filter<IAccessEvent>> getCopyOfAttachedFiltersList() {
460 return fai.getCopyOfAttachedFiltersList();
461 }
462
463 @Override
464 public FilterReply getFilterChainDecision(IAccessEvent event) {
465 return fai.getFilterChainDecision(event);
466 }
467
468 public void addLifeCycleListener(LifeCycle.Listener listener) {
469
470 }
471
472 public void removeLifeCycleListener(LifeCycle.Listener listener) {
473
474 }
475 }