All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.wicket.protocol.http.RequestLogger Maven / Gradle / Ivy

Go to download

Pax Wicket Service is an OSGi extension of the Wicket framework, allowing for dynamic loading and unloading of Wicket components and pageSources.

There is a newer version: 5.0.0
Show newest version
/*
 * 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.wicket.protocol.http;

import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.wicket.Application;
import org.apache.wicket.IClusterable;
import org.apache.wicket.IPageMap;
import org.apache.wicket.IRequestTarget;
import org.apache.wicket.MetaDataKey;
import org.apache.wicket.Page;
import org.apache.wicket.RequestCycle;
import org.apache.wicket.Session;
import org.apache.wicket.request.target.component.IBookmarkablePageRequestTarget;
import org.apache.wicket.request.target.component.IPageRequestTarget;
import org.apache.wicket.request.target.component.listener.IListenerInterfaceRequestTarget;
import org.apache.wicket.request.target.resource.ISharedResourceRequestTarget;
import org.apache.wicket.util.lang.Classes;
import org.apache.wicket.util.string.AppendingStringBuffer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * This is the logger class that can be set in the
 * {@link org.apache.wicket.protocol.http.WebApplication#getRequestLogger()} method. If this class
 * is set all request and live sessions will be recorded and displayed From the total created
 * sessions, to the peak session count and the current livesessions. For the livesessions the
 * request logger will record what request are happening what kind of {@link IRequestTarget} was the
 * event target and what {@link IRequestTarget} was the response target. It also records what
 * session data was touched for this and how long the request did take.
 * 
 * To view this information live see the {@link InspectorBug} that shows the {@link InspectorPage}
 * with the {@link LiveSessionsPage}
 * 
 * @author jcompagner
 * 
 * @since 1.2
 */
public class RequestLogger implements IRequestLogger
{
	/** log. */
	protected static Logger log = LoggerFactory.getLogger(RequestLogger.class);


	private static MetaDataKey REQUEST_DATA = new MetaDataKey()
	{
		private static final long serialVersionUID = 1L;
	};

	/**
	 * This interface can be implemented in a custom session object. to give an object that has more
	 * information for the current session (state of session).
	 * 
	 * @author jcompagner
	 */
	public interface ISessionLogInfo
	{

		/**
		 * If you use the request logger log functionality then this object should have a nice
		 * String representation. So make sure that the toString() is implemented for the returned
		 * object.
		 * 
		 * @return The custom object stored in the request loggers current request.
		 */
		Object getSessionInfo();
	}


	private final AtomicInteger totalCreatedSessions = new AtomicInteger();

	private final AtomicInteger peakSessions = new AtomicInteger();

	private final List requests;

	private final Map liveSessions;

	private final AtomicInteger active = new AtomicInteger();

	private final AtomicInteger peakActive = new AtomicInteger();

	/**
	 * Construct.
	 */
	public RequestLogger()
	{
		requests = Collections.synchronizedList(new LinkedList()
		{
			private static final long serialVersionUID = 1L;

			/**
			 * @see java.util.LinkedList#add(java.lang.Object)
			 */
			@Override
			public void add(int index, RequestData o)
			{
				super.add(index, o);
				if (size() > Application.get().getRequestLoggerSettings().getRequestsWindowSize())
				{
					removeLast();
				}
			}
		});
		liveSessions = new ConcurrentHashMap();
	}

	/**
	 * @see org.apache.wicket.protocol.http.IRequestLogger#getTotalCreatedSessions()
	 */
	public int getTotalCreatedSessions()
	{
		return totalCreatedSessions.get();
	}

	/**
	 * @see org.apache.wicket.protocol.http.IRequestLogger#getPeakSessions()
	 */
	public int getPeakSessions()
	{
		return peakSessions.get();
	}

	/**
	 * @see org.apache.wicket.protocol.http.IRequestLogger#getCurrentActiveRequestCount()
	 */
	public int getCurrentActiveRequestCount()
	{
		return active.get();
	}

	/**
	 * @see org.apache.wicket.protocol.http.IRequestLogger#getPeakActiveRequestCount()
	 */
	public int getPeakActiveRequestCount()
	{
		return peakActive.get();
	}

	/**
	 * @see org.apache.wicket.protocol.http.IRequestLogger#getRequests()
	 */
	public List getRequests()
	{
		return Collections.unmodifiableList(requests);
	}

	public SessionData[] getLiveSessions()
	{
		SessionData[] sessions = liveSessions.values().toArray(
			new SessionData[liveSessions.values().size()]);
		Arrays.sort(sessions);
		return sessions;
	}

	/**
	 * @see org.apache.wicket.protocol.http.IRequestLogger#sessionDestroyed(java.lang.String)
	 */
	public void sessionDestroyed(String sessionId)
	{
		liveSessions.remove(sessionId);
	}

	/**
	 * @see org.apache.wicket.protocol.http.IRequestLogger#sessionDestroyed(java.lang.String)
	 */
	public void sessionCreated(String sessionId)
	{
		liveSessions.put(sessionId, new SessionData(sessionId));
		if (liveSessions.size() > peakSessions.get())
		{
			peakSessions.set(liveSessions.size());
		}
		totalCreatedSessions.incrementAndGet();
	}

	RequestData getCurrentRequest()
	{
		RequestCycle requestCycle = RequestCycle.get();
		RequestData rd = requestCycle.getMetaData(REQUEST_DATA);
		if (rd == null)
		{
			rd = new RequestData();
			requestCycle.setMetaData(REQUEST_DATA, rd);
			int activeCount = active.incrementAndGet();

			if (activeCount > peakActive.get())
			{
				peakActive.set(activeCount);
			}
		}
		return rd;
	}

	/**
	 * @see org.apache.wicket.protocol.http.IRequestLogger#requestTime(long)
	 */
	public void requestTime(long timeTaken)
	{
		RequestData rd = RequestCycle.get().getMetaData(REQUEST_DATA);
		if (rd != null)
		{
			if (active.get() > 0)
			{
				rd.setActiveRequest(active.decrementAndGet());
			}
			Session session = Session.get();
			String sessionId = session.getId();
			rd.setSessionId(sessionId);

			Object sessionInfo = getSessionInfo(session);
			rd.setSessionInfo(sessionInfo);

			long sizeInBytes = -1;
			if (Application.get().getRequestLoggerSettings().getRecordSessionSize())
			{
				try
				{
					sizeInBytes = session.getSizeInBytes();
				}
				catch (Exception e)
				{
					// log the error and let the request logging continue (this is what happens in
					// the
					// detach phase of the request cycle anyway. This provides better diagnostics).
					log.error(
						"Exception while determining the size of the session in the request logger: " +
							e.getMessage(), e);
				}
			}
			rd.setSessionSize(sizeInBytes);
			rd.setTimeTaken(timeTaken);

			requests.add(0, rd);
			if (sessionId != null)
			{
				SessionData sd = liveSessions.get(sessionId);
				if (sd == null && session.isSessionInvalidated() == false)
				{
					// passivated session or logger only started after it.
					sessionCreated(sessionId);
					sd = liveSessions.get(sessionId);
				}
				if (sd != null)
				{
					sd.setSessionInfo(sessionInfo);
					sd.setSessionSize(sizeInBytes);
					sd.addTimeTaken(timeTaken);
					log(rd, sd);
				}
				else
				{
					log(rd, null);
				}
			}
			else
			{
				log(rd, null);
			}
		}
	}

	/**
	 * @param rd
	 * @param sd
	 */
	protected void log(RequestData rd, SessionData sd)
	{
		if (log.isInfoEnabled())
		{
			log.info(createLogString(rd, sd, true).toString());
		}
	}

	protected AppendingStringBuffer createLogString(RequestData rd, SessionData sd,
		boolean includeRuntimeInfo)
	{
		AppendingStringBuffer asb = new AppendingStringBuffer(150);
		asb.append("time=");
		asb.append(rd.getTimeTaken());
		asb.append(",event=");
		asb.append(rd.getEventTarget());
		asb.append(",response=");
		asb.append(rd.getResponseTarget());
		if (rd.getSessionInfo() != null && !rd.getSessionInfo().equals(""))
		{
			asb.append(",sessioninfo=");
			asb.append(rd.getSessionInfo());
		}
		else
		{
			asb.append(",sessionid=");
			asb.append(rd.getSessionId());
		}
		asb.append(",sessionsize=");
		asb.append(rd.getSessionSize());
		if (sd != null)
		{
			asb.append(",sessionstart=");
			asb.append(sd.getStartDate());
			asb.append(",requests=");
			asb.append(sd.getNumberOfRequests());
			asb.append(",totaltime=");
			asb.append(sd.getTotalTimeTaken());
		}
		asb.append(",activerequests=");
		asb.append(rd.getActiveRequest());
		if (includeRuntimeInfo)
		{
			Runtime runtime = Runtime.getRuntime();
			long max = runtime.maxMemory() / 1000000;
			long total = runtime.totalMemory() / 1000000;
			long used = total - runtime.freeMemory() / 1000000;
			asb.append(",maxmem=");
			asb.append(max);
			asb.append("M,total=");
			asb.append(total);
			asb.append("M,used=");
			asb.append(used);
			asb.append("M");
		}
		return asb;
	}

	private Object getSessionInfo(Session session)
	{
		if (session instanceof ISessionLogInfo)
		{
			return ((ISessionLogInfo)session).getSessionInfo();
		}
		return "";
	}

	/**
	 * @see org.apache.wicket.protocol.http.IRequestLogger#objectRemoved(java.lang.Object)
	 */
	public void objectRemoved(Object value)
	{
		RequestData rd = getCurrentRequest();
		if (value instanceof Page)
		{
			Page page = (Page)value;
			rd.addEntry("Page removed, id: " + page.getId() + ", class:" + page.getClass());
		}
		else if (value instanceof IPageMap)
		{
			IPageMap map = (IPageMap)value;
			rd.addEntry("PageMap removed, name: " +
				(map.getName() == null ? "DEFAULT" : map.getName()));
		}
		else if (value instanceof WebSession)
		{
			rd.addEntry("Session removed");
		}
		else
		{
			rd.addEntry("Custom object removed: " + value);
		}
	}

	/**
	 * @see org.apache.wicket.protocol.http.IRequestLogger#objectUpdated(java.lang.Object)
	 */
	public void objectUpdated(Object value)
	{
		RequestData rd = getCurrentRequest();
		if (value instanceof Page)
		{
			Page page = (Page)value;
			rd.addEntry("Page updated, id: " + page.getId() + ", class:" + page.getClass());
		}
		else if (value instanceof IPageMap)
		{
			IPageMap map = (IPageMap)value;
			rd.addEntry("PageMap updated, name: " +
				(map.getName() == null ? "DEFAULT" : map.getName()));
		}
		else if (value instanceof Session)
		{
			rd.addEntry("Session updated");
		}
		else
		{
			rd.addEntry("Custom object updated: " + value);
		}
	}

	/**
	 * @see org.apache.wicket.protocol.http.IRequestLogger#objectCreated(java.lang.Object)
	 */
	public void objectCreated(Object value)
	{
		RequestData rd = getCurrentRequest();

		if (value instanceof Session)
		{
			rd.addEntry("Session created");
		}
		else if (value instanceof Page)
		{
			Page page = (Page)value;
			rd.addEntry("Page created, id: " + page.getId() + ", class:" + page.getClass());
		}
		else if (value instanceof IPageMap)
		{
			IPageMap map = (IPageMap)value;
			rd.addEntry("PageMap created, name: " +
				(map.getName() == null ? "DEFAULT" : map.getName()));
		}
		else
		{
			rd.addEntry("Custom object created: " + value);
		}

	}

	/**
	 * @see org.apache.wicket.protocol.http.IRequestLogger#logResponseTarget(org.apache.wicket.IRequestTarget)
	 */
	public void logResponseTarget(IRequestTarget target)
	{
		getCurrentRequest().addResponseTarget(getRequestTargetString(target));
	}

	/**
	 * @see org.apache.wicket.protocol.http.IRequestLogger#logEventTarget(org.apache.wicket.IRequestTarget)
	 */
	public void logEventTarget(IRequestTarget target)
	{
		getCurrentRequest().addEventTarget(getRequestTargetString(target));
	}


	/**
	 * @param target
	 * @return The request target nice display string
	 */
	private String getRequestTargetString(IRequestTarget target)
	{
		AppendingStringBuffer sb = new AppendingStringBuffer(128);
		if (target instanceof IListenerInterfaceRequestTarget)
		{
			IListenerInterfaceRequestTarget listener = (IListenerInterfaceRequestTarget)target;
			sb.append("Interface[target:");
			sb.append(Classes.simpleName(listener.getTarget().getClass()));
			sb.append("(");
			sb.append(listener.getTarget().getPageRelativePath());
			sb.append("), page: ");
			sb.append(listener.getPage().getClass().getName());
			sb.append("(");
			sb.append(listener.getPage().getId());
			sb.append("), interface: ");
			sb.append(listener.getRequestListenerInterface().getName());
			sb.append(".");
			sb.append(listener.getRequestListenerInterface().getMethod().getName());
			sb.append("]");
		}
		else if (target instanceof IPageRequestTarget)
		{
			IPageRequestTarget pageRequestTarget = (IPageRequestTarget)target;
			sb.append("PageRequest[");
			sb.append(pageRequestTarget.getPage().getClass().getName());
			sb.append("(");
			sb.append(pageRequestTarget.getPage().getId());
			sb.append(")]");
		}
		else if (target instanceof IBookmarkablePageRequestTarget)
		{
			IBookmarkablePageRequestTarget pageRequestTarget = (IBookmarkablePageRequestTarget)target;
			sb.append("BookmarkablePage[");
			sb.append(pageRequestTarget.getPageClass().getName());
			sb.append("(").append(pageRequestTarget.getPageParameters()).append(")");
			sb.append("]");
		}
		else if (target instanceof ISharedResourceRequestTarget)
		{
			ISharedResourceRequestTarget sharedResourceTarget = (ISharedResourceRequestTarget)target;
			sb.append("SharedResource[");
			sb.append(sharedResourceTarget.getResourceKey());
			sb.append("]");
		}
		else
		{
			sb.append(target.toString());
		}
		return sb.toString();
	}

	/**
	 * This class hold the information one request of a session has.
	 * 
	 * @author jcompagner
	 */
	public static class SessionData implements IClusterable, Comparable
	{
		private static final long serialVersionUID = 1L;

		private final String sessionId;
		private final long startDate;
		private long lastActive;
		private long numberOfRequests;
		private long totalTimeTaken;
		private long sessionSize;
		private Object sessionInfo;

		/**
		 * Construct.
		 * 
		 * @param sessionId
		 */
		public SessionData(String sessionId)
		{
			this.sessionId = sessionId;
			startDate = System.currentTimeMillis();
			numberOfRequests = 1;
		}

		/**
		 * @return The last active date.
		 */
		public Date getLastActive()
		{
			return new Date(lastActive);
		}

		/**
		 * @return The start date of this session
		 */
		public Date getStartDate()
		{
			return new Date(startDate);
		}

		/**
		 * @return The number of request for this session
		 */
		public long getNumberOfRequests()
		{
			return numberOfRequests;
		}

		/**
		 * @return Returns the session size.
		 */
		public long getSessionSize()
		{
			return sessionSize;
		}

		/**
		 * @return Returns the total time this session has spent.
		 */
		public long getTotalTimeTaken()
		{
			return totalTimeTaken;
		}

		/**
		 * @return The session info object given by the {@link ISessionLogInfo#getSessionInfo()}
		 *         session method.
		 */
		public Object getSessionInfo()
		{
			return sessionInfo;
		}

		/**
		 * @return The session id
		 */
		public String getSessionId()
		{
			return sessionId;
		}

		public void addTimeTaken(long time)
		{
			lastActive = System.currentTimeMillis();
			numberOfRequests++;
			totalTimeTaken += time;
		}

		public void setSessionInfo(Object sessionInfo)
		{
			this.sessionInfo = sessionInfo;
		}

		public void setSessionSize(long size)
		{
			sessionSize = size;
		}

		public int compareTo(SessionData sd)
		{
			return (int)(sd.lastActive - lastActive);
		}

	}


}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy