View Javadoc
1   /*
2    * Copyright 2014 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty.handler.codec.http2;
17  
18  import static io.netty.util.internal.ObjectUtil.checkNotNull;
19  import io.netty.buffer.ByteBuf;
20  import io.netty.buffer.ByteBufUtil;
21  import io.netty.channel.ChannelHandlerAdapter;
22  import io.netty.util.internal.logging.InternalLogLevel;
23  import io.netty.util.internal.logging.InternalLogger;
24  import io.netty.util.internal.logging.InternalLoggerFactory;
25  
26  /**
27   * Logs HTTP2 frames for debugging purposes.
28   */
29  public class Http2FrameLogger extends ChannelHandlerAdapter {
30  
31      public enum Direction {
32          INBOUND,
33          OUTBOUND
34      }
35  
36      private final InternalLogger logger;
37      private final InternalLogLevel level;
38  
39      public Http2FrameLogger(InternalLogLevel level) {
40          this(level, InternalLoggerFactory.getInstance(Http2FrameLogger.class));
41      }
42  
43      public Http2FrameLogger(InternalLogLevel level, InternalLogger logger) {
44          this.level = checkNotNull(level, "level");
45          this.logger = checkNotNull(logger, "logger");
46      }
47  
48      public void logData(Direction direction, int streamId, ByteBuf data, int padding,
49              boolean endStream) {
50          log(direction,
51                  "DATA: streamId=%d, padding=%d, endStream=%b, length=%d, bytes=%s",
52                  streamId, padding, endStream, data.readableBytes(), ByteBufUtil.hexDump(data));
53      }
54  
55      public void logHeaders(Direction direction, int streamId, Http2Headers headers, int padding,
56              boolean endStream) {
57          log(direction, "HEADERS: streamId:%d, headers=%s, padding=%d, endStream=%b",
58                  streamId, headers, padding, endStream);
59      }
60  
61      public void logHeaders(Direction direction, int streamId, Http2Headers headers,
62              int streamDependency, short weight, boolean exclusive, int padding, boolean endStream) {
63          log(direction,
64                  "HEADERS: streamId:%d, headers=%s, streamDependency=%d, weight=%d, exclusive=%b, "
65                          + "padding=%d, endStream=%b", streamId, headers,
66                  streamDependency, weight, exclusive, padding, endStream);
67      }
68  
69      public void logPriority(Direction direction, int streamId, int streamDependency, short weight,
70              boolean exclusive) {
71          log(direction, "PRIORITY: streamId=%d, streamDependency=%d, weight=%d, exclusive=%b",
72                  streamId, streamDependency, weight, exclusive);
73      }
74  
75      public void logRstStream(Direction direction, int streamId, long errorCode) {
76          log(direction, "RST_STREAM: streamId=%d, errorCode=%d", streamId, errorCode);
77      }
78  
79      public void logSettingsAck(Direction direction) {
80          log(direction, "SETTINGS ack=true");
81      }
82  
83      public void logSettings(Direction direction, Http2Settings settings) {
84          log(direction, "SETTINGS: ack=false, settings=%s", settings);
85      }
86  
87      public void logPing(Direction direction, ByteBuf data) {
88          log(direction, "PING: ack=false, length=%d, bytes=%s", data.readableBytes(), ByteBufUtil.hexDump(data));
89      }
90  
91      public void logPingAck(Direction direction, ByteBuf data) {
92          log(direction, "PING: ack=true, length=%d, bytes=%s", data.readableBytes(), ByteBufUtil.hexDump(data));
93      }
94  
95      public void logPushPromise(Direction direction, int streamId, int promisedStreamId,
96              Http2Headers headers, int padding) {
97          log(direction, "PUSH_PROMISE: streamId=%d, promisedStreamId=%d, headers=%s, padding=%d",
98                  streamId, promisedStreamId, headers, padding);
99      }
100 
101     public void logGoAway(Direction direction, int lastStreamId, long errorCode, ByteBuf debugData) {
102         log(direction, "GO_AWAY: lastStreamId=%d, errorCode=%d, length=%d, bytes=%s", lastStreamId,
103                 errorCode, debugData.readableBytes(), ByteBufUtil.hexDump(debugData));
104     }
105 
106     public void logWindowsUpdate(Direction direction, int streamId, int windowSizeIncrement) {
107         log(direction, "WINDOW_UPDATE: streamId=%d, windowSizeIncrement=%d", streamId,
108                 windowSizeIncrement);
109     }
110 
111     public void logUnknownFrame(Direction direction, byte frameType, int streamId, Http2Flags flags, ByteBuf data) {
112         log(direction, "UNKNOWN: frameType=%d, streamId=%d, flags=%d, length=%d, bytes=%s",
113                 frameType & 0xFF, streamId, flags.value(), data.readableBytes(), ByteBufUtil.hexDump(data));
114     }
115 
116     private void log(Direction direction, String format, Object... args) {
117         if (logger.isEnabled(level)) {
118             StringBuilder b = new StringBuilder(200);
119             b.append("\n----------------")
120              .append(direction.name())
121              .append("--------------------\n")
122              .append(String.format(format, args))
123              .append("\n------------------------------------");
124             logger.log(level, b.toString());
125         }
126     }
127 }