1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.logging;
17
18 import io.netty.buffer.ByteBuf;
19 import io.netty.buffer.ByteBufHolder;
20 import io.netty.channel.ChannelDuplexHandler;
21 import io.netty.channel.ChannelHandler;
22 import io.netty.channel.ChannelHandler.Sharable;
23 import io.netty.channel.ChannelHandlerContext;
24 import io.netty.channel.ChannelPromise;
25 import io.netty.util.internal.logging.InternalLogLevel;
26 import io.netty.util.internal.logging.InternalLogger;
27 import io.netty.util.internal.logging.InternalLoggerFactory;
28
29 import java.net.SocketAddress;
30
31 import static io.netty.buffer.ByteBufUtil.appendPrettyHexDump;
32 import static io.netty.util.internal.StringUtil.NEWLINE;
33
34
35
36
37
38 @Sharable
39 public class LoggingHandler extends ChannelDuplexHandler {
40
41 private static final LogLevel DEFAULT_LEVEL = LogLevel.DEBUG;
42
43 protected final InternalLogger logger;
44 protected final InternalLogLevel internalLevel;
45
46 private final LogLevel level;
47
48
49
50
51
52 public LoggingHandler() {
53 this(DEFAULT_LEVEL);
54 }
55
56
57
58
59
60
61
62 public LoggingHandler(LogLevel level) {
63 if (level == null) {
64 throw new NullPointerException("level");
65 }
66
67 logger = InternalLoggerFactory.getInstance(getClass());
68 this.level = level;
69 internalLevel = level.toInternalLevel();
70 }
71
72
73
74
75
76 public LoggingHandler(Class<?> clazz) {
77 this(clazz, DEFAULT_LEVEL);
78 }
79
80
81
82
83
84
85 public LoggingHandler(Class<?> clazz, LogLevel level) {
86 if (clazz == null) {
87 throw new NullPointerException("clazz");
88 }
89 if (level == null) {
90 throw new NullPointerException("level");
91 }
92 logger = InternalLoggerFactory.getInstance(clazz);
93 this.level = level;
94 internalLevel = level.toInternalLevel();
95 }
96
97
98
99
100 public LoggingHandler(String name) {
101 this(name, DEFAULT_LEVEL);
102 }
103
104
105
106
107
108
109 public LoggingHandler(String name, LogLevel level) {
110 if (name == null) {
111 throw new NullPointerException("name");
112 }
113 if (level == null) {
114 throw new NullPointerException("level");
115 }
116 logger = InternalLoggerFactory.getInstance(name);
117 this.level = level;
118 internalLevel = level.toInternalLevel();
119 }
120
121
122
123
124 public LogLevel level() {
125 return level;
126 }
127
128 protected String format(ChannelHandlerContext ctx, String message) {
129 String chStr = ctx.channel().toString();
130 return new StringBuilder(chStr.length() + message.length() + 1)
131 .append(chStr)
132 .append(' ')
133 .append(message)
134 .toString();
135 }
136
137 @Override
138 public void channelRegistered(ChannelHandlerContext ctx)
139 throws Exception {
140 if (logger.isEnabled(internalLevel)) {
141 logger.log(internalLevel, format(ctx, "REGISTERED"));
142 }
143 super.channelRegistered(ctx);
144 }
145
146 @Override
147 public void channelUnregistered(ChannelHandlerContext ctx)
148 throws Exception {
149 if (logger.isEnabled(internalLevel)) {
150 logger.log(internalLevel, format(ctx, "UNREGISTERED"));
151 }
152 super.channelUnregistered(ctx);
153 }
154
155 @Override
156 public void channelActive(ChannelHandlerContext ctx)
157 throws Exception {
158 if (logger.isEnabled(internalLevel)) {
159 logger.log(internalLevel, format(ctx, "ACTIVE"));
160 }
161 super.channelActive(ctx);
162 }
163
164 @Override
165 public void channelInactive(ChannelHandlerContext ctx)
166 throws Exception {
167 if (logger.isEnabled(internalLevel)) {
168 logger.log(internalLevel, format(ctx, "INACTIVE"));
169 }
170 super.channelInactive(ctx);
171 }
172
173 @Override
174 public void exceptionCaught(ChannelHandlerContext ctx,
175 Throwable cause) throws Exception {
176 if (logger.isEnabled(internalLevel)) {
177 logger.log(internalLevel, format(ctx, "EXCEPTION: " + cause), cause);
178 }
179 super.exceptionCaught(ctx, cause);
180 }
181
182 @Override
183 public void userEventTriggered(ChannelHandlerContext ctx,
184 Object evt) throws Exception {
185 if (logger.isEnabled(internalLevel)) {
186 logger.log(internalLevel, format(ctx, "USER_EVENT: " + evt));
187 }
188 super.userEventTriggered(ctx, evt);
189 }
190
191 @Override
192 public void bind(ChannelHandlerContext ctx,
193 SocketAddress localAddress, ChannelPromise promise) throws Exception {
194 if (logger.isEnabled(internalLevel)) {
195 logger.log(internalLevel, format(ctx, "BIND(" + localAddress + ')'));
196 }
197 super.bind(ctx, localAddress, promise);
198 }
199
200 @Override
201 public void connect(ChannelHandlerContext ctx,
202 SocketAddress remoteAddress, SocketAddress localAddress,
203 ChannelPromise promise) throws Exception {
204 if (logger.isEnabled(internalLevel)) {
205 logger.log(internalLevel, format(ctx, "CONNECT(" + remoteAddress + ", " + localAddress + ')'));
206 }
207 super.connect(ctx, remoteAddress, localAddress, promise);
208 }
209
210 @Override
211 public void disconnect(ChannelHandlerContext ctx,
212 ChannelPromise promise) throws Exception {
213 if (logger.isEnabled(internalLevel)) {
214 logger.log(internalLevel, format(ctx, "DISCONNECT()"));
215 }
216 super.disconnect(ctx, promise);
217 }
218
219 @Override
220 public void close(ChannelHandlerContext ctx,
221 ChannelPromise promise) throws Exception {
222 if (logger.isEnabled(internalLevel)) {
223 logger.log(internalLevel, format(ctx, "CLOSE()"));
224 }
225 super.close(ctx, promise);
226 }
227
228 @Override
229 public void deregister(ChannelHandlerContext ctx,
230 ChannelPromise promise) throws Exception {
231 if (logger.isEnabled(internalLevel)) {
232 logger.log(internalLevel, format(ctx, "DEREGISTER()"));
233 }
234 super.deregister(ctx, promise);
235 }
236
237 @Override
238 public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
239 if (logger.isEnabled(internalLevel)) {
240 logger.log(internalLevel, format(ctx, "READ COMPLETE"));
241 }
242 ctx.fireChannelReadComplete();
243 }
244
245 @Override
246 public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
247 logMessage(ctx, "READ", msg);
248 ctx.fireChannelRead(msg);
249 }
250
251 @Override
252 public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
253 logMessage(ctx, "WRITE", msg);
254 ctx.write(msg, promise);
255 }
256
257 @Override
258 public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {
259 if (logger.isEnabled(internalLevel)) {
260 logger.log(internalLevel, format(ctx, "WRITABILITY CHANGED"));
261 }
262 ctx.fireChannelWritabilityChanged();
263 }
264
265 @Override
266 public void flush(ChannelHandlerContext ctx) throws Exception {
267 if (logger.isEnabled(internalLevel)) {
268 logger.log(internalLevel, format(ctx, "FLUSH"));
269 }
270 ctx.flush();
271 }
272
273 private void logMessage(ChannelHandlerContext ctx, String eventName, Object msg) {
274 if (logger.isEnabled(internalLevel)) {
275 logger.log(internalLevel, format(ctx, formatMessage(eventName, msg)));
276 }
277 }
278
279 protected String formatMessage(String eventName, Object msg) {
280 if (msg instanceof ByteBuf) {
281 return formatByteBuf(eventName, (ByteBuf) msg);
282 } else if (msg instanceof ByteBufHolder) {
283 return formatByteBufHolder(eventName, (ByteBufHolder) msg);
284 } else {
285 return formatNonByteBuf(eventName, msg);
286 }
287 }
288
289
290
291
292 protected String formatByteBuf(String eventName, ByteBuf msg) {
293 int length = msg.readableBytes();
294 if (length == 0) {
295 StringBuilder buf = new StringBuilder(eventName.length() + 4);
296 buf.append(eventName).append(": 0B");
297 return buf.toString();
298 } else {
299 int rows = length / 16 + (length % 15 == 0? 0 : 1) + 4;
300 StringBuilder buf = new StringBuilder(eventName.length() + 2 + 10 + 1 + 2 + rows * 80);
301
302 buf.append(eventName).append(": ").append(length).append('B').append(NEWLINE);
303 appendPrettyHexDump(buf, msg);
304
305 return buf.toString();
306 }
307 }
308
309
310
311
312 protected String formatNonByteBuf(String eventName, Object msg) {
313 return eventName + ": " + msg;
314 }
315
316
317
318
319
320
321
322 protected String formatByteBufHolder(String eventName, ByteBufHolder msg) {
323 String msgStr = msg.toString();
324 ByteBuf content = msg.content();
325 int length = content.readableBytes();
326 if (length == 0) {
327 StringBuilder buf = new StringBuilder(eventName.length() + 2 + msgStr.length() + 4);
328 buf.append(eventName).append(", ").append(msgStr).append(", 0B");
329 return buf.toString();
330 } else {
331 int rows = length / 16 + (length % 15 == 0? 0 : 1) + 4;
332 StringBuilder buf = new StringBuilder(
333 eventName.length() + 2 + msgStr.length() + 2 + 10 + 1 + 2 + rows * 80);
334
335 buf.append(eventName).append(": ")
336 .append(msgStr).append(", ").append(length).append('B').append(NEWLINE);
337 appendPrettyHexDump(buf, content);
338
339 return buf.toString();
340 }
341 }
342 }
343