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

org.glassfish.grizzly.http.server.accesslog.ApacheLogFormat Maven / Gradle / Ivy

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

package org.glassfish.grizzly.http.server.accesslog;

import static java.util.logging.Level.WARNING;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.TimeZone;
import java.util.logging.Logger;

import org.glassfish.grizzly.Grizzly;
import org.glassfish.grizzly.http.Cookie;
import org.glassfish.grizzly.http.Method;
import org.glassfish.grizzly.http.Protocol;
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.grizzly.http.server.Request;
import org.glassfish.grizzly.http.server.Response;
import org.glassfish.grizzly.http.util.MimeHeaders;

/**
 * An {@link AccessLogFormat} using a standard vaguely similar and heavily
 * influenced by Apache's
 * own custom access log formats.
 *
 * 

As with Apache, the format string specified at * {@linkplain #ApacheLogFormat(String) construction} should be composed of * these tokens:

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
%%The literal percent sign (can also be escaped with back-slash, like "\%"
%aRemote IP-address
%ALocal IP-address
%bSize of response in bytes, excluding HTTP headers, using "-" (a dash character) rather than a "0" (zero) when no bytes are sent
%BSize of response in bytes, excluding HTTP headers
%{Foobar}CThe contents of cookie "Foobar" in the request sent to the server
%DThe time taken to serve the request, in microseconds
%hRemote host name
%{local|remote}hHost name, either "local" or "remote"
%HThe request protocol
%{Foobar}iThe contents of the "Foobar: ..." header in the request
%mThe request method
%{Foobar}oThe contents of the "Foobar: ..." header in the response
%pLocal port number
%{local|remote}pThe port number, either "local" or "remote"
%qThe query string, prepended with a "?" (question mark) if a query string exists, otherwise an empty string
%rFirst line of request, an alias to "%m %U%q %H"
%sStatus code
%tThe time the request was received, in standard English format (like "[09/Feb/2014:12:00:34 +0900]")
%{[format][@timezone]}tThe time the request was received. Both format and timezone are optional
*
  • When "format" is left unspecified, the default %t format [yyyy/MMM/dd:HH:mm:ss Z] is used
  • *
  • When "format" is specified, the given pattern must be a valid {@link SimpleDateFormat} pattern.
  • *
  • When "@timezone" is left unspecified, the {@linkplain TimeZone#getDefault() default time zone} is used.
  • *
  • When "@timezone" is specified, the time zone will be looked up by {@linkplain TimeZone#getTimeZone(String) time zone identifier} * (note that this will default to GMT if the specified identifier was not recognized).
  • *
* When the "@" character needs to be used in the format, it must be escaped as "@@"
%TThe time taken to serve the request, in seconds
%{...}TThe time taken to serve the request. The parameter can be a time unit like: *
  • "n", "nano[s]", "nanosec[s]", "nanosecond[s]"
  • *
  • "micro[s]", "microsec[s]", "microsecond[s]"
  • *
  • "m", "milli[s]", "millisec[s]", "millisecond[s]"
  • *
  • "s", "sec[s]", "second[s]"
%uThe remote user name
%UThe URL path requested, not including any query string
%vThe name of the server which served the request
* * @author Pier Fumagalli * @author USRZ.com */ public class ApacheLogFormat implements AccessLogFormat { /* The UTC time zone */ private static final TimeZone UTC = TimeZone.getTimeZone("UTC"); /** A {@link String} representing our version of Apache's common format. */ public static final String COMMON_FORMAT = "%h - %u %t \"%r\" %s %b"; /** A {@link String} representing our version of Apache's combined format. */ public static final String COMBINED_FORMAT = "%h - %u %t \"%r\" %s %b \"%{Referer}i\" \"%{User-agent}i\""; /** A {@link String} representing our version of Apache's common with virtual-hosts format. */ public static final String VHOST_COMMON_FORMAT = "%v %h - %u %t \"%r\" %s %b"; /** A {@link String} representing our version of Apache's combined with virtual-hosts format. */ public static final String VHOST_COMBINED_FORMAT = "%v %h - %u %t \"%r\" %s %b \"%{Referer}i\" \"%{User-agent}i\""; /** A {@link String} representing our version of Apache's referer format. */ public static final String REFERER_FORMAT = "%{Referer}i -> %U"; /** A {@link String} representing our version of Apache's user-agent format. */ public static final String AGENT_FORMAT = "%{User-agent}i"; /** A {@linkplain ApacheLogFormat format} compatible with Apache's common format. */ public static final ApacheLogFormat COMMON = new ApacheLogFormat(COMMON_FORMAT); /** A {@linkplain ApacheLogFormat format} compatible with Apache's combined format. */ public static final ApacheLogFormat COMBINED = new ApacheLogFormat(COMBINED_FORMAT); /** A {@linkplain ApacheLogFormat format} compatible with Apache's common with virtual-hosts format. */ public static final ApacheLogFormat VHOST_COMMON = new ApacheLogFormat(VHOST_COMMON_FORMAT); /** A {@linkplain ApacheLogFormat format} compatible with Apache's combined with virtual-hosts format. */ public static final ApacheLogFormat VHOST_COMBINED = new ApacheLogFormat(VHOST_COMBINED_FORMAT); /** A {@linkplain ApacheLogFormat format} compatible with Apache's referer format. */ public static final ApacheLogFormat REFERER = new ApacheLogFormat(REFERER_FORMAT); /** A {@linkplain ApacheLogFormat format} compatible with Apache's user-agent format. */ public static final ApacheLogFormat AGENT = new ApacheLogFormat(AGENT_FORMAT); /** A {@linkplain ApacheLogFormat format} compatible with Apache's common format set to use the UTC {@linkplain TimeZone time zone}. */ public static final ApacheLogFormat COMMON_UTC = new ApacheLogFormat(UTC, COMMON_FORMAT); /** A {@linkplain ApacheLogFormat format} compatible with Apache's combined format set to use the UTC {@linkplain TimeZone time zone}. */ public static final ApacheLogFormat COMBINED_UTC = new ApacheLogFormat(UTC, COMBINED_FORMAT); /** A {@linkplain ApacheLogFormat format} compatible with Apache's common with virtual-hosts format set to use the UTC {@linkplain TimeZone time zone}. */ public static final ApacheLogFormat VHOST_COMMON_UTC = new ApacheLogFormat(UTC, VHOST_COMMON_FORMAT); /** A {@linkplain ApacheLogFormat format} compatible with Apache's combined with virtual-hosts format set to use the UTC {@linkplain TimeZone time zone}. */ public static final ApacheLogFormat VHOST_COMBINED_UTC = new ApacheLogFormat(UTC, VHOST_COMBINED_FORMAT); /** A {@linkplain ApacheLogFormat format} compatible with Apache's referer format set to use the UTC {@linkplain TimeZone time zone}. */ public static final ApacheLogFormat REFERER_UTC = new ApacheLogFormat(UTC, REFERER_FORMAT); /** A {@linkplain ApacheLogFormat format} compatible with Apache's user-agent format set to use the UTC {@linkplain TimeZone time zone}. */ public static final ApacheLogFormat AGENT_UTC = new ApacheLogFormat(UTC, AGENT_FORMAT); /* Log log log, never enough */ private static final Logger LOGGER = Grizzly.logger(HttpServer.class); /* Our list of fields for formatting */ private final List fields; /* Our timezone */ private final TimeZone timeZone; /** * Create a new {@link ApacheLogFormat} instance by parsing the format * from the specified {@link String}. */ public ApacheLogFormat(String format) { this(TimeZone.getDefault(), format); } /** * Create a new {@link ApacheLogFormat} instance by parsing the format * from the specified {@link String}. */ public ApacheLogFormat(TimeZone timeZone, String format) { if (timeZone == null) throw new NullPointerException("Null time zone"); fields = new ArrayList(); this.timeZone = timeZone; parse(format); } @Override public String format(Response response, Date timeStamp, long responseNanos) { final StringBuilder builder = new StringBuilder(); final Request request = response.getRequest(); for (Field field: fields) try { field.format(builder, request, response, timeStamp, responseNanos); } catch (Exception exception) { LOGGER.log(WARNING, "Exception formatting access log entry", exception); builder.append('-'); } return builder.toString(); } String unsafeFormat(Response response, Date timeStamp, long responseNanos) { final StringBuilder builder = new StringBuilder(); final Request request = response.getRequest(); for (Field field: fields) { field.format(builder, request, response, timeStamp, responseNanos); } return builder.toString(); } /** * Return the normalized format associated with this instance. */ public String getFormat() { final StringBuilder builder = new StringBuilder(); for (Field field: fields) builder.append(field.toString()); return builder.toString(); } /* ====================================================================== */ /* PARSING OF FORMAT STRINGS */ /* ====================================================================== */ private void parse(String format) { for (int x = 0; x < format.length(); x ++) { switch (format.charAt(x)) { case '\\': x = parseEscape(format, x); break; case '%': x = parseFormat(format, null, x); break; default: addLiteral(format.charAt(x)); } } } private int parseFormat(String format, String parameter, int position) { if (++position < format.length()) { final char field = format.charAt(position); /* Initial check to see if parameter is supposed to be there */ if (parameter != null) switch (field) { case 'C': break; // parameter is cookie name case 'h': break; // parameter for host ("local" or "remote") case 'i': break; // parameter is request header name case 'o': break; // parameter is response header name case 'p': break; // parameter for port ("local" or "remote") case 't': break; // parameter is simple date format's format case 'T': break; // parameter is scale ("nano", "micro", "milli" or number) default: throw new IllegalArgumentException("Unsupported parameter \"" + parameter + "\" for field '" + field + "' in [" + format + "] at character " + position); } switch (field) { case '{': return parseParameter(format, position); case '%': addLiteral('%'); break; // The percent sign case 'a': fields.add(new RemoteAddressField()); break; // Remote IP-address case 'A': fields.add(new LocalAddressField()); break; // Local IP-address case 'b': fields.add(new ResponseSizeField(false)); break; // Size of response in bytes in CLF format case 'B': fields.add(new ResponseSizeField(true)); break; // Size of response in bytes with zeroes /* */ case 'C': fields.add(new RequestCookieField(parameter)); break; // The contents of a cookie case 'D': fields.add(new ResponseTimeField("micro", format, position)); break; // The time taken to serve the request, in microseconds. /* */ case 'h': // Remote (or local if parameterized) host fields.add(parseLocal(parameter, false, field, format, position) ? new LocalHostField() : new RemoteHostField()); break; case 'H': fields.add(new RequestProtocolField()); break; // The request protocol /* */ case 'i': fields.add(new RequestHeaderField(parameter)); break; // A request header case 'm': fields.add(new RequestMethodField()); break; // The request method /* */ case 'o': fields.add(new ResponseHeaderField(parameter)); break; // A response header /* */ case 'p': // Local (or remote if parameterized) port fields.add(parseLocal(parameter, true, field, format, position) ? new LocalPortField() : new RemotePortField()); break; case 'q': fields.add(new RequestQueryField()); break; // The query string (prepended with a ?) case 'r': // First line of request, alias to "%m %U%q %H" fields.add(new RequestMethodField()); addLiteral(' '); fields.add(new RequestURIField()); fields.add(new RequestQueryField()); addLiteral(' '); fields.add(new RequestProtocolField()); break; case 's': fields.add(new ResponseStatusField()); break; // Status. /* */ case 't': fields.add(new RequestTimeField(parameter, timeZone)); break; // The time, in the form given by format, which should be in strftime(3) format. (potentially localized) /* */ case 'T': fields.add(new ResponseTimeField(parameter, format, position)); break; // The time taken to serve the request, in the scale specified. case 'u': fields.add(new RequestUserField()); break; // The URL path requested, not including any query string. case 'U': fields.add(new RequestURIField()); break; // The URL path requested, not including any query string. case 'v': fields.add(new ServerNameField()); break; // The canonical ServerName of the server serving the request. default: throw new IllegalArgumentException("Unsupported field '" + field + "' in [" + format + "] at character " + position); } return position; } throw new IllegalArgumentException("Unterminated field declaration in [" + format + "] at character " + position); } private boolean parseLocal(String parameter, boolean defaultValue, char field, String format, int position) { if (parameter == null) return defaultValue; final String p = parameter.trim().toLowerCase(); if (p.equals("local")) { return true; } else if (p.equals("remote")) { return false; } else { throw new IllegalArgumentException("Unsupported parameter \"" + parameter + "\" for field '" + field + "' in [" + format + "] at character " + position); } } private int parseParameter(String format, int position) { if (++position < format.length()) { final int end = format.indexOf('}', position); if (end == position) { return parseFormat(format, null, end); } else if (end > position) { return parseFormat(format, format.substring(position, end), end); } } throw new IllegalArgumentException("Unterminated format parameter in [" + format + "] at character " + position); } private int parseEscape(String format, int position) { if (++position < format.length()) { final char escaped = format.charAt(position); switch (escaped) { case 't': addLiteral('\t'); break; case 'b': addLiteral('\b'); break; case 'n': addLiteral('\n'); break; case 'r': addLiteral('\r'); break; case 'f': addLiteral('\f'); break; default: addLiteral(escaped); } return position; } throw new IllegalArgumentException("Unterminated escape sequence in [" + format + "] at character " + position); } /* ====================================================================== */ private void addLiteral(char c) { /* See if we can add to the previuos literal field */ if (!fields.isEmpty()) { final Field last = fields.get(fields.size() - 1); if (last instanceof LiteralField) { ((LiteralField) last).append(c); return; } } /* List empty or last field was not a literal, add a new one */ fields.add(new LiteralField(c)); } /* ====================================================================== */ /* FIELD DECLARATIONS */ /* ====================================================================== */ private static abstract class Field { abstract StringBuilder format(StringBuilder builder, Request request, Response response, Date timeStamp, long responseNanos); @Override public abstract String toString(); } private static abstract class AbstractField extends Field { private final char format; private final String parameter; protected AbstractField(char format) { this(format, null); } protected AbstractField(char format, String parameter) { this.format = format; this.parameter = parameter; } @Override public final String toString() { final StringBuilder builder = new StringBuilder().append('%'); if (parameter != null) builder.append('{').append(parameter).append('}'); return builder.append(format).toString(); } } /* ====================================================================== */ private abstract static class HeaderField extends AbstractField { final String name; HeaderField(char format, String name) { super(format, name.trim().toLowerCase()); this.name = name.trim().toLowerCase(); } StringBuilder format(StringBuilder builder, MimeHeaders headers) { final Iterator iterator = headers.values(name).iterator(); if (iterator.hasNext()) builder.append(iterator.next()); while (iterator.hasNext()) builder.append("; ").append(iterator.next()); return builder; } } /* ====================================================================== */ private static class LiteralField extends Field { final StringBuilder contents; LiteralField(char character) { contents = new StringBuilder().append(character); } void append(char character) { contents.append(character); } @Override StringBuilder format(StringBuilder builder, Request request, Response response, Date timeStamp, long responseNanos) { return builder.append(contents); } @Override public String toString() { final StringBuilder builder = new StringBuilder(); for (int x = 0; x < contents.length(); x ++) { final char character = contents.charAt(x); /* Escape \t \b \n \r \f and %% */ switch(character) { case 't': case 'b': case 'n': case 'r': case 'f': builder.append('\\'); break; case '%': builder.append('%'); break; } builder.append(character); } return builder.toString(); } } /* ====================================================================== */ private static class ServerNameField extends AbstractField { ServerNameField() { super('v'); } @Override StringBuilder format(StringBuilder builder, Request request, Response response, Date timeStamp, long responseNanos) { final String name = request.getServerName(); return builder.append(name == null ? "-" : name); } } /* ====================================================================== */ private static class LocalHostField extends AbstractField { LocalHostField() { super('h', "local"); } @Override StringBuilder format(StringBuilder builder, Request request, Response response, Date timeStamp, long responseNanos) { final String host = request.getLocalName(); return builder.append(host == null ? "-" : host); } } /* ====================================================================== */ private static class LocalAddressField extends AbstractField { LocalAddressField() { super('A'); } @Override StringBuilder format(StringBuilder builder, Request request, Response response, Date timeStamp, long responseNanos) { final String address = request.getLocalAddr(); return builder.append(address == null ? "-" : address); } } /* ====================================================================== */ private static class LocalPortField extends AbstractField { LocalPortField() { super('p'); } @Override StringBuilder format(StringBuilder builder, Request request, Response response, Date timeStamp, long responseNanos) { final int port = request.getLocalPort(); return builder.append(port < 1 ? "-" : port); } } /* ====================================================================== */ private static class RemoteHostField extends AbstractField { RemoteHostField() { super('h'); } @Override StringBuilder format(StringBuilder builder, Request request, Response response, Date timeStamp, long responseNanos) { final String host = request.getRemoteHost(); return builder.append(host == null ? "-" : host); } } /* ====================================================================== */ private static class RemoteAddressField extends AbstractField { RemoteAddressField() { super('a'); } @Override StringBuilder format(StringBuilder builder, Request request, Response response, Date timeStamp, long responseNanos) { final String address = request.getRemoteAddr(); return builder.append(address == null ? "-" : address); } } /* ====================================================================== */ private static class RemotePortField extends AbstractField { RemotePortField() { super('p', "remote"); } @Override StringBuilder format(StringBuilder builder, Request request, Response response, Date timeStamp, long responseNanos) { final int port = request.getRemotePort(); return builder.append(port < 1 ? "-" : port); } } /* ====================================================================== */ private static class RequestTimeField extends Field { private static final String DEFAULT_PATTERN = "[yyyy/MMM/dd:HH:mm:ss Z]"; private final SimpleDateFormatThreadLocal simpleDateFormat; private final TimeZone timeZone; private final String pattern; private final String format; RequestTimeField(String format, TimeZone zone) { this.format = format; if (format == null) { pattern = DEFAULT_PATTERN; timeZone = zone; } else { /* Check for timezone separation */ final int pos = format.lastIndexOf('@'); if ((pos < 0) || ((pos > 0) && (format.charAt(pos - 1) == '@'))) { /* There is no '@' or the last '@' is actually an '@@' */ pattern = format.replace("@@", "@"); timeZone = zone; } else if (pos == 0) { /* We have *ONLY* a time zone specified */ pattern = DEFAULT_PATTERN; timeZone = TimeZone.getTimeZone(format.substring(1)); } else { /* We have both format and time zone */ pattern = format.substring(0, pos).replace("@@", "@"); timeZone = TimeZone.getTimeZone(format.substring(pos + 1)); } } /* Get our simple date format */ simpleDateFormat = new SimpleDateFormatThreadLocal(pattern); } @Override StringBuilder format(StringBuilder builder, Request request, Response response, Date timeStamp, long responseNanos) { if (timeStamp == null) return builder.append('-'); final SimpleDateFormat format = simpleDateFormat.get(); format.setTimeZone(timeZone); return builder.append(format.format(timeStamp)); } @Override public String toString() { return format == null ? "%t" : "%{" + format + "}t"; } } /* ====================================================================== */ private static class RequestMethodField extends AbstractField { RequestMethodField() { super('m'); } @Override StringBuilder format(StringBuilder builder, Request request, Response response, Date timeStamp, long responseNanos) { final Method method = request.getMethod(); return builder.append(method == null ? "-" : method.toString()); } } /* ====================================================================== */ private static class RequestUserField extends AbstractField { RequestUserField() { super('u'); } @Override StringBuilder format(StringBuilder builder, Request request, Response response, Date timeStamp, long responseNanos) { final String user = request.getRemoteUser(); return builder.append(user == null ? "-" : user); } } /* ====================================================================== */ private static class RequestURIField extends AbstractField { RequestURIField() { super('U'); } @Override StringBuilder format(StringBuilder builder, Request request, Response response, Date timeStamp, long responseNanos) { final String uri = request.getRequestURI(); return builder.append(uri == null ? "-" : uri); } } /* ====================================================================== */ private static class RequestQueryField extends AbstractField { RequestQueryField() { super('q'); } @Override StringBuilder format(StringBuilder builder, Request request, Response response, Date timeStamp, long responseNanos) { final String query = request.getQueryString(); if (query != null) builder.append('?').append(query); return builder; } } /* ====================================================================== */ private static class RequestProtocolField extends AbstractField { RequestProtocolField() { super('H'); } @Override StringBuilder format(StringBuilder builder, Request request, Response response, Date timeStamp, long responseNanos) { final Protocol protocol = request.getProtocol(); if (protocol == null) return builder.append("-"); switch (protocol) { case HTTP_0_9: return builder.append("HTTP/0.9"); case HTTP_1_0: return builder.append("HTTP/1.0"); case HTTP_1_1: return builder.append("HTTP/1.1"); default: return builder.append("-"); } } } /* ====================================================================== */ private static class RequestHeaderField extends HeaderField { RequestHeaderField(String name) { super('i', name); } @Override StringBuilder format(StringBuilder builder, Request request, Response response, Date timeStamp, long responseNanos) { return this.format(builder, request.getRequest().getHeaders()); } } /* ====================================================================== */ private static class RequestCookieField extends AbstractField { final String name; RequestCookieField(String name) { super('C', name.trim().toLowerCase()); this.name = name.trim().toLowerCase(); } @Override StringBuilder format(StringBuilder builder, Request request, Response response, Date timeStamp, long responseNanos) { final Cookie[] cookies = request.getCookies(); if (cookies != null) for (Cookie cookie: cookies) { if (name.equals(cookie.getName().toLowerCase())) { return builder.append(cookie.getValue()); } } return builder; } } /* ====================================================================== */ private static class ResponseStatusField extends AbstractField { ResponseStatusField() { super('s'); } @Override StringBuilder format(StringBuilder builder, Request request, Response response, Date timeStamp, long responseNanos) { final int status = response.getStatus(); if (status < 10) builder.append('0'); if (status < 100) builder.append('0'); return builder.append(status); } } /* ====================================================================== */ private static class ResponseSizeField extends AbstractField { final String zero; ResponseSizeField(boolean zero) { super(zero ? 'B' : 'b'); this.zero = zero ? "0" : "-"; } @Override StringBuilder format(StringBuilder builder, Request request, Response response, Date timeStamp, long responseNanos) { final long size = response.getContentLengthLong(); return builder.append(size < 1 ? zero : Long.toString(size)); } } /* ====================================================================== */ private static class ResponseTimeField extends Field { private final long scale; ResponseTimeField(String unit, String format, int position) { /* Figure out the scale */ if (unit == null) { scale = 1000000000; return; } String s = unit.trim().toLowerCase(); if (s.equals("n") || s.equals("nano") || s.equals( "nanos") || s.equals("nanosec") || s.equals( "nanosecs") || s.equals("nanosecond") || s.equals( "nanoseconds")) { scale = 1; } else if (s.equals("micro") || s.equals("micros") || s.equals( "microsec") || s.equals("microsecs") || s.equals( "microsecond") || s.equals("microseconds")) { scale = 1000; } else if (s.equals("m") || s.equals("milli") || s.equals( "millis") || s.equals("millisec") || s.equals( "millisecs") || s.equals("millisecond") || s.equals( "milliseconds")) { scale = 1000000; } else if (s.equals("s") || s.equals("sec") || s.equals( "secs") || s.equals("second") || s.equals("seconds")) { scale = 1000000000; } else { throw new IllegalArgumentException( "Unsupported time unit \"" + unit + "\" for field 'T' in [" + format + "] at character " + position); } } @Override StringBuilder format(StringBuilder builder, Request request, Response response, Date timeStamp, long responseNanos) { if (responseNanos < 0) return builder.append('-'); return builder.append(responseNanos / scale); } @Override public String toString() { final StringBuilder string = new StringBuilder().append('%'); if (scale == 1) string.append("{n}T"); else if (scale == 1000) string.append('D'); else if (scale == 1000000) string.append("{m}T"); else if (scale == 1000000000) string.append('T'); else string.append('{').append(scale).append("}T"); return string.toString(); } } /* ====================================================================== */ private static class ResponseHeaderField extends HeaderField { ResponseHeaderField(String name) { super('o', name); } @Override StringBuilder format(StringBuilder builder, Request request, Response response, Date timeStamp, long responseNanos) { return this.format(builder, response.getResponse().getHeaders()); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy