Line data Source code
1 : // Copyright (C) 2010 The Android Open Source Project
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : package com.google.gerrit.pgm.http.jetty;
16 :
17 : import static com.google.gerrit.httpd.GitOverHttpServlet.GIT_COMMAND_STATUS_HEADER;
18 :
19 : import com.google.common.base.Strings;
20 : import com.google.gerrit.httpd.GetUserFilter;
21 : import com.google.gerrit.httpd.RequestMetricsFilter;
22 : import com.google.gerrit.httpd.restapi.LogRedactUtil;
23 : import com.google.gerrit.server.config.GerritServerConfig;
24 : import com.google.gerrit.server.util.SystemLog;
25 : import com.google.gerrit.server.util.time.TimeUtil;
26 : import com.google.inject.Inject;
27 : import org.apache.log4j.AsyncAppender;
28 : import org.apache.log4j.Level;
29 : import org.apache.log4j.Logger;
30 : import org.apache.log4j.spi.LoggingEvent;
31 : import org.eclipse.jetty.server.Request;
32 : import org.eclipse.jetty.server.RequestLog;
33 : import org.eclipse.jetty.server.Response;
34 : import org.eclipse.jetty.util.component.AbstractLifeCycle;
35 : import org.eclipse.jgit.lib.Config;
36 :
37 : /** Writes the {@code httpd_log} file with per-request data. */
38 : class HttpLog extends AbstractLifeCycle implements RequestLog {
39 15 : private static final Logger log = Logger.getLogger(HttpLog.class);
40 : private static final String LOG_NAME = "httpd_log";
41 : private static final String JSON_SUFFIX = ".json";
42 :
43 : interface HttpLogFactory {
44 : HttpLog get();
45 : }
46 :
47 : protected static final String P_HOST = "Host";
48 : protected static final String P_USER = "User";
49 : protected static final String P_METHOD = "Method";
50 : protected static final String P_RESOURCE = "Resource";
51 : protected static final String P_PROTOCOL = "Version";
52 : protected static final String P_STATUS = "Status";
53 : protected static final String P_CONTENT_LENGTH = "Content-Length";
54 : protected static final String P_LATENCY = "Latency";
55 : protected static final String P_REFERER = "Referer";
56 : protected static final String P_USER_AGENT = "User-Agent";
57 : protected static final String P_CPU_TOTAL = "Cpu-Total";
58 : protected static final String P_CPU_USER = "Cpu-User";
59 : protected static final String P_MEMORY = "Memory";
60 : protected static final String P_COMMAND_STATUS = "Command-Status";
61 :
62 : private final AsyncAppender async;
63 :
64 : @Inject
65 15 : HttpLog(SystemLog systemLog, @GerritServerConfig Config config) {
66 15 : boolean json = config.getBoolean("log", "jsonLogging", false);
67 15 : boolean text = config.getBoolean("log", "textLogging", true) || !json;
68 :
69 15 : async = new AsyncAppender();
70 :
71 15 : if (text) {
72 15 : async.addAppender(systemLog.createAsyncAppender(LOG_NAME, new HttpLogLayout()));
73 : }
74 :
75 15 : if (json) {
76 0 : async.addAppender(
77 0 : systemLog.createAsyncAppender(LOG_NAME + JSON_SUFFIX, new HttpLogJsonLayout()));
78 : }
79 15 : }
80 :
81 : @Override
82 15 : protected void doStart() throws Exception {}
83 :
84 : @Override
85 : protected void doStop() throws Exception {
86 15 : async.close();
87 15 : }
88 :
89 : @Override
90 : public void log(Request req, Response rsp) {
91 6 : final LoggingEvent event =
92 : new LoggingEvent( //
93 6 : Logger.class.getName(), // fqnOfCategoryClass
94 : log, // logger
95 6 : TimeUtil.nowMs(), // when
96 : Level.INFO, // level
97 : "", // message text
98 6 : Thread.currentThread().getName(), // thread name
99 : null, // exception information
100 : null, // current NDC string
101 : null, // caller location
102 : null // MDC properties
103 : );
104 :
105 6 : String uri = req.getRequestURI();
106 6 : if (!Strings.isNullOrEmpty(req.getQueryString())) {
107 3 : uri += "?" + LogRedactUtil.redactQueryString(req.getQueryString());
108 : }
109 6 : String user = (String) req.getAttribute(GetUserFilter.USER_ATTR_KEY);
110 6 : if (user != null) {
111 5 : event.setProperty(P_USER, user);
112 : }
113 :
114 6 : set(event, P_HOST, req.getRemoteAddr());
115 6 : set(event, P_METHOD, req.getMethod());
116 6 : set(event, P_RESOURCE, uri);
117 6 : set(event, P_PROTOCOL, req.getProtocol());
118 6 : set(event, P_STATUS, rsp.getStatus());
119 6 : set(event, P_CONTENT_LENGTH, rsp.getContentCount());
120 6 : set(event, P_LATENCY, System.currentTimeMillis() - req.getTimeStamp());
121 6 : set(event, P_REFERER, req.getHeader("Referer"));
122 6 : set(event, P_USER_AGENT, req.getHeader("User-Agent"));
123 6 : set(event, P_COMMAND_STATUS, rsp.getHeader(GIT_COMMAND_STATUS_HEADER));
124 :
125 6 : RequestMetricsFilter.Context ctx =
126 6 : (RequestMetricsFilter.Context) req.getAttribute(RequestMetricsFilter.METRICS_CONTEXT);
127 6 : if (ctx != null) {
128 6 : set(event, P_CPU_TOTAL, ctx.getTotalCpuTime());
129 6 : set(event, P_CPU_USER, ctx.getUserCpuTime());
130 6 : set(event, P_MEMORY, ctx.getAllocatedMemory());
131 : }
132 :
133 6 : async.append(event);
134 6 : }
135 :
136 : private static void set(LoggingEvent event, String key, String val) {
137 6 : if (val != null && !val.isEmpty()) {
138 6 : event.setProperty(key, val);
139 : }
140 6 : }
141 :
142 : private static void set(LoggingEvent event, String key, long val) {
143 6 : if (0 < val) {
144 6 : event.setProperty(key, String.valueOf(val));
145 : }
146 6 : }
147 : }
|