概述
前言:
在最开始我们创建HelloServer的示例中,我们为ServerBootStrap指定了LoggingHandler,当时的代码是这样写的
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
// 指定处理channel
.channel(NioServerSocketChannel.class)
// 设置属性值
.option(ChannelOption.SO_BACKLOG, 100)
// 指定server处理Handler
.handler(new LoggingHandler(LogLevel.INFO))
...
这个Handler有什么作用呢?我们是如何使用到这个Handler的呢。这篇文章就来详细介绍下LoggingHandler
1.io.netty.handler.logging.LoggingHandler构造
public class LoggingHandler extends ChannelDuplexHandler {
// 默认日志级别为DEBUG
private static final LogLevel DEFAULT_LEVEL = LogLevel.DEBUG;
// 这里做了一个日志适配器,兼容各种日志模板
protected final InternalLogger logger;
// 貌似跟LogLevel是一样的
protected final InternalLogLevel internalLevel;
// 指定日志级别
private final LogLevel level;
// 暂时不知道作用,后面我们通过代码来看
private final ByteBufFormat byteBufFormat;
}
LoggingHandler继承了ChannelDuplexHandler,那么无论是inbound事件还是outbound事件都会经过LoggingHandler。
1.1 构造方法
// 默认debug级别展示
public LoggingHandler() {
this(DEFAULT_LEVEL);
}
public LoggingHandler(LogLevel level) {
this(level, ByteBufFormat.HEX_DUMP);
}
// 最终在这里设置各种参数
public LoggingHandler(LogLevel level, ByteBufFormat byteBufFormat) {
this.level = ObjectUtil.checkNotNull(level, "level");
this.byteBufFormat = ObjectUtil.checkNotNull(byteBufFormat, "byteBufFormat");
logger = InternalLoggerFactory.getInstance(getClass());
internalLevel = level.toInternalLevel();
}
/**
* Creates a new instance with the specified logger name and with hex dump
* enabled.
*
* @param clazz the class type to generate the logger for
*/
public LoggingHandler(Class<?> clazz) {
this(clazz, DEFAULT_LEVEL);
}
public LoggingHandler(Class<?> clazz, LogLevel level) {
this(clazz, level, ByteBufFormat.HEX_DUMP);
}
// 与上面不带class的LoggingHandler区别就是logger对象的创建
public LoggingHandler(Class<?> clazz, LogLevel level, ByteBufFormat byteBufFormat) {
ObjectUtil.checkNotNull(clazz, "clazz");
this.level = ObjectUtil.checkNotNull(level, "level");
this.byteBufFormat = ObjectUtil.checkNotNull(byteBufFormat, "byteBufFormat");
logger = InternalLoggerFactory.getInstance(clazz);
internalLevel = level.toInternalLevel();
}
public LoggingHandler(String name) {
this(name, DEFAULT_LEVEL);
}
public LoggingHandler(String name, LogLevel level) {
this(name, level, ByteBufFormat.HEX_DUMP);
}
public LoggingHandler(String name, LogLevel level, ByteBufFormat byteBufFormat) {
ObjectUtil.checkNotNull(name, "name");
this.level = ObjectUtil.checkNotNull(level, "level");
this.byteBufFormat = ObjectUtil.checkNotNull(byteBufFormat, "byteBufFormat");
// 可以指定name
logger = InternalLoggerFactory.getInstance(name);
internalLevel = level.toInternalLevel();
}
LoggingHandler的构造方法不少,方便我们在构造时灵活创建,主要就是Level和logger的创建。
2 常规方法的日志打印
我们可以看一个典型,channelRegistered方法
public class LoggingHandler extends ChannelDuplexHandler {
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
// 如果适配当前level
if (logger.isEnabled(internalLevel)) {
// 这里就是将format后的内容以internalLevel级别打印出来,重点在format,具体在2.1
logger.log(internalLevel, format(ctx, "REGISTERED"));
}
// 事件传递到下一个Handler
ctx.fireChannelRegistered();
}
}
其他常规方法也是与registered方法类似,不再展示
2.1 format(ChannelHandlerContext ctx, String eventName)打印
protected String format(ChannelHandlerContext ctx, String eventName) {
// 获取当前channel信息
String chStr = ctx.channel().toString();
// 将channel信息及事件类型打印出来
return new StringBuilder(chStr.length() + 1 + eventName.length())
.append(chStr)
.append(' ')
.append(eventName)
.toString();
}
// 笔者启动HelloServer时打印出来的(channelRegistered)结果如下
22:28:52.627 [nioEventLoopGroup-2-1] INFO i.n.handler.logging.LoggingHandler - [id: 0xffa14504] REGISTERED
3.读写类方法日志打印
读写类的方法,因为有ByteBuf参数的传递,所以,打印方式有所不同。这里可以选择打印出16进制数据,具体方法如下:
public class LoggingHandler extends ChannelDuplexHandler {
protected String format(ChannelHandlerContext ctx, String eventName, Object arg) {
if (arg instanceof ByteBuf) {
// 将ByteBuf中的字节信息打印出来
return formatByteBuf(ctx, eventName, (ByteBuf) arg);
} else if (arg instanceof ByteBufHolder) {
return formatByteBufHolder(ctx, eventName, (ByteBufHolder) arg);
} else {
// 这个与2.1中的format方法类似
return formatSimple(ctx, eventName, arg);
}
}
}
3.1 LoggingHandler.formatByteBuf()
public class LoggingHandler extends ChannelDuplexHandler {
private String formatByteBuf(ChannelHandlerContext ctx, String eventName, ByteBuf msg) {
String chStr = ctx.channel().toString();
// 获取可读字节数
int length = msg.readableBytes();
if (length == 0) {
StringBuilder buf = new StringBuilder(chStr.length() + 1 + eventName.length() + 4);
buf.append(chStr).append(' ').append(eventName).append(": 0B");
return buf.toString();
} else {
int outputLength = chStr.length() + 1 + eventName.length() + 2 + 10 + 1;
if (byteBufFormat == ByteBufFormat.HEX_DUMP) {
// 一堆计算StringBuilder的总大小
int rows = length / 16 + (length % 15 == 0? 0 : 1) + 4;
int hexDumpLength = 2 + rows * 80;
outputLength += hexDumpLength;
}
StringBuilder buf = new StringBuilder(outputLength);
buf.append(chStr).append(' ').append(eventName).append(": ").append(length).append('B');
if (byteBufFormat == ByteBufFormat.HEX_DUMP) {
buf.append(NEWLINE);
// 具体在这里打印,具体不再深入
appendPrettyHexDump(buf, msg);
}
return buf.toString();
}
}
}
// 看一个服务端读取到客户端发送过来的信息(jack),所打印出来的结果
+-------------------------------------------------+
| 0 1 2 3 4 5 6 7 8 9 a b c d e f |
+--------+-------------------------------------------------+----------------+
|00000000| 6a 61 63 6b |jack |
+--------+-------------------------------------------------+----------------+
注意:HelloServer的代码需要改造下
// 指定client处理Handler
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("frame", new DelimiterBasedFrameDecoder(1024, Delimiters.lineDelimiter()));
// 需要放在这里,否则后续经过StringDecoder的处理后,ByteBuf已经变成了String类型了。
pipeline.addLast("logger", new LoggingHandler(LogLevel.INFO));
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
pipeline.addLast("handler", new HelloServerHandler());
}
});
另外formatByteBufHolder()的打印方法与该方法类似,不再细聊。
总结:
LoggingHandler在我们排查问题时还是比较有用的,我们可以在Netty开发中适当引用。
最后
以上就是花痴钢笔为你收集整理的Netty源码解析-LoggingHandler的全部内容,希望文章能够帮你解决Netty源码解析-LoggingHandler所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复