org.jboss.netty.handler.logging.LoggingHandler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of netty Show documentation
Show all versions of netty Show documentation
The Netty project is an effort to provide an asynchronous event-driven
network application framework and tools for rapid development of
maintainable high performance and high scalability protocol servers and
clients. In other words, Netty is a NIO client server framework which
enables quick and easy development of network applications such as protocol
servers and clients. It greatly simplifies and streamlines network
programming such as TCP and UDP socket server.
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you 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.jboss.netty.handler.logging;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.channel.ChannelDownstreamHandler;
import org.jboss.netty.channel.ChannelEvent;
import org.jboss.netty.channel.ChannelHandler;
import org.jboss.netty.channel.ChannelHandler.Sharable;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelUpstreamHandler;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.logging.InternalLogLevel;
import org.jboss.netty.logging.InternalLogger;
import org.jboss.netty.logging.InternalLoggerFactory;
/**
* A {@link ChannelHandler} that logs all events via {@link InternalLogger}.
* By default, all events are logged at DEBUG level. You can extend
* this class and override {@link #log(ChannelEvent)} to change the default
* behavior.
* @apiviz.landmark
*/
@Sharable
public class LoggingHandler implements ChannelUpstreamHandler, ChannelDownstreamHandler {
private static final InternalLogLevel DEFAULT_LEVEL = InternalLogLevel.DEBUG;
private static final String NEWLINE = String.format("%n");
private static final String[] BYTE2HEX = new String[256];
private static final String[] HEXPADDING = new String[16];
private static final String[] BYTEPADDING = new String[16];
private static final char[] BYTE2CHAR = new char[256];
static {
int i;
// Generate the lookup table for byte-to-hex-dump conversion
for (i = 0; i < 10; i ++) {
StringBuilder buf = new StringBuilder(3);
buf.append(" 0");
buf.append(i);
BYTE2HEX[i] = buf.toString();
}
for (; i < 16; i ++) {
StringBuilder buf = new StringBuilder(3);
buf.append(" 0");
buf.append((char) ('a' + i - 10));
BYTE2HEX[i] = buf.toString();
}
for (; i < BYTE2HEX.length; i ++) {
StringBuilder buf = new StringBuilder(3);
buf.append(' ');
buf.append(Integer.toHexString(i));
BYTE2HEX[i] = buf.toString();
}
// Generate the lookup table for hex dump paddings
for (i = 0; i < HEXPADDING.length; i ++) {
int padding = HEXPADDING.length - i;
StringBuilder buf = new StringBuilder(padding * 3);
for (int j = 0; j < padding; j ++) {
buf.append(" ");
}
HEXPADDING[i] = buf.toString();
}
// Generate the lookup table for byte dump paddings
for (i = 0; i < BYTEPADDING.length; i ++) {
int padding = BYTEPADDING.length - i;
StringBuilder buf = new StringBuilder(padding);
for (int j = 0; j < padding; j ++) {
buf.append(' ');
}
BYTEPADDING[i] = buf.toString();
}
// Generate the lookup table for byte-to-char conversion
for (i = 0; i < BYTE2CHAR.length; i ++) {
if (i <= 0x1f || i >= 0x7f) {
BYTE2CHAR[i] = '.';
} else {
BYTE2CHAR[i] = (char) i;
}
}
}
private final InternalLogger logger;
private final InternalLogLevel level;
private final boolean hexDump;
/**
* Creates a new instance whose logger name is the fully qualified class
* name of the instance with hex dump enabled.
*/
public LoggingHandler() {
this(true);
}
/**
* Creates a new instance whose logger name is the fully qualified class
* name of the instance.
*
* @param level the log level
*/
public LoggingHandler(InternalLogLevel level) {
this(level, true);
}
/**
* Creates a new instance whose logger name is the fully qualified class
* name of the instance.
*
* @param hexDump {@code true} if and only if the hex dump of the received
* message is logged
*/
public LoggingHandler(boolean hexDump) {
this(DEFAULT_LEVEL, hexDump);
}
/**
* Creates a new instance whose logger name is the fully qualified class
* name of the instance.
*
* @param level the log level
* @param hexDump {@code true} if and only if the hex dump of the received
* message is logged
*/
public LoggingHandler(InternalLogLevel level, boolean hexDump) {
if (level == null) {
throw new NullPointerException("level");
}
logger = InternalLoggerFactory.getInstance(getClass());
this.level = level;
this.hexDump = hexDump;
}
/**
* Creates a new instance with the specified logger name and with hex dump
* enabled.
*/
public LoggingHandler(Class> clazz) {
this(clazz, true);
}
/**
* Creates a new instance with the specified logger name.
*
* @param hexDump {@code true} if and only if the hex dump of the received
* message is logged
*/
public LoggingHandler(Class> clazz, boolean hexDump) {
this(clazz, DEFAULT_LEVEL, hexDump);
}
/**
* Creates a new instance with the specified logger name.
*
* @param level the log level
*/
public LoggingHandler(Class> clazz, InternalLogLevel level) {
this(clazz, level, true);
}
/**
* Creates a new instance with the specified logger name.
*
* @param level the log level
* @param hexDump {@code true} if and only if the hex dump of the received
* message is logged
*/
public LoggingHandler(Class> clazz, InternalLogLevel level, boolean hexDump) {
if (clazz == null) {
throw new NullPointerException("clazz");
}
if (level == null) {
throw new NullPointerException("level");
}
logger = InternalLoggerFactory.getInstance(clazz);
this.level = level;
this.hexDump = hexDump;
}
/**
* Creates a new instance with the specified logger name and with hex dump
* enabled.
*/
public LoggingHandler(String name) {
this(name, true);
}
/**
* Creates a new instance with the specified logger name.
*
* @param hexDump {@code true} if and only if the hex dump of the received
* message is logged
*/
public LoggingHandler(String name, boolean hexDump) {
this(name, DEFAULT_LEVEL, hexDump);
}
/**
* Creates a new instance with the specified logger name.
*
* @param level the log level
* @param hexDump {@code true} if and only if the hex dump of the received
* message is logged
*/
public LoggingHandler(String name, InternalLogLevel level, boolean hexDump) {
if (name == null) {
throw new NullPointerException("name");
}
if (level == null) {
throw new NullPointerException("level");
}
logger = InternalLoggerFactory.getInstance(name);
this.level = level;
this.hexDump = hexDump;
}
/**
* Returns the {@link InternalLogger} that this handler uses to log
* a {@link ChannelEvent}.
*/
public InternalLogger getLogger() {
return logger;
}
/**
* Returns the {@link InternalLogLevel} that this handler uses to log
* a {@link ChannelEvent}.
*/
public InternalLogLevel getLevel() {
return level;
}
/**
* Logs the specified event to the {@link InternalLogger} returned by
* {@link #getLogger()}. If hex dump has been enabled for this handler,
* the hex dump of the {@link ChannelBuffer} in a {@link MessageEvent} will
* be logged together.
*/
public void log(ChannelEvent e) {
if (getLogger().isEnabled(level)) {
String msg = e.toString();
// Append hex dump if necessary.
if (hexDump && e instanceof MessageEvent) {
MessageEvent me = (MessageEvent) e;
if (me.getMessage() instanceof ChannelBuffer) {
msg += formatBuffer((ChannelBuffer) me.getMessage());
}
}
// Log the message (and exception if available.)
if (e instanceof ExceptionEvent) {
getLogger().log(level, msg, ((ExceptionEvent) e).getCause());
} else {
getLogger().log(level, msg);
}
}
}
private static String formatBuffer(ChannelBuffer buf) {
int length = buf.readableBytes();
int rows = length / 16 + (length % 15 == 0? 0 : 1) + 4;
StringBuilder dump = new StringBuilder(rows * 80);
dump.append(
NEWLINE + " +-------------------------------------------------+" +
NEWLINE + " | 0 1 2 3 4 5 6 7 8 9 a b c d e f |" +
NEWLINE + "+--------+-------------------------------------------------+----------------+");
final int startIndex = buf.readerIndex();
final int endIndex = buf.writerIndex();
int i;
for (i = startIndex; i < endIndex; i ++) {
int relIdx = i - startIndex;
int relIdxMod16 = relIdx & 15;
if (relIdxMod16 == 0) {
dump.append(NEWLINE);
dump.append(Long.toHexString(relIdx & 0xFFFFFFFFL | 0x100000000L));
dump.setCharAt(dump.length() - 9, '|');
dump.append('|');
}
dump.append(BYTE2HEX[buf.getUnsignedByte(i)]);
if (relIdxMod16 == 15) {
dump.append(" |");
for (int j = i - 15; j <= i; j ++) {
dump.append(BYTE2CHAR[buf.getUnsignedByte(j)]);
}
dump.append('|');
}
}
if ((i - startIndex & 15) != 0) {
int remainder = length & 15;
dump.append(HEXPADDING[remainder]);
dump.append(" |");
for (int j = i - remainder; j < i; j ++) {
dump.append(BYTE2CHAR[buf.getUnsignedByte(j)]);
}
dump.append(BYTEPADDING[remainder]);
dump.append('|');
}
dump.append(
NEWLINE + "+--------+-------------------------------------------------+----------------+");
return dump.toString();
}
public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e)
throws Exception {
log(e);
ctx.sendUpstream(e);
}
public void handleDownstream(ChannelHandlerContext ctx, ChannelEvent e)
throws Exception {
log(e);
ctx.sendDownstream(e);
}
}