org.kaazing.gateway.transport.LoggingUtils Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gateway.transport Show documentation
Show all versions of gateway.transport Show documentation
Core abstraction of a transport protocol that is used to communicate with an endpoint
The newest version!
/**
* Copyright 2007-2016, Kaazing Corporation. All rights reserved.
*
* Licensed 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.kaazing.gateway.transport;
import static java.lang.String.format;
import static org.kaazing.gateway.resource.address.ResourceAddress.IDENTITY_RESOLVER;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import javax.security.auth.Subject;
import org.apache.mina.core.service.IoAcceptor;
import org.apache.mina.core.service.IoService;
import org.apache.mina.core.session.IoSession;
import org.kaazing.gateway.resource.address.IdentityResolver;
import org.kaazing.gateway.resource.address.ResourceAddress;
import org.kaazing.mina.core.session.IoSessionEx;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public final class LoggingUtils {
// message used in all IOExceptions when connectivity is lost - moved here to have a unique message that can be used also in tests
public static final String NETWORK_CONNECTIVITY_ERROR_MESSAGE = "Network connectivity has been lost or transport was closed at other end";
public static final String EARLY_TERMINATION_OF_IOSESSION_MESSAGE = "Early termination of IO session";
private static final String HOST_PORT_FORMAT = "%s:%d";
private static final TypedAttributeKey LOG_ID_ATTRIBUTE
= new TypedAttributeKey<>(LoggingUtils.class, "logId");
private LoggingUtils() {
// so as not to be instantiated
}
/**
* Prepends short session details (result of getId) for the session in square brackets to the message.
* @param message the message to be logged
* @param session an instance of IoSessionEx
* @return example: "[wsn#34 127.0.0.0.1:41234] this is the log message"
*/
public static String addSession(String message, IoSession session) {
return format("[%s] %s", getId(session), message);
}
/**
* Gets the identifying attributes of a session as a short string useful for logging purposes.
* Example return values: wsn#34 127.0.0.0.1:41234, wsn#34 joe 127.0.0.0.1:41234
* @param session
* @return a short string including the numerical session ID, transport name and user or host and port details
*/
public static String getId(IoSession session) {
String result = LOG_ID_ATTRIBUTE.get(session);
if (result == null) {
result = session.getTransportMetadata().getName() + "#" + session.getId();
String user = LoggingUtils.getUserIdentifier(session);
if (user != null) {
result = result + " " + user;
}
LOG_ID_ATTRIBUTE.set(session, result);
}
return result;
}
/**
* Logs an unexpected exception in the same way LoggingFilter would, using the transport
* logger for the transport of the given session.
*/
public static void log(IoSession session, Throwable t) {
Logger logger = getTransportLogger(session);
log(session, logger, t);
}
/**
* Logs an unexpected exception in the same way LoggingFilter would.
*/
public static void log(IoSession session, Logger logger, Throwable t) {
log(session, logger, t.toString(), t);
}
/**
* Logs an unexpected exception in the same way LoggingFilter would.
* IOExceptions are treated specially because they are frequent and expected: they
* are logged only if info level is enabled.
*/
public static void log(IoSession session, Logger logger, String message, Throwable t) {
boolean isIOException = t instanceof IOException;
if (isIOException && !logger.isInfoEnabled()) {
return;
}
if (logger.isWarnEnabled()) {
String finalMessage = t.getCause() == null ? message : message + ", caused by " + t.getCause();
finalMessage = addSession(finalMessage, session);
if (isIOException) {
logIOException(finalMessage, logger, t);
}
else if (logger.isInfoEnabled()) {
logger.warn(finalMessage, t);
}
else {
logger.warn(finalMessage);
}
}
}
/**
* IOExceptions ("Network connectivity has been lost or transport was closed at other end")
* can be frequent due to network timeouts (inactivity timeout) or loss of network connectivity
* so we only print info level and include a stack trace of the cause, if there is one.
*/
private static void logIOException(String message, Logger logger, Throwable t) {
Throwable cause = t.getCause();
if (cause != null) {
logger.info(message, cause);
} else {
logger.info(message);
}
}
/**
* Get a suitable identification for the user. For now this just consists of the TCP endpoint.
* the HTTP-layer auth principal, etc.
* @param session
* @return
*/
static String getUserIdentifier(IoSession session) {
boolean isAcceptor = isAcceptor(session);
SocketAddress hostPortAddress = isAcceptor ? session.getRemoteAddress() : session.getLocalAddress();
SocketAddress identityAddress = isAcceptor ? session.getLocalAddress() : session.getRemoteAddress();
String identity = resolveIdentity(identityAddress, (IoSessionEx)session);
String hostPort = getHostPort(hostPortAddress);
return identity == null ? hostPort : format("%s %s", identity, hostPort);
}
private static boolean isAcceptor(IoSession session) {
IoService service = session.getService();
return service instanceof IoAcceptor || service instanceof BridgeAcceptor;
}
/**
* Method performing identity resolution - attempts to extract a subject from the current
* IoSessionEx session
* @param address
* @param session
* @return
*/
private static String resolveIdentity(SocketAddress address, IoSessionEx session) {
if (address instanceof ResourceAddress) {
Subject subject = session.getSubject();
if (subject == null) {
subject = new Subject();
}
return resolveIdentity((ResourceAddress) address, subject);
}
return null;
}
/**
* Method attempting to perform identity resolution based on the provided subject parameter and transport
* It is attempted to perform the resolution from the highest to the lowest layer, recursively.
* @param address
* @param subject
* @return
*/
private static String resolveIdentity(ResourceAddress address, Subject subject) {
IdentityResolver resolver = address.getOption(IDENTITY_RESOLVER);
ResourceAddress transport = address.getTransport();
if (resolver != null) {
return resolver.resolve(subject);
}
if (transport != null) {
return resolveIdentity(transport, subject);
}
return null;
}
/**
* Method attempting to retrieve host port identifier
* @param address
* @return
*/
private static String getHostPort(SocketAddress address) {
if (address instanceof ResourceAddress) {
ResourceAddress lowest = getLowestTransportLayer((ResourceAddress)address);
return format(HOST_PORT_FORMAT, lowest.getResource().getHost(), lowest.getResource().getPort());
}
if (address instanceof InetSocketAddress) {
InetSocketAddress inet = (InetSocketAddress)address;
// we don't use inet.toString() because it would include a leading /, for example "/127.0.0.1:21345"
// use getHostString() to avoid a reverse DNS lookup
return format(HOST_PORT_FORMAT, inet.getHostString(), inet.getPort());
}
return null;
}
/**
* Method returning lowest transport layer
* @param transport
* @return
*/
static ResourceAddress getLowestTransportLayer(ResourceAddress transport) {
if (transport.getTransport() != null) {
return getLowestTransportLayer(transport.getTransport());
}
return transport;
}
private static Logger getTransportLogger(IoSession session) {
String loggerName = "transport." + session.getService().getTransportMetadata().getName()
+ (isAcceptor(session) ? ".accept" : ".connect");
return LoggerFactory.getLogger(loggerName);
}
}