text: // Copyright 2018 The etcd Authors
  //
  // Licensed under the Apache License, Version 2.0 (the "License");
  // you may not use this file except in compliance with the License.
  // You may obtain a copy of the License at
  //
  //     http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing, software
  // distributed under the License is distributed on an "AS IS" BASIS,
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  // See the License for the specific language governing permissions and
  // limitations under the License.
  
  package etcdserverpb
  
  import (
  	"fmt"
  	"strings"
  
  	proto "github.com/golang/protobuf/proto"
  )
  
  // InternalRaftStringer implements custom proto Stringer:
  // redact password, replace value fields with value_size fields.
  type InternalRaftStringer struct {
  	Request *InternalRaftRequest
  }
  
  func (as *InternalRaftStringer) String() string {
  	switch {
  	case as.Request.LeaseGrant != nil:
  		return fmt.Sprintf("header:<%s> lease_grant:<ttl:%d-second id:%016x>",
  			as.Request.Header.String(),
  			as.Request.LeaseGrant.TTL,
  			as.Request.LeaseGrant.ID,
  		)
  	case as.Request.LeaseRevoke != nil:
  		return fmt.Sprintf("header:<%s> lease_revoke:<id:%016x>",
  			as.Request.Header.String(),
  			as.Request.LeaseRevoke.ID,
  		)
  	case as.Request.Authenticate != nil:
  		return fmt.Sprintf("header:<%s> authenticate:<name:%s simple_token:%s>",
  			as.Request.Header.String(),
  			as.Request.Authenticate.Name,
  			as.Request.Authenticate.SimpleToken,
  		)
  	case as.Request.AuthUserAdd != nil:
  		return fmt.Sprintf("header:<%s> auth_user_add:<name:%s>",
  			as.Request.Header.String(),
  			as.Request.AuthUserAdd.Name,
  		)
  	case as.Request.AuthUserChangePassword != nil:
  		return fmt.Sprintf("header:<%s> auth_user_change_password:<name:%s>",
  			as.Request.Header.String(),
  			as.Request.AuthUserChangePassword.Name,
  		)
  	case as.Request.Put != nil:
  		return fmt.Sprintf("header:<%s> put:<%s>",
  			as.Request.Header.String(),
  			NewLoggablePutRequest(as.Request.Put).String(),
  		)
  	case as.Request.Txn != nil:
  		return fmt.Sprintf("header:<%s> txn:<%s>",
  			as.Request.Header.String(),
  			NewLoggableTxnRequest(as.Request.Txn).String(),
  		)
  	default:
  		// nothing to redact
  	}
  	return as.Request.String()
  }
  
  // txnRequestStringer implements a custom proto String to replace value bytes fields with value size
  // fields in any nested txn and put operations.
  type txnRequestStringer struct {
  	Request *TxnRequest
  }
  
  func NewLoggableTxnRequest(request *TxnRequest) *txnRequestStringer {
  	return &txnRequestStringer{request}
  }
  
  func (as *txnRequestStringer) String() string {
  	var compare []string
  	for _, c := range as.Request.Compare {
  		switch cv := c.TargetUnion.(type) {
  		case *Compare_Value:
  			compare = append(compare, newLoggableValueCompare(c, cv).String())
  		default:
  			// nothing to redact
  			compare = append(compare, c.String())
  		}
  	}
  	var success []string
  	for _, s := range as.Request.Success {
  		success = append(success, newLoggableRequestOp(s).String())
  	}
  	var failure []string
  	for _, f := range as.Request.Failure {
  		failure = append(failure, newLoggableRequestOp(f).String())
  	}
  	return fmt.Sprintf("compare:<%s> success:<%s> failure:<%s>",
  		strings.Join(compare, " "),
  		strings.Join(success, " "),
  		strings.Join(failure, " "),
  	)
  }
  
  // requestOpStringer implements a custom proto String to replace value bytes fields with value
  // size fields in any nested txn and put operations.
  type requestOpStringer struct {
  	Op *RequestOp
  }
  
  func newLoggableRequestOp(op *RequestOp) *requestOpStringer {
  	return &requestOpStringer{op}
  }
  
  func (as *requestOpStringer) String() string {
  	switch op := as.Op.Request.(type) {
  	case *RequestOp_RequestPut:
  		return fmt.Sprintf("request_put:<%s>", NewLoggablePutRequest(op.RequestPut).String())
  	case *RequestOp_RequestTxn:
  		return fmt.Sprintf("request_txn:<%s>", NewLoggableTxnRequest(op.RequestTxn).String())
  	default:
  		// nothing to redact
  	}
  	return as.Op.String()
  }
  
  // loggableValueCompare implements a custom proto String for Compare.Value union member types to
  // replace the value bytes field with a value size field.
  // To preserve proto encoding of the key and range_end bytes, a faked out proto type is used here.
  type loggableValueCompare struct {
  	Result    Compare_CompareResult `protobuf:"varint,1,opt,name=result,proto3,enum=etcdserverpb.Compare_CompareResult"`
  	Target    Compare_CompareTarget `protobuf:"varint,2,opt,name=target,proto3,enum=etcdserverpb.Compare_CompareTarget"`
  	Key       []byte                `protobuf:"bytes,3,opt,name=key,proto3"`
  	ValueSize int                   `protobuf:"bytes,7,opt,name=value_size,proto3"`
  	RangeEnd  []byte                `protobuf:"bytes,64,opt,name=range_end,proto3"`
  }
  
  func newLoggableValueCompare(c *Compare, cv *Compare_Value) *loggableValueCompare {
  	return &loggableValueCompare{
  		c.Result,
  		c.Target,
  		c.Key,
  		len(cv.Value),
  		c.RangeEnd,
  	}
  }
  
  func (m *loggableValueCompare) Reset()         { *m = loggableValueCompare{} }
  func (m *loggableValueCompare) String() string { return proto.CompactTextString(m) }
  func (*loggableValueCompare) ProtoMessage()    {}
  
  // loggablePutRequest implements a custom proto String to replace value bytes field with a value
  // size field.
  // To preserve proto encoding of the key bytes, a faked out proto type is used here.
  type loggablePutRequest struct {
  	Key         []byte `protobuf:"bytes,1,opt,name=key,proto3"`
  	ValueSize   int    `protobuf:"varint,2,opt,name=value_size,proto3"`
  	Lease       int64  `protobuf:"varint,3,opt,name=lease,proto3"`
  	PrevKv      bool   `protobuf:"varint,4,opt,name=prev_kv,proto3"`
  	IgnoreValue bool   `protobuf:"varint,5,opt,name=ignore_value,proto3"`
  	IgnoreLease bool   `protobuf:"varint,6,opt,name=ignore_lease,proto3"`
  }
  
  func NewLoggablePutRequest(request *PutRequest) *loggablePutRequest {
  	return &loggablePutRequest{
  		request.Key,
  		len(request.Value),
  		request.Lease,
  		request.PrevKv,
  		request.IgnoreValue,
  		request.IgnoreLease,
  	}
  }
  
  func (m *loggablePutRequest) Reset()         { *m = loggablePutRequest{} }
  func (m *loggablePutRequest) String() string { return proto.CompactTextString(m) }
  func (*loggablePutRequest) ProtoMessage()    {}
  