view src/org/eclipse/jetty/server/handler/RequestLogHandler.java @ 925:720a98fb0253

remove scheduleDispatch()
author Franklin Schmidt <fschmidt@gmail.com>
date Sun, 09 Oct 2016 18:29:29 -0600
parents ea1768c00d03
children 23a57aad34c0
line wrap: on
line source

//
//  ========================================================================
//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
//  ------------------------------------------------------------------------
//  All rights reserved. This program and the accompanying materials
//  are made available under the terms of the Eclipse Public License v1.0
//  and Apache License v2.0 which accompanies this distribution.
//
//      The Eclipse Public License is available at
//      http://www.eclipse.org/legal/epl-v10.html
//
//      The Apache License v2.0 is available at
//      http://www.opensource.org/licenses/apache2.0.php
//
//  You may elect to redistribute this code under either of these licenses.
//  ========================================================================
//

package org.eclipse.jetty.server.handler; 

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Locale;
import java.util.TimeZone;

import javax.servlet.DispatcherType;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.eclipse.jetty.continuation.Continuation;
import org.eclipse.jetty.continuation.ContinuationListener;
import org.eclipse.jetty.http.HttpHeaders;
import org.eclipse.jetty.server.AsyncContinuation;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/** 
 * RequestLogHandler.
 * This handler can be used to wrap an individual context for context logging.
 * 
 * @org.apache.xbean.XBean
 */
public class RequestLogHandler extends HandlerWrapper
{
	private static final Logger LOG = LoggerFactory.getLogger(RequestLogHandler.class);
	
	/* ------------------------------------------------------------ */
	/* 
	 * @see org.eclipse.jetty.server.server.Handler#handle(java.lang.String, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, int)
	 */
	@Override
	public void handle(String target, final Request baseRequest, HttpServletRequest request, final HttpServletResponse response)
			throws IOException, ServletException
	{
		AsyncContinuation continuation = baseRequest.getAsyncContinuation();
		if (!continuation.isInitial())
		{
			baseRequest.setDispatchTime(System.currentTimeMillis());
		}
		
		try
		{
			super.handle(target, baseRequest, request, response);
		}
		finally
		{
			if (baseRequest.getDispatcherType().equals(DispatcherType.REQUEST))
			{
				if (continuation.isAsync())
				{
					if (continuation.isInitial())
						continuation.addContinuationListener(new ContinuationListener()
						{

							public void onTimeout(Continuation continuation)
							{

							}

							public void onComplete(Continuation continuation)
							{
								log(baseRequest, (Response)response);
							}
						});
				}
				else
					log(baseRequest, (Response)response);
			}
		}
	}

	/* ------------------------------------------------------------ */

	/* ------------------------------------------------------------ */
	/* 
	 * @see org.eclipse.jetty.server.server.handler.HandlerWrapper#doStart()
	 */
	@Override
	protected void doStart() throws Exception
	{
		super.doStart();
		startLog();
	}

	/* ------------------------------------------------------------ */
	/* 
	 * @see org.eclipse.jetty.server.server.handler.HandlerWrapper#doStop()
	 */
	@Override
	protected void doStop() throws Exception
	{
		super.doStop();
		stopLog();
	}



	// from NCSARequestLog

	public String filename = null;
	private boolean extended = false;
	public long retainTime = 1000L*60*60*24*31;  // 31 days
	private boolean _closeOut;
	public boolean preferProxiedForAddress = false;
	public String logDateFormat = "dd/MMM/yyyy:HH:mm:ss Z";
	public Locale logLocale = Locale.getDefault();
	public TimeZone timeZone = TimeZone.getTimeZone("GMT");
	public boolean logLatency = false;
	public boolean logCookies = false;
	public boolean logServer = false;
	public boolean logDispatch = false;

	private transient OutputStream _out;
	private transient DateFormat dateFormat;
	private transient Writer _writer;

	/* ------------------------------------------------------------ */
	/**
	 * Writes the request and response information to the output stream.
	 * 
	 * @see org.eclipse.jetty.server.RequestLog#log(org.eclipse.jetty.server.Request, org.eclipse.jetty.server.Response)
	 */
	public void log(Request request, Response response)
	{
		try
		{
			if (_out == null)
				return;

			StringBuilder buf = new StringBuilder(256);

			if (logServer)
			{
				buf.append(request.getServerName());
				buf.append(' ');
			}

			String addr = null;
			if (preferProxiedForAddress)
			{
				addr = request.getHeader(HttpHeaders.X_FORWARDED_FOR);
			}

			if (addr == null)
				addr = request.getRemoteAddr();

			buf.append(addr);
			buf.append(" - [");

			synchronized(dateFormat) {
				buf.append(dateFormat.format(request.getTimeStamp()));
			}

			buf.append("] \"");
			buf.append(request.getMethod());
			buf.append(' ');
			buf.append(request.getUri().toString());
			buf.append(' ');
			buf.append(request.getProtocol());
			buf.append("\" ");
			if (request.getAsyncContinuation().isInitial())
			{
				int status = response.getStatus();
				if (status <= 0)
					status = 404;
				buf.append((char)('0' + ((status / 100) % 10)));
				buf.append((char)('0' + ((status / 10) % 10)));
				buf.append((char)('0' + (status % 10)));
			}
			else
				buf.append("Async");

			long responseLength = response.getContentCount();
			if (responseLength >= 0)
			{
				buf.append(' ');
				if (responseLength > 99999)
					buf.append(responseLength);
				else
				{
					if (responseLength > 9999)
						buf.append((char)('0' + ((responseLength / 10000) % 10)));
					if (responseLength > 999)
						buf.append((char)('0' + ((responseLength / 1000) % 10)));
					if (responseLength > 99)
						buf.append((char)('0' + ((responseLength / 100) % 10)));
					if (responseLength > 9)
						buf.append((char)('0' + ((responseLength / 10) % 10)));
					buf.append((char)('0' + (responseLength) % 10));
				}
				buf.append(' ');
			}
			else
				buf.append(" - ");

			
			if (extended)
				logExtended(request, response, buf);

			if (logCookies)
			{
				Cookie[] cookies = request.getCookies();
				if (cookies == null || cookies.length == 0)
					buf.append(" -");
				else
				{
					buf.append(" \"");
					for (int i = 0; i < cookies.length; i++)
					{
						if (i != 0)
							buf.append(';');
						buf.append(cookies[i].getName());
						buf.append('=');
						buf.append(cookies[i].getValue());
					}
					buf.append('\"');
				}
			}

			if (logDispatch || logLatency)
			{
				long now = System.currentTimeMillis();

				if (logDispatch)
				{   
					long d = request.getDispatchTime();
					buf.append(' ');
					buf.append(now - (d==0 ? request.getTimeStamp():d));
				}

				if (logLatency)
				{
					buf.append(' ');
					buf.append(now - request.getTimeStamp());
				}
			}

			buf.append('\n');
			
			String log = buf.toString();
			write(log);
		}
		catch (IOException e)
		{
			LOG.warn("",e);
		}
	}

	/* ------------------------------------------------------------ */
	protected synchronized void write(String log) throws IOException 
	{
		if (_writer==null)
			return;
		_writer.write(log);
		_writer.flush();
	}

	
	/* ------------------------------------------------------------ */
	/**
	 * Writes extended request and response information to the output stream.
	 * 
	 * @param request request object
	 * @param response response object
	 * @param b StringBuilder to write to
	 * @throws IOException
	 */
	protected void logExtended(Request request,
							   Response response,
							   StringBuilder b) throws IOException
	{
		String referer = request.getHeader(HttpHeaders.REFERER);
		if (referer == null)
			b.append("\"-\" ");
		else
		{
			b.append('"');
			b.append(referer);
			b.append("\" ");
		}

		String agent = request.getHeader(HttpHeaders.USER_AGENT);
		if (agent == null)
			b.append("\"-\" ");
		else
		{
			b.append('"');
			b.append(agent);
			b.append('"');
		}
	}

	private synchronized void startLog() throws Exception {
		dateFormat = new SimpleDateFormat(logDateFormat,logLocale);
		dateFormat.setTimeZone(timeZone);

		if (filename != null) {
			File file = new File(filename);
			if( file.exists() ) {
				File old = new File(filename+".old");
				if( old.exists() && file.lastModified() - old.lastModified() > retainTime )
					old.delete();
				if( !old.exists() )
					file.renameTo(old);
			}
			_out = new FileOutputStream(file,true);
			_closeOut = true;
			LOG.info("Opened " + filename);
		}
		else
			_out = System.err;

		_writer = new OutputStreamWriter(_out);
	}

	private synchronized void stopLog() throws Exception {
		try {
			if (_writer != null)
				_writer.flush();
		} catch (IOException e) {
			LOG.trace("",e);
		}
		if (_closeOut) {
			try {
				_out.close();
			} catch (IOException e) {
				LOG.trace("",e);
			}
		}
		_out = null;
		_closeOut = false;
		dateFormat = null;
		_writer = null;
	}
	
}