1// Copyright 2018 The etcd Authors 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain 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, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package etcdserverpb 16 17import ( 18 "fmt" 19 "strings" 20 21 proto "github.com/golang/protobuf/proto" 22) 23 24// InternalRaftStringer implements custom proto Stringer: 25// redact password, replace value fields with value_size fields. 26type InternalRaftStringer struct { 27 Request *InternalRaftRequest 28} 29 30func (as *InternalRaftStringer) String() string { 31 switch { 32 case as.Request.LeaseGrant != nil: 33 return fmt.Sprintf("header:<%s> lease_grant:<ttl:%d-second id:%016x>", 34 as.Request.Header.String(), 35 as.Request.LeaseGrant.TTL, 36 as.Request.LeaseGrant.ID, 37 ) 38 case as.Request.LeaseRevoke != nil: 39 return fmt.Sprintf("header:<%s> lease_revoke:<id:%016x>", 40 as.Request.Header.String(), 41 as.Request.LeaseRevoke.ID, 42 ) 43 case as.Request.Authenticate != nil: 44 return fmt.Sprintf("header:<%s> authenticate:<name:%s simple_token:%s>", 45 as.Request.Header.String(), 46 as.Request.Authenticate.Name, 47 as.Request.Authenticate.SimpleToken, 48 ) 49 case as.Request.AuthUserAdd != nil: 50 return fmt.Sprintf("header:<%s> auth_user_add:<name:%s>", 51 as.Request.Header.String(), 52 as.Request.AuthUserAdd.Name, 53 ) 54 case as.Request.AuthUserChangePassword != nil: 55 return fmt.Sprintf("header:<%s> auth_user_change_password:<name:%s>", 56 as.Request.Header.String(), 57 as.Request.AuthUserChangePassword.Name, 58 ) 59 case as.Request.Put != nil: 60 return fmt.Sprintf("header:<%s> put:<%s>", 61 as.Request.Header.String(), 62 NewLoggablePutRequest(as.Request.Put).String(), 63 ) 64 case as.Request.Txn != nil: 65 return fmt.Sprintf("header:<%s> txn:<%s>", 66 as.Request.Header.String(), 67 NewLoggableTxnRequest(as.Request.Txn).String(), 68 ) 69 default: 70 // nothing to redact 71 } 72 return as.Request.String() 73} 74 75// txnRequestStringer implements a custom proto String to replace value bytes fields with value size 76// fields in any nested txn and put operations. 77type txnRequestStringer struct { 78 Request *TxnRequest 79} 80 81func NewLoggableTxnRequest(request *TxnRequest) *txnRequestStringer { 82 return &txnRequestStringer{request} 83} 84 85func (as *txnRequestStringer) String() string { 86 var compare []string 87 for _, c := range as.Request.Compare { 88 switch cv := c.TargetUnion.(type) { 89 case *Compare_Value: 90 compare = append(compare, newLoggableValueCompare(c, cv).String()) 91 default: 92 // nothing to redact 93 compare = append(compare, c.String()) 94 } 95 } 96 var success []string 97 for _, s := range as.Request.Success { 98 success = append(success, newLoggableRequestOp(s).String()) 99 } 100 var failure []string 101 for _, f := range as.Request.Failure { 102 failure = append(failure, newLoggableRequestOp(f).String()) 103 } 104 return fmt.Sprintf("compare:<%s> success:<%s> failure:<%s>", 105 strings.Join(compare, " "), 106 strings.Join(success, " "), 107 strings.Join(failure, " "), 108 ) 109} 110 111// requestOpStringer implements a custom proto String to replace value bytes fields with value 112// size fields in any nested txn and put operations. 113type requestOpStringer struct { 114 Op *RequestOp 115} 116 117func newLoggableRequestOp(op *RequestOp) *requestOpStringer { 118 return &requestOpStringer{op} 119} 120 121func (as *requestOpStringer) String() string { 122 switch op := as.Op.Request.(type) { 123 case *RequestOp_RequestPut: 124 return fmt.Sprintf("request_put:<%s>", NewLoggablePutRequest(op.RequestPut).String()) 125 case *RequestOp_RequestTxn: 126 return fmt.Sprintf("request_txn:<%s>", NewLoggableTxnRequest(op.RequestTxn).String()) 127 default: 128 // nothing to redact 129 } 130 return as.Op.String() 131} 132 133// loggableValueCompare implements a custom proto String for Compare.Value union member types to 134// replace the value bytes field with a value size field. 135// To preserve proto encoding of the key and range_end bytes, a faked out proto type is used here. 136type loggableValueCompare struct { 137 Result Compare_CompareResult `protobuf:"varint,1,opt,name=result,proto3,enum=etcdserverpb.Compare_CompareResult"` 138 Target Compare_CompareTarget `protobuf:"varint,2,opt,name=target,proto3,enum=etcdserverpb.Compare_CompareTarget"` 139 Key []byte `protobuf:"bytes,3,opt,name=key,proto3"` 140 ValueSize int64 `protobuf:"varint,7,opt,name=value_size,proto3"` 141 RangeEnd []byte `protobuf:"bytes,64,opt,name=range_end,proto3"` 142} 143 144func newLoggableValueCompare(c *Compare, cv *Compare_Value) *loggableValueCompare { 145 return &loggableValueCompare{ 146 c.Result, 147 c.Target, 148 c.Key, 149 int64(len(cv.Value)), 150 c.RangeEnd, 151 } 152} 153 154func (m *loggableValueCompare) Reset() { *m = loggableValueCompare{} } 155func (m *loggableValueCompare) String() string { return proto.CompactTextString(m) } 156func (*loggableValueCompare) ProtoMessage() {} 157 158// loggablePutRequest implements a custom proto String to replace value bytes field with a value 159// size field. 160// To preserve proto encoding of the key bytes, a faked out proto type is used here. 161type loggablePutRequest struct { 162 Key []byte `protobuf:"bytes,1,opt,name=key,proto3"` 163 ValueSize int64 `protobuf:"varint,2,opt,name=value_size,proto3"` 164 Lease int64 `protobuf:"varint,3,opt,name=lease,proto3"` 165 PrevKv bool `protobuf:"varint,4,opt,name=prev_kv,proto3"` 166 IgnoreValue bool `protobuf:"varint,5,opt,name=ignore_value,proto3"` 167 IgnoreLease bool `protobuf:"varint,6,opt,name=ignore_lease,proto3"` 168} 169 170func NewLoggablePutRequest(request *PutRequest) *loggablePutRequest { 171 return &loggablePutRequest{ 172 request.Key, 173 int64(len(request.Value)), 174 request.Lease, 175 request.PrevKv, 176 request.IgnoreValue, 177 request.IgnoreLease, 178 } 179} 180 181func (m *loggablePutRequest) Reset() { *m = loggablePutRequest{} } 182func (m *loggablePutRequest) String() string { return proto.CompactTextString(m) } 183func (*loggablePutRequest) ProtoMessage() {} 184