-
Notifications
You must be signed in to change notification settings - Fork 17
/
RequestLogger.java
237 lines (209 loc) · 10.8 KB
/
RequestLogger.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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
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
232
233
234
235
236
237
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.sling.engine.impl.log;
import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.metatype.annotations.AttributeDefinition;
import org.osgi.service.metatype.annotations.Designate;
import org.osgi.service.metatype.annotations.ObjectClassDefinition;
import org.osgi.service.metatype.annotations.Option;
/**
* The <code>RequestLogger</code> just registers {@link RequestLoggerService}
* instance on behalf of the provided configuration.
*/
@Component
@Designate(ocd = RequestLogger.Config.class)
public class RequestLogger {
@ObjectClassDefinition(
name = "Apache Sling Request Logger",
description = "Configures the main loggers of the request logger, "
+ "namely the request log and the access log. Further loggers may be configured "
+ "by creating configurations for the Request Logger Service.")
public @interface Config {
@AttributeDefinition(
name = "Request Log Name",
description = "Name of the destination for the request log. "
+ "The request log logs the entry and exit of each request into and "
+ "out of the system together with the entry time, exit time, time to process "
+ "the request, a request counter as well as the final status code and response "
+ "content type. The format can be configured with the Request Log Entry/Exit Format setting.")
String request_log_output() default "logs/request.log";
@AttributeDefinition(
name = "Request Log Type",
description = "Type of request log destination. Select "
+ "\"Logger Name\" to write the access log to an SLF4J logger, \"File Name\" to "
+ "write the access log to a file (relative paths resolved against sling.home) "
+ "or \"RequestLog Service\" to use a named OSGi service registered with the "
+ "service interface \"org.apache.sling.engine.RequestLog\" and a service property "
+ "\"requestlog.name\" equal to the Logger Name setting.",
options = {
@Option(label = "Logger Name", value = "0"),
@Option(label = "File Name", value = "1"),
@Option(label = "RequestLog Service", value = "2")
})
int request_log_outputtype() default 0;
@AttributeDefinition(
name = "Request Log Entry Format",
description = "The format of the request log. This is a format string as defined at "
+ "https://sling.apache.org/site/client-request-logging.html#ClientRequestLogging-LogFormatSpecification. "
+ "The request entry is logged with the format \"%t [%R] -> %m %U%q %H\" by default.")
String request_log_entry_format() default REQUEST_LOG_ENTRY_FORMAT;
@AttributeDefinition(
name = "Request Log Exit Format",
description =
"The format of the request log. This is a format string as defined at "
+ "https://sling.apache.org/site/client-request-logging.html#ClientRequestLogging-LogFormatSpecification. "
+ "The request exit is logged with the format \"%{end}t [%R] <- %s %{Content-Type}o %Dms\" by default.")
String request_log_exit_format() default REQUEST_LOG_EXIT_FORMAT;
@AttributeDefinition(name = "Enable Request Log", description = "Whether to enable Request logging or not.")
boolean request_log_enabled() default true;
@AttributeDefinition(
name = "Access Log Name",
description = "Name of the destination for the request log. "
+ "The access log writes an entry for each request as the request terminates. "
+ "The format of the access log can be configured by the Access Log Format setting.")
String access_log_output() default "logs/access.log";
@AttributeDefinition(
name = "Access Log Type",
description = "Type of access log destination. Select "
+ "\"Logger Name\" to write the access log to an SLF4J logger, \"File Name\" to "
+ "write the access log to a file (relative paths resolved against sling.home) "
+ "or \"RequestLog Service\" to use a named OSGi service registered with the "
+ "service interface \"org.apache.sling.engine.RequestLog\" and a service property "
+ "\"requestlog.name\" equal to the Logger Name setting.",
options = {
@Option(label = "Logger Name", value = "0"),
@Option(label = "File Name", value = "1"),
@Option(label = "RequestLog Service", value = "2")
})
int access_log_outputtype() default 0;
@AttributeDefinition(
name = "Access Log Format",
description = "This is a format string as defined at "
+ "https://sling.apache.org/site/client-request-logging.html#ClientRequestLogging-LogFormatSpecification. "
+ "The default format for the access log is using the NCSA extended/combined log "
+ "format. In terms of Request Logger Service formats the access log is written with the format "
+ "\"%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"\".")
String access_log_format() default ACCESS_LOG_FORMAT;
@AttributeDefinition(name = "Enable Access Log", description = "Whether to enable Access logging or not.")
boolean access_log_enabled() default true;
}
/**
* The log format string for the request log entry message (value is "%t
* [%R] -> %m %U%q %H").
*/
private static final String REQUEST_LOG_ENTRY_FORMAT = "%t [%R] -> %m %U%q %H";
/**
* The log format string for the request log exit message (value is "%{end}t
* [%R] <- %s %{Content-Type}o %Dms").
*/
private static final String REQUEST_LOG_EXIT_FORMAT = "%{end}t [%R] <- %s %{Content-Type}o %Dms";
/**
* The log format for the access log which is exactly the NCSA
* extended/combined log format (value is "%a %l %u %t \"%r\" %>s %b
* \"%{Referer}i\" \"%{User-Agent}i\"").
*/
private static final String ACCESS_LOG_FORMAT = "%a %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"";
/**
* RequestLoggerService instances created on behalf of the static
* configuration.
*/
private Map<ServiceRegistration, RequestLoggerService> services = new HashMap<>();
// ---------- SCR Integration ----------------------------------------------
@Activate
protected void activate(BundleContext bundleContext, Config config) {
// prepare the request loggers if a name is configured and the
// request loggers are enabled
if (config.request_log_output() != null && config.request_log_enabled()) {
createRequestLoggerService(
services,
bundleContext,
true,
config.request_log_entry_format(),
config.request_log_output(),
config.request_log_outputtype());
createRequestLoggerService(
services,
bundleContext,
false,
config.request_log_exit_format(),
config.request_log_output(),
config.request_log_outputtype());
}
// prepare the access logger if a name is configured and the
// access logger is enabled
if (config.access_log_output() != null && config.access_log_enabled()) {
createRequestLoggerService(
services,
bundleContext,
false,
config.access_log_format(),
config.access_log_output(),
config.access_log_outputtype());
}
}
@Deactivate
protected void deactivate() {
for (Entry<ServiceRegistration, RequestLoggerService> entry : services.entrySet()) {
entry.getKey().unregister();
entry.getValue().shutdown();
}
services.clear();
}
private static void createRequestLoggerService(
Map<ServiceRegistration, RequestLoggerService> services,
final BundleContext bundleContext,
final boolean onEntry,
final String format,
final String output,
final int outputType) {
final RequestLoggerService service = new RequestLoggerService(bundleContext, new RequestLoggerService.Config() {
@Override
public Class<? extends Annotation> annotationType() {
return RequestLoggerService.Config.class;
}
@Override
public int request_log_service_outputtype() {
return outputType;
}
@Override
public String request_log_service_output() {
return output;
}
@Override
public boolean request_log_service_onentry() {
return onEntry;
}
@Override
public String request_log_service_format() {
return format;
}
});
final ServiceRegistration reg =
bundleContext.registerService(service.getClass().getName(), service, null);
services.put(reg, service);
}
}