001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.wicket.protocol.http;
018
019import org.apache.wicket.request.ILoggableRequestHandler;
020import org.apache.wicket.request.IRequestHandler;
021import org.apache.wicket.util.lang.Classes;
022import org.apache.wicket.util.string.Strings;
023import org.slf4j.Logger;
024import org.slf4j.LoggerFactory;
025
026/**
027 * This is the logger class that can be set in the
028 * {@link org.apache.wicket.protocol.http.WebApplication#getRequestLogger()} method. If this class
029 * is set all request and live sessions will be recorded and displayed From the total created
030 * sessions, to the peak session count and the current live sessions. For the live sessions the
031 * request logger will record what request are happening what kind of {@link IRequestHandler} was
032 * the event target and what {@link IRequestHandler} was the response target. It also records what
033 * session data was touched for this and how long the request did take.
034 * 
035 * To view this information live see org.apache.wicket.devutils.inspector.InspectorBug that shows
036 * the org.apache.wicket.devutils.inspector.InspectorPage with the org.apache.wicket.devutils.inspector.LiveSessionsPage.
037 * 
038 * This implementation uses a rounded buffer for storing the request data, and strives to minimize
039 * contention on accessing the rounded buffer. At the beginning of your application start, the
040 * buffer is empty and fills up during the lifetime of the application until the window size has
041 * been reached, and new requests are written to the position containing the oldest request.
042 * 
043 * @since 1.2
044 */
045public class RequestLogger extends AbstractRequestLogger
046{
047        /** log, don't change this as it is often used to direct request logging to a different file. */
048        private static final Logger LOG = LoggerFactory.getLogger(RequestLogger.class);
049
050        @Override
051        protected void log(RequestData rd, SessionData sd)
052        {
053                if (LOG.isInfoEnabled())
054                {
055                        LOG.info(createRequestData(rd, sd));
056                }
057        }
058
059        private String createRequestData(RequestData rd, SessionData sd)
060        {
061                StringBuilder sb = new StringBuilder(768);
062
063                sb.append("startTime=\"");
064                sb.append(formatDate(rd.getStartDate()));
065                sb.append("\",duration=");
066                sb.append(rd.getTimeTaken());
067                sb.append(",url=\"");
068                sb.append(rd.getRequestedUrl());
069                sb.append('"');
070                sb.append(",event={");
071                appendRequestHandlerString(sb, rd.getEventTarget());
072                sb.append("},response={");
073                appendRequestHandlerString(sb, rd.getResponseTarget());
074                sb.append("},sessionid=\"");
075                sb.append(rd.getSessionId());
076                sb.append('"');
077                sb.append(",sessionsize=");
078                sb.append(rd.getSessionSize());
079                if (rd.getSessionInfo() != null && !Strings.isEmpty(rd.getSessionInfo().toString()))
080                {
081                        sb.append(",sessioninfo={");
082                        sb.append(rd.getSessionInfo());
083                        sb.append('}');
084                }
085                if (sd != null)
086                {
087                        sb.append(",sessionstart=\"");
088                        sb.append(formatDate(sd.getStartDate()));
089                        sb.append("\",requests=");
090                        sb.append(sd.getNumberOfRequests());
091                        sb.append(",totaltime=");
092                        sb.append(sd.getTotalTimeTaken());
093                }
094                sb.append(",activerequests=");
095                sb.append(rd.getActiveRequest());
096
097                Runtime runtime = Runtime.getRuntime();
098                long max = runtime.maxMemory() / 1000000;
099                long total = runtime.totalMemory() / 1000000;
100                long used = total - runtime.freeMemory() / 1000000;
101                sb.append(",maxmem=");
102                sb.append(max);
103                sb.append("M,total=");
104                sb.append(total);
105                sb.append("M,used=");
106                sb.append(used);
107                sb.append('M');
108
109                return sb.toString();
110        }
111
112        private void appendRequestHandlerString(StringBuilder sb, IRequestHandler handler)
113        {
114                if (handler != null)
115                {
116                        Class<? extends IRequestHandler> handlerClass = handler.getClass();
117                        sb.append("handler=");
118                        sb.append(handlerClass.isAnonymousClass() ? handlerClass.getName()
119                                        : Classes.simpleName(handlerClass));
120                        if (handler instanceof ILoggableRequestHandler)
121                        {
122                                sb.append(",data=");
123                                sb.append(((ILoggableRequestHandler)handler).getLogData());
124                        }
125                }
126                else
127                {
128                        sb.append("none");
129                }
130        }
131}