1// Copyright 2012 Gary Burd 2// 3// Licensed under the Apache License, Version 2.0 (the "License"): you may 4// not use this file except in compliance with the License. You may obtain 5// a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12// License for the specific language governing permissions and limitations 13// under the License. 14 15package redis 16 17import ( 18 "bytes" 19 "fmt" 20 "log" 21) 22 23// NewLoggingConn returns a logging wrapper around a connection. 24func NewLoggingConn(conn Conn, logger *log.Logger, prefix string) Conn { 25 if prefix != "" { 26 prefix = prefix + "." 27 } 28 return &loggingConn{conn, logger, prefix} 29} 30 31type loggingConn struct { 32 Conn 33 logger *log.Logger 34 prefix string 35} 36 37func (c *loggingConn) Close() error { 38 err := c.Conn.Close() 39 var buf bytes.Buffer 40 fmt.Fprintf(&buf, "%sClose() -> (%v)", c.prefix, err) 41 c.logger.Output(2, buf.String()) 42 return err 43} 44 45func (c *loggingConn) printValue(buf *bytes.Buffer, v interface{}) { 46 const chop = 32 47 switch v := v.(type) { 48 case []byte: 49 if len(v) > chop { 50 fmt.Fprintf(buf, "%q...", v[:chop]) 51 } else { 52 fmt.Fprintf(buf, "%q", v) 53 } 54 case string: 55 if len(v) > chop { 56 fmt.Fprintf(buf, "%q...", v[:chop]) 57 } else { 58 fmt.Fprintf(buf, "%q", v) 59 } 60 case []interface{}: 61 if len(v) == 0 { 62 buf.WriteString("[]") 63 } else { 64 sep := "[" 65 fin := "]" 66 if len(v) > chop { 67 v = v[:chop] 68 fin = "...]" 69 } 70 for _, vv := range v { 71 buf.WriteString(sep) 72 c.printValue(buf, vv) 73 sep = ", " 74 } 75 buf.WriteString(fin) 76 } 77 default: 78 fmt.Fprint(buf, v) 79 } 80} 81 82func (c *loggingConn) print(method, commandName string, args []interface{}, reply interface{}, err error) { 83 var buf bytes.Buffer 84 fmt.Fprintf(&buf, "%s%s(", c.prefix, method) 85 if method != "Receive" { 86 buf.WriteString(commandName) 87 for _, arg := range args { 88 buf.WriteString(", ") 89 c.printValue(&buf, arg) 90 } 91 } 92 buf.WriteString(") -> (") 93 if method != "Send" { 94 c.printValue(&buf, reply) 95 buf.WriteString(", ") 96 } 97 fmt.Fprintf(&buf, "%v)", err) 98 c.logger.Output(3, buf.String()) 99} 100 101func (c *loggingConn) Do(commandName string, args ...interface{}) (interface{}, error) { 102 reply, err := c.Conn.Do(commandName, args...) 103 c.print("Do", commandName, args, reply, err) 104 return reply, err 105} 106 107func (c *loggingConn) Send(commandName string, args ...interface{}) error { 108 err := c.Conn.Send(commandName, args...) 109 c.print("Send", commandName, args, nil, err) 110 return err 111} 112 113func (c *loggingConn) Receive() (interface{}, error) { 114 reply, err := c.Conn.Receive() 115 c.print("Receive", "", nil, reply, err) 116 return reply, err 117} 118