• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2019 The gRPC Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * 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,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package io.grpc.okhttp;
18 
19 import static com.google.common.base.Preconditions.checkNotNull;
20 
21 import com.google.common.annotations.VisibleForTesting;
22 import io.grpc.okhttp.internal.framed.ErrorCode;
23 import io.grpc.okhttp.internal.framed.Header;
24 import io.grpc.okhttp.internal.framed.Settings;
25 import java.util.EnumMap;
26 import java.util.List;
27 import java.util.logging.Level;
28 import java.util.logging.Logger;
29 import okio.Buffer;
30 import okio.ByteString;
31 
32 class OkHttpFrameLogger {
33   private static final int BUFFER_LENGTH_THRESHOLD = 64;
34   private final Logger logger;
35   private final Level level;
36 
OkHttpFrameLogger(Level level, Class<?> clazz)37   OkHttpFrameLogger(Level level, Class<?> clazz) {
38     this(level, Logger.getLogger(clazz.getName()));
39   }
40 
41   @VisibleForTesting
OkHttpFrameLogger(Level level, Logger logger)42   OkHttpFrameLogger(Level level, Logger logger) {
43     this.level = checkNotNull(level, "level");
44     this.logger = checkNotNull(logger, "logger");
45   }
46 
toString(Settings settings)47   private static String toString(Settings settings) {
48     EnumMap<SettingParams, Integer> map = new EnumMap<>(SettingParams.class);
49     for (SettingParams p : SettingParams.values()) {
50       // Only log set parameters.
51       if (settings.isSet(p.getBit())) {
52         map.put(p, settings.get(p.getBit()));
53       }
54     }
55     return map.toString();
56   }
57 
toString(Buffer buf)58   private static String toString(Buffer buf) {
59     if (buf.size() <= BUFFER_LENGTH_THRESHOLD) {
60       // Log the entire buffer.
61       return buf.snapshot().hex();
62     }
63 
64     // Otherwise just log the first 64 bytes.
65     int length = (int) Math.min(buf.size(), BUFFER_LENGTH_THRESHOLD);
66     return buf.snapshot(length).hex() + "...";
67   }
68 
isEnabled()69   private boolean isEnabled() {
70     return logger.isLoggable(level);
71   }
72 
logData(Direction direction, int streamId, Buffer data, int length, boolean endStream)73   void logData(Direction direction, int streamId, Buffer data, int length, boolean endStream) {
74     if (isEnabled()) {
75       logger.log(
76           level,
77           direction
78               + " DATA: streamId="
79               + streamId
80               + " endStream="
81               + endStream
82               + " length="
83               + length
84               + " bytes="
85               + toString(data));
86     }
87   }
88 
logHeaders(Direction direction, int streamId, List<Header> headers, boolean endStream)89   void logHeaders(Direction direction, int streamId, List<Header> headers, boolean endStream) {
90     if (isEnabled()) {
91       logger.log(
92           level,
93           direction
94               + " HEADERS: streamId="
95               + streamId
96               + " headers="
97               + headers
98               + " endStream="
99               + endStream);
100     }
101   }
102 
logPriority( Direction direction, int streamId, int streamDependency, int weight, boolean exclusive)103   public void logPriority(
104       Direction direction, int streamId, int streamDependency, int weight, boolean exclusive) {
105     if (isEnabled()) {
106       logger.log(
107           level,
108           direction
109               + " PRIORITY: streamId="
110               + streamId
111               + " streamDependency="
112               + streamDependency
113               + " weight="
114               + weight
115               + " exclusive="
116               + exclusive);
117     }
118   }
119 
logRstStream(Direction direction, int streamId, ErrorCode errorCode)120   void logRstStream(Direction direction, int streamId, ErrorCode errorCode) {
121     if (isEnabled()) {
122       logger.log(
123           level, direction + " RST_STREAM: streamId=" + streamId + " errorCode=" + errorCode);
124     }
125   }
126 
logSettingsAck(Direction direction)127   void logSettingsAck(Direction direction) {
128     if (isEnabled()) {
129       logger.log(level, direction + " SETTINGS: ack=true");
130     }
131   }
132 
logSettings(Direction direction, Settings settings)133   void logSettings(Direction direction, Settings settings) {
134     if (isEnabled()) {
135       logger.log(level, direction + " SETTINGS: ack=false settings=" + toString(settings));
136     }
137   }
138 
logPing(Direction direction, long data)139   void logPing(Direction direction, long data) {
140     if (isEnabled()) {
141       logger.log(level, direction + " PING: ack=false bytes=" + data);
142     }
143   }
144 
logPingAck(Direction direction, long data)145   void logPingAck(Direction direction, long data) {
146     if (isEnabled()) {
147       logger.log(level, direction + " PING: ack=true bytes=" + data);
148     }
149   }
150 
logPushPromise( Direction direction, int streamId, int promisedStreamId, List<Header> headers)151   void logPushPromise(
152       Direction direction, int streamId, int promisedStreamId, List<Header> headers) {
153     if (isEnabled()) {
154       logger.log(
155           level,
156           direction
157               + " PUSH_PROMISE: streamId="
158               + streamId
159               + " promisedStreamId="
160               + promisedStreamId
161               + " headers="
162               + headers);
163     }
164   }
165 
logGoAway(Direction direction, int lastStreamId, ErrorCode errorCode, ByteString debugData)166   void logGoAway(Direction direction, int lastStreamId, ErrorCode errorCode, ByteString debugData) {
167     if (isEnabled()) {
168       logger.log(
169           level,
170           direction
171               + " GO_AWAY: lastStreamId="
172               + lastStreamId
173               + " errorCode="
174               + errorCode
175               + " length="
176               + debugData.size()
177               + " bytes="
178               + toString(new Buffer().write(debugData)));
179     }
180   }
181 
logWindowsUpdate(Direction direction, int streamId, long windowSizeIncrement)182   void logWindowsUpdate(Direction direction, int streamId, long windowSizeIncrement) {
183     if (isEnabled()) {
184       logger.log(
185           level,
186           direction
187               + " WINDOW_UPDATE: streamId="
188               + streamId
189               + " windowSizeIncrement="
190               + windowSizeIncrement);
191     }
192   }
193 
194   enum Direction {
195     INBOUND,
196     OUTBOUND
197   }
198 
199   // Note the set bits in OkHttp's Settings are different from HTTP2 Specifications.
200   private enum SettingParams {
201     HEADER_TABLE_SIZE(1),
202     ENABLE_PUSH(2),
203     MAX_CONCURRENT_STREAMS(4),
204     MAX_FRAME_SIZE(5),
205     MAX_HEADER_LIST_SIZE(6),
206     INITIAL_WINDOW_SIZE(7);
207 
208     private final int bit;
209 
SettingParams(int bit)210     SettingParams(int bit) {
211       this.bit = bit;
212     }
213 
getBit()214     public int getBit() {
215       return this.bit;
216     }
217   }
218 }
219