org.testifyproject.glassfish.jersey.logging.LoggingFeature Maven / Gradle / Ivy
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2016-2017 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 org.testifyproject.testifyprojectpliance with the License. You can
* obtain a copy of the License at
* https://oss.oracle.org.testifyproject.testifyproject/licenses/CDDL+GPL-1.1
* or 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 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.testifyproject.glassfish.org.testifyproject.logging;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ws.rs.RuntimeType;
import javax.ws.rs.core.Feature;
import javax.ws.rs.core.FeatureContext;
import org.testifyproject.glassfish.org.testifyproject.CommonProperties;
/**
* This feature enables logging request and/or response on client-side and/or server-side depending
* on the context's {@link RuntimeType}.
*
* The feature may be register programmatically like other features by calling any of {@link javax.ws.rs.core.Configurable}
* {@code register(...)} method, i.e. {@link javax.ws.rs.core.Configurable#register(Class)} or by setting any of the
* configuration property listed bellow.
*
* Common configurable properties applies for both client and server and are following:
*
* - {@link #LOGGING_FEATURE_LOGGER_NAME}
* - {@link #LOGGING_FEATURE_LOGGER_LEVEL}
* - {@link #LOGGING_FEATURE_VERBOSITY}
* - {@link #LOGGING_FEATURE_MAX_ENTITY_SIZE}
*
*
* If any of the configuration value is not set, following default values are applied:
*
* - logger name: {@code org.testifyproject.glassfish.org.testifyproject.logging.LoggingFeature}
* - logger level: {@link Level#FINE}
* - verbosity: {@link Verbosity#PAYLOAD_TEXT}
* - maximum entity size: {@value #DEFAULT_MAX_ENTITY_SIZE}
*
*
* Server configurable properties:
*
* - {@link #LOGGING_FEATURE_LOGGER_NAME_SERVER}
* - {@link #LOGGING_FEATURE_LOGGER_LEVEL_SERVER}
* - {@link #LOGGING_FEATURE_VERBOSITY_SERVER}
* - {@link #LOGGING_FEATURE_MAX_ENTITY_SIZE_SERVER}
*
* Client configurable properties:
*
* - {@link #LOGGING_FEATURE_LOGGER_NAME_CLIENT}
* - {@link #LOGGING_FEATURE_LOGGER_LEVEL_CLIENT}
* - {@link #LOGGING_FEATURE_VERBOSITY_CLIENT}
* - {@link #LOGGING_FEATURE_MAX_ENTITY_SIZE_CLIENT}
*
*
* @author Ondrej Kosatka (ondrej.kosatka at oracle.org.testifyproject.testifyproject)
* @since 2.23
*/
public class LoggingFeature implements Feature {
/**
* Default logger name to log request and response messages.
*/
public static final String DEFAULT_LOGGER_NAME = LoggingFeature.class.getName();
/**
* Default logger level which will be used for logging request and response messages.
*/
public static final String DEFAULT_LOGGER_LEVEL = Level.FINE.getName();
/**
* Default maximum entity bytes to be logged.
*/
public static final int DEFAULT_MAX_ENTITY_SIZE = 8 * 1024;
/**
* Default verbosity for entity logging. See {@link Verbosity}.
*/
public static final Verbosity DEFAULT_VERBOSITY = Verbosity.PAYLOAD_TEXT;
private static final String LOGGER_NAME_POSTFIX = ".logger.name";
private static final String LOGGER_LEVEL_POSTFIX = ".logger.level";
private static final String VERBOSITY_POSTFIX = ".verbosity";
private static final String MAX_ENTITY_POSTFIX = ".entity.maxSize";
private static final String LOGGING_FEATURE_COMMON_PREFIX = "org.testifyproject.config.logging";
/**
* Common logger name property.
*/
public static final String LOGGING_FEATURE_LOGGER_NAME = LOGGING_FEATURE_COMMON_PREFIX + LOGGER_NAME_POSTFIX;
/**
* Common logger level property.
*/
public static final String LOGGING_FEATURE_LOGGER_LEVEL = LOGGING_FEATURE_COMMON_PREFIX + LOGGER_LEVEL_POSTFIX;
/**
* Common property for configuring a verbosity of entity.
*/
public static final String LOGGING_FEATURE_VERBOSITY = LOGGING_FEATURE_COMMON_PREFIX + VERBOSITY_POSTFIX;
/**
* Common property for configuring a maximum number of bytes of entity to be logged.
*/
public static final String LOGGING_FEATURE_MAX_ENTITY_SIZE = LOGGING_FEATURE_COMMON_PREFIX + MAX_ENTITY_POSTFIX;
private static final String LOGGING_FEATURE_SERVER_PREFIX = "org.testifyproject.config.server.logging";
/**
* Server logger name property.
*/
public static final String LOGGING_FEATURE_LOGGER_NAME_SERVER = LOGGING_FEATURE_SERVER_PREFIX + LOGGER_NAME_POSTFIX;
/**
* Server logger level property.
*/
public static final String LOGGING_FEATURE_LOGGER_LEVEL_SERVER = LOGGING_FEATURE_SERVER_PREFIX + LOGGER_LEVEL_POSTFIX;
/**
* Server property for configuring a verbosity of entity.
*/
public static final String LOGGING_FEATURE_VERBOSITY_SERVER = LOGGING_FEATURE_SERVER_PREFIX + VERBOSITY_POSTFIX;
/**
* Server property for configuring a maximum number of bytes of entity to be logged.
*/
public static final String LOGGING_FEATURE_MAX_ENTITY_SIZE_SERVER = LOGGING_FEATURE_SERVER_PREFIX + MAX_ENTITY_POSTFIX;
private static final String LOGGING_FEATURE_CLIENT_PREFIX = "org.testifyproject.config.client.logging";
/**
* Client logger name property.
*/
public static final String LOGGING_FEATURE_LOGGER_NAME_CLIENT = LOGGING_FEATURE_CLIENT_PREFIX + LOGGER_NAME_POSTFIX;
/**
* Client logger level property.
*/
public static final String LOGGING_FEATURE_LOGGER_LEVEL_CLIENT = LOGGING_FEATURE_CLIENT_PREFIX + LOGGER_LEVEL_POSTFIX;
/**
* Client property for configuring a verbosity of entity.
*/
public static final String LOGGING_FEATURE_VERBOSITY_CLIENT = LOGGING_FEATURE_CLIENT_PREFIX + VERBOSITY_POSTFIX;
/**
* Client property for configuring a maximum number of bytes of entity to be logged.
*/
public static final String LOGGING_FEATURE_MAX_ENTITY_SIZE_CLIENT = LOGGING_FEATURE_CLIENT_PREFIX + MAX_ENTITY_POSTFIX;
private final Logger filterLogger;
private final Verbosity verbosity;
private final Integer maxEntitySize;
private final Level level;
/**
* Creates the feature with default values.
*/
public LoggingFeature() {
this(null, null, null, null);
}
/**
* Creates the feature with custom logger.
*
* @param logger the logger to log requests and responses.
*/
public LoggingFeature(Logger logger) {
this(logger, null, null, null);
}
/**
* Creates the feature with custom logger and verbosity.
*
* @param logger the logger to log requests and responses.
* @param verbosity verbosity of logged messages. See {@link Verbosity}.
*/
public LoggingFeature(Logger logger, Verbosity verbosity) {
this(logger, null, verbosity, null);
}
/**
* Creates the feature with custom logger and maximum number of bytes of entity to log.
*
* @param logger the logger to log requests and responses.
* @param maxEntitySize maximum number of entity bytes to be logged (and buffered) - if the entity is larger,
* logging filter will print (and buffer in memory) only the specified number of bytes
* and print "...more..." string at the end. Negative values are interpreted as zero.
*/
public LoggingFeature(Logger logger, Integer maxEntitySize) {
this(logger, null, DEFAULT_VERBOSITY, maxEntitySize);
}
/**
* Creates the feature with custom logger, it's level, message verbosity and maximum number of bytes of entity to log.
*
* @param logger the logger to log requests and responses.
* @param level level on which the messages will be logged.
* @param verbosity verbosity of logged messages. See {@link Verbosity}.
* @param maxEntitySize maximum number of entity bytes to be logged (and buffered) - if the entity is larger,
* logging filter will print (and buffer in memory) only the specified number of bytes
* and print "...more..." string at the end. Negative values are interpreted as zero.
*/
public LoggingFeature(Logger logger, Level level, Verbosity verbosity, Integer maxEntitySize) {
this.filterLogger = logger;
this.level = level;
this.verbosity = verbosity;
this.maxEntitySize = maxEntitySize;
}
@Override
public boolean configure(FeatureContext context) {
boolean enabled = false;
if (context.getConfiguration().getRuntimeType() == RuntimeType.CLIENT) {
ClientLoggingFilter clientLoggingFilter = (ClientLoggingFilter) createLoggingFilter(context, RuntimeType.CLIENT);
context.register(clientLoggingFilter);
enabled = true;
}
if (context.getConfiguration().getRuntimeType() == RuntimeType.SERVER) {
ServerLoggingFilter serverClientFilter = (ServerLoggingFilter) createLoggingFilter(context, RuntimeType.SERVER);
context.register(serverClientFilter);
enabled = true;
}
return enabled;
}
private LoggingInterceptor createLoggingFilter(FeatureContext context, RuntimeType runtimeType) {
Map properties = context.getConfiguration().getProperties();
String filterLoggerName = CommonProperties.getValue(
properties,
runtimeType == RuntimeType.SERVER ? LOGGING_FEATURE_LOGGER_NAME_SERVER : LOGGING_FEATURE_LOGGER_NAME_CLIENT,
CommonProperties.getValue(
properties,
LOGGING_FEATURE_LOGGER_NAME,
DEFAULT_LOGGER_NAME
));
String filterLevel = CommonProperties.getValue(
properties,
runtimeType == RuntimeType.SERVER ? LOGGING_FEATURE_LOGGER_LEVEL_SERVER : LOGGING_FEATURE_LOGGER_LEVEL_CLIENT,
CommonProperties.getValue(
context.getConfiguration().getProperties(),
LOGGING_FEATURE_LOGGER_LEVEL,
DEFAULT_LOGGER_LEVEL));
Verbosity filterVerbosity = CommonProperties.getValue(
properties,
runtimeType == RuntimeType.SERVER ? LOGGING_FEATURE_VERBOSITY_SERVER : LOGGING_FEATURE_VERBOSITY_CLIENT,
CommonProperties.getValue(
properties,
LOGGING_FEATURE_VERBOSITY,
DEFAULT_VERBOSITY
));
int filterMaxEntitySize = CommonProperties.getValue(
properties,
runtimeType == RuntimeType.SERVER ? LOGGING_FEATURE_MAX_ENTITY_SIZE_SERVER
: LOGGING_FEATURE_MAX_ENTITY_SIZE_CLIENT,
CommonProperties.getValue(
properties,
LOGGING_FEATURE_MAX_ENTITY_SIZE,
DEFAULT_MAX_ENTITY_SIZE
));
Level loggerLevel = Level.parse(filterLevel);
if (runtimeType == RuntimeType.SERVER) {
return new ServerLoggingFilter(filterLogger != null ? filterLogger : Logger.getLogger(filterLoggerName),
level != null ? level : loggerLevel,
verbosity != null ? verbosity : filterVerbosity,
maxEntitySize != null ? maxEntitySize : filterMaxEntitySize);
} else {
return new ClientLoggingFilter(filterLogger != null ? filterLogger : Logger.getLogger(filterLoggerName),
level != null ? level : loggerLevel,
verbosity != null ? verbosity : filterVerbosity,
maxEntitySize != null ? maxEntitySize : filterMaxEntitySize);
}
}
/**
* {@code Verbosity} determines how detailed message will be logged.
*
*
* - The lowest verbosity ({@link #HEADERS_ONLY}) will log only request/response headers.
* -
* The medium verbosity will log request/response headers, as well as an entity if considered a readable text. See {@link
* #PAYLOAD_TEXT}.
*
* - The highest verbosity will log all types of an entity (besides the request/response headers.
*
*
* Note that the entity is logged up to the maximum number specified in any of the following constructors {@link
* LoggingFeature#LoggingFeature(Logger, Integer)}, {@link LoggingFeature#LoggingFeature(Logger, Level, Verbosity, Integer)}
* or by some of the feature's properties (see {@link #LOGGING_FEATURE_MAX_ENTITY_SIZE}, {@link
* #LOGGING_FEATURE_MAX_ENTITY_SIZE_CLIENT}, {@link #LOGGING_FEATURE_MAX_ENTITY_SIZE_SERVER}.
*/
public enum Verbosity {
/**
* Only content of HTTP headers is logged. No message payload data are logged.
*/
HEADERS_ONLY,
/**
* Content of HTTP headers as well as entity content of textual media types is logged. Following is the list of media
* types that are considered textual for the logging purposes:
*
* - {@code text/*}
* - {@code application/atom+xml}
* - {@code application/json}
* - {@code application/svg+xml}
* - {@code application/x-www-form-urlencoded}
* - {@code application/xhtml+xml}
* - {@code application/xml}
*
*/
PAYLOAD_TEXT,
/**
* Full verbose logging. Content of HTTP headers as well as any message payload content will be logged.
*/
PAYLOAD_ANY
}
}