1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.codec.http2;
17
18 import io.netty.buffer.ByteBuf;
19 import io.netty.buffer.ByteBufUtil;
20 import io.netty.channel.ChannelHandlerAdapter;
21 import io.netty.channel.ChannelHandlerContext;
22 import io.netty.handler.logging.LogLevel;
23 import io.netty.util.internal.logging.InternalLogLevel;
24 import io.netty.util.internal.logging.InternalLogger;
25 import io.netty.util.internal.logging.InternalLoggerFactory;
26
27 import static io.netty.util.internal.ObjectUtil.checkNotNull;
28
29
30
31
32 public class Http2FrameLogger extends ChannelHandlerAdapter {
33
34 public enum Direction {
35 INBOUND,
36 OUTBOUND
37 }
38
39 private static final int BUFFER_LENGTH_THRESHOLD = 64;
40 private final InternalLogger logger;
41 private final InternalLogLevel level;
42
43 public Http2FrameLogger(LogLevel level) {
44 this(checkAndConvertLevel(level), InternalLoggerFactory.getInstance(Http2FrameLogger.class));
45 }
46
47 public Http2FrameLogger(LogLevel level, String name) {
48 this(checkAndConvertLevel(level), InternalLoggerFactory.getInstance(checkNotNull(name, "name")));
49 }
50
51 public Http2FrameLogger(LogLevel level, Class<?> clazz) {
52 this(checkAndConvertLevel(level), InternalLoggerFactory.getInstance(checkNotNull(clazz, "clazz")));
53 }
54
55 private Http2FrameLogger(InternalLogLevel level, InternalLogger logger) {
56 this.level = level;
57 this.logger = logger;
58 }
59
60 private static InternalLogLevel checkAndConvertLevel(LogLevel level) {
61 return checkNotNull(level, "level").toInternalLevel();
62 }
63
64 public boolean isEnabled() {
65 return logger.isEnabled(level);
66 }
67
68 public void logData(Direction direction, ChannelHandlerContext ctx, int streamId, ByteBuf data, int padding,
69 boolean endStream) {
70 if (isEnabled()) {
71 logger.log(level, "{} {} DATA: streamId={} padding={} endStream={} length={} bytes={}", ctx.channel(),
72 direction.name(), streamId, padding, endStream, data.readableBytes(), toString(data));
73 }
74 }
75
76 public void logHeaders(Direction direction, ChannelHandlerContext ctx, int streamId, Http2Headers headers,
77 int padding, boolean endStream) {
78 if (isEnabled()) {
79 logger.log(level, "{} {} HEADERS: streamId={} headers={} padding={} endStream={}", ctx.channel(),
80 direction.name(), streamId, headers, padding, endStream);
81 }
82 }
83
84 public void logHeaders(Direction direction, ChannelHandlerContext ctx, int streamId, Http2Headers headers,
85 int streamDependency, short weight, boolean exclusive, int padding, boolean endStream) {
86 if (isEnabled()) {
87 logger.log(level, "{} {} HEADERS: streamId={} headers={} streamDependency={} weight={} exclusive={} " +
88 "padding={} endStream={}", ctx.channel(),
89 direction.name(), streamId, headers, streamDependency, weight, exclusive, padding, endStream);
90 }
91 }
92
93 public void logPriority(Direction direction, ChannelHandlerContext ctx, int streamId, int streamDependency,
94 short weight, boolean exclusive) {
95 if (isEnabled()) {
96 logger.log(level, "{} {} PRIORITY: streamId={} streamDependency={} weight={} exclusive={}", ctx.channel(),
97 direction.name(), streamId, streamDependency, weight, exclusive);
98 }
99 }
100
101 public void logRstStream(Direction direction, ChannelHandlerContext ctx, int streamId, long errorCode) {
102 if (isEnabled()) {
103 logger.log(level, "{} {} RST_STREAM: streamId={} errorCode={}", ctx.channel(),
104 direction.name(), streamId, errorCode);
105 }
106 }
107
108 public void logSettingsAck(Direction direction, ChannelHandlerContext ctx) {
109 logger.log(level, "{} {} SETTINGS: ack=true", ctx.channel(), direction.name());
110 }
111
112 public void logSettings(Direction direction, ChannelHandlerContext ctx, Http2Settings settings) {
113 if (isEnabled()) {
114 logger.log(level, "{} {} SETTINGS: ack=false settings={}", ctx.channel(), direction.name(), settings);
115 }
116 }
117
118 public void logPing(Direction direction, ChannelHandlerContext ctx, long data) {
119 if (isEnabled()) {
120 logger.log(level, "{} {} PING: ack=false bytes={}", ctx.channel(),
121 direction.name(), data);
122 }
123 }
124
125 public void logPingAck(Direction direction, ChannelHandlerContext ctx, long data) {
126 if (isEnabled()) {
127 logger.log(level, "{} {} PING: ack=true bytes={}", ctx.channel(),
128 direction.name(), data);
129 }
130 }
131
132 public void logPushPromise(Direction direction, ChannelHandlerContext ctx, int streamId, int promisedStreamId,
133 Http2Headers headers, int padding) {
134 if (isEnabled()) {
135 logger.log(level, "{} {} PUSH_PROMISE: streamId={} promisedStreamId={} headers={} padding={}",
136 ctx.channel(), direction.name(), streamId, promisedStreamId, headers, padding);
137 }
138 }
139
140 public void logGoAway(Direction direction, ChannelHandlerContext ctx, int lastStreamId, long errorCode,
141 ByteBuf debugData) {
142 if (isEnabled()) {
143 logger.log(level, "{} {} GO_AWAY: lastStreamId={} errorCode={} length={} bytes={}", ctx.channel(),
144 direction.name(), lastStreamId, errorCode, debugData.readableBytes(), toString(debugData));
145 }
146 }
147
148 public void logWindowsUpdate(Direction direction, ChannelHandlerContext ctx, int streamId,
149 int windowSizeIncrement) {
150 if (isEnabled()) {
151 logger.log(level, "{} {} WINDOW_UPDATE: streamId={} windowSizeIncrement={}", ctx.channel(),
152 direction.name(), streamId, windowSizeIncrement);
153 }
154 }
155
156 public void logUnknownFrame(Direction direction, ChannelHandlerContext ctx, byte frameType, int streamId,
157 Http2Flags flags, ByteBuf data) {
158 if (isEnabled()) {
159 logger.log(level, "{} {} UNKNOWN: frameType={} streamId={} flags={} length={} bytes={}", ctx.channel(),
160 direction.name(), frameType & 0xFF, streamId, flags.value(), data.readableBytes(), toString(data));
161 }
162 }
163
164 private String toString(ByteBuf buf) {
165 if (level == InternalLogLevel.TRACE || buf.readableBytes() <= BUFFER_LENGTH_THRESHOLD) {
166
167 return ByteBufUtil.hexDump(buf);
168 }
169
170
171 int length = Math.min(buf.readableBytes(), BUFFER_LENGTH_THRESHOLD);
172 return ByteBufUtil.hexDump(buf, buf.readerIndex(), length) + "...";
173 }
174 }