
org.glassfish.grizzly.http.server.accesslog.AccessLogBuilder Maven / Gradle / Ivy
/* * Copyright (c) 2014, 2020 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at * http://www.eclipse.org/legal/epl-2.0. * * This Source Code may also be made available under the following Secondary * Licenses when the conditions for such availability set forth in the * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, * version 2 with the GNU Classpath Exception, which is available at * https://www.gnu.org/software/classpath/license.html. * * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 */ package org.glassfish.grizzly.http.server.accesslog; import java.io.File; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.TimeZone; import org.glassfish.grizzly.http.server.HttpServer; import org.glassfish.grizzly.http.server.HttpServerMonitoringConfig; import org.glassfish.grizzly.http.server.ServerConfiguration; /** * A simple builder to configure access logging for Grizzly. * *
specified here is* If the {@linkplain #format(AccessLogFormat) format} is left unspecified, the default * {@linkplain ApacheLogFormat#COMBINED Apache combined format} will be used. *
* ** If the {@linkplain #timeZone(TimeZone) time zone} is left unspecified, the {@link TimeZone#getDefault() default time * zone} will be used. *
* * @author Pier Fumagalli * @author USRZ.com */ public class AccessLogBuilder { /* Our default access log format (Apache "combined" log) */ private AccessLogFormat format = ApacheLogFormat.COMBINED; /* The default status threshold (log everything) */ private int statusThreshold = AccessLogProbe.DEFAULT_STATUS_THRESHOLD; /* Null rotation pattern, do NOT rotate by default */ private String rotationPattern; /* Non-synchronous, always use a Queue+Thread */ private boolean synchronous; /* The base file name of the access log */ private final File file; /** * Create a new {@link AccessLogBuilder} writing logs to the specified file. * * @param file The location of the access log file. */ public AccessLogBuilder(String file) { if (file == null) { throw new NullPointerException("Null file"); } this.file = new File(file).getAbsoluteFile(); } /** * Create a new {@link AccessLogBuilder} writing logs to the specified file. * * @param file The location of the access log file. */ public AccessLogBuilder(File file) { if (file == null) { throw new NullPointerException("Null file"); } this.file = file; } /** * Build an {@link AccessLogProbe} instance which can be injected into an {@link HttpServer}'s * {@linkplain HttpServerMonitoringConfig monitoring configuration} to provide access logging. */ public AccessLogProbe build() { /* Build an appender, plain or rotating */ AccessLogAppender appender; try { if (rotationPattern == null) { appender = new FileAppender(file.getCanonicalFile()); } else { /* Get directory and base file name (encode ' single quotes) */ final File directory = file.getCanonicalFile().getParentFile(); final String name = file.getName(); /* Split "name.ext" name in "name" + ".ext" */ final String base; final String extension; final int position = name.lastIndexOf("."); if (position < 0) { base = name.replace("'", "''"); extension = ""; } else { base = name.substring(0, position).replace("'", "''"); extension = name.substring(position).replace("'", "''"); } /* Build a simple date format pattern like "'name-'pattern'.ext'" */ final String archive = new StringBuilder().append('\'').append(base).append("'-").append(rotationPattern).append('\'').append(extension) .append('\'').toString(); /* Create our appender */ appender = new RotatingFileAppender(directory, name, archive); } } catch (IOException exception) { throw new IllegalStateException("I/O error creating access log", exception); } /* Wrap the synch in a queue in a-synchronous */ if (!synchronous) { appender = new QueueingAppender(appender); } /* Create and return our probe */ return new AccessLogProbe(appender, format, statusThreshold); } /** * Build an {@link AccessLogProbe} instance and directly instrument it in an {@link HttpServer}'s * {@linkplain HttpServerMonitoringConfig monitoring configuration} to provide access logging. * * @param serverConfiguration The {@link ServerConfiguration} to instrument. */ public ServerConfiguration instrument(ServerConfiguration serverConfiguration) { serverConfiguration.getMonitoringConfig().getWebServerConfig().addProbes(build()); return serverConfiguration; } /** * Set the {@link AccessLogFormat} instance that will be used by the access logs configured by this instance. */ public AccessLogBuilder format(AccessLogFormat format) { if (format == null) { throw new NullPointerException("Null format"); } this.format = format; return this; } /** * Set the format as a {@link String} compatible with the default {@linkplain ApacheLogFormat Apache access log * format} that will be used by the access logs configured by this instance. */ public AccessLogBuilder format(String format) { if (format == null) { throw new NullPointerException("Null format"); } return this.format(new ApacheLogFormat(format)); } /** * Set the time zone that will be used to represent dates. */ public AccessLogBuilder timeZone(TimeZone timeZone) { if (timeZone == null) { throw new NullPointerException("Null time zone"); } if (format instanceof ApacheLogFormat) { final ApacheLogFormat apacheFormat = (ApacheLogFormat) format; format = new ApacheLogFormat(timeZone, apacheFormat.getFormat()); return this; } throw new IllegalStateException("TimeZone can not be set for " + format.getClass().getName()); } /** * Set the time zone that will be used to represent dates. * ** The time zone will be looked up by {@linkplain TimeZone#getTimeZone(String) time zone identifier}, and if this is * invalid or unrecognized, it will default to GMT. *
*/ public AccessLogBuilder timeZone(String timeZone) { if (timeZone == null) { throw new NullPointerException("Null time zone"); } return this.timeZone(TimeZone.getTimeZone(timeZone)); } /** * Set the minimum response status that will trigger an entry in an access log configured by this instance. * ** For example a threshold of
*/ public AccessLogBuilder statusThreshold(int statusThreshold) { this.statusThreshold = statusThreshold; return this; } /** * Set up automatic log-file rotation, on a hourly basis. * *500
will only generate log entries for requests that terminated in error. ** For example, if the file name specified at {@linkplain #AccessLogBuilder(File) construction} was *
*/ public AccessLogBuilder rotatedHourly() { return rotationPattern("yyyyMMDDhh"); } /** * Set up automatic log-file rotation, on a daily basis. * *access.log
, files will be archived on a hourly basis with names likeaccess-yyyyMMDDhh.log
. ** For example, if the file name specified at {@linkplain #AccessLogBuilder(File) construction} was *
*/ public AccessLogBuilder rotatedDaily() { return rotationPattern("yyyyMMDD"); } /** * Set up automatic log-file rotation based on a specified {@link SimpleDateFormat} pattern. * *access.log
, files will be archived on a daily basis with names likeaccess-yyyyMMDD.log
. ** For example, if the file name specified at {@linkplain #AccessLogBuilder(File) construction} was *
access.log
and the rotation patternEEE
(day name in * week), files will be archived on a daily basis with names likeaccess-Mon.log
, *access-Tue.log
, ... * */ public AccessLogBuilder rotationPattern(String rotationPattern) { if (rotationPattern == null) { throw new NullPointerException("Null rotation pattern"); } this.rotationPattern = rotationPattern; return this; } /** * Specify whether access log entries should be writtensynchronously or not. * * * If false (the default) a {@link QueueingAppender} will be used to enqueue entries and append to the final * appenders when possible. *
*/ public AccessLogBuilder synchronous(boolean synchronous) { this.synchronous = synchronous; return this; } }