@@ -16,11 +16,14 @@ package etcdserver
16
16
17
17
import (
18
18
"fmt"
19
+ "strings"
19
20
"time"
20
21
21
22
"github.com/coreos/etcd/etcdserver/api/membership"
22
23
"github.com/coreos/etcd/etcdserver/api/rafthttp"
24
+ pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
23
25
"github.com/coreos/etcd/pkg/types"
26
+ "github.com/golang/protobuf/proto"
24
27
25
28
"go.uber.org/zap"
26
29
)
@@ -99,15 +102,40 @@ func (nc *notifier) notify(err error) {
99
102
close (nc .c )
100
103
}
101
104
102
- func warnOfExpensiveRequest (lg * zap.Logger , now time.Time , stringer fmt.Stringer ) {
103
- warnOfExpensiveGenericRequest (lg , now , stringer , "" )
105
+ func warnOfExpensiveRequest (lg * zap.Logger , now time.Time , reqStringer fmt.Stringer , respMsg proto.Message , err error ) {
106
+ var resp string
107
+ if respMsg != nil {
108
+ resp = fmt .Sprintf ("<size:%d>" , safeSize (respMsg ))
109
+ }
110
+ warnOfExpensiveGenericRequest (lg , now , reqStringer , "" , resp , err )
104
111
}
105
112
106
- func warnOfExpensiveReadOnlyRangeRequest (lg * zap.Logger , now time.Time , stringer fmt.Stringer ) {
107
- warnOfExpensiveGenericRequest (lg , now , stringer , "read-only range " )
113
+ func warnOfExpensiveReadOnlyTxnRequest (lg * zap.Logger , now time.Time , reqStringer fmt.Stringer , txnResponse * pb.TxnResponse , err error ) {
114
+ var resp string
115
+ if txnResponse != nil {
116
+ var resps []string
117
+ for _ , r := range txnResponse .Responses {
118
+ switch op := r .Response .(type ) {
119
+ case * pb.ResponseOp_ResponseRange :
120
+ resps = append (resps , fmt .Sprintf ("<range_response_count:%d>" , len (op .ResponseRange .Kvs )))
121
+ default :
122
+ // only range responses should be in a read only txn request
123
+ }
124
+ }
125
+ resp = fmt .Sprintf ("<responses:<%s> size:%d>" , strings .Join (resps , " " ), safeSize (txnResponse ))
126
+ }
127
+ warnOfExpensiveGenericRequest (lg , now , reqStringer , "read-only range " , resp , err )
108
128
}
109
129
110
- func warnOfExpensiveGenericRequest (lg * zap.Logger , now time.Time , stringer fmt.Stringer , prefix string ) {
130
+ func warnOfExpensiveReadOnlyRangeRequest (lg * zap.Logger , now time.Time , reqStringer fmt.Stringer , rangeResponse * pb.RangeResponse , err error ) {
131
+ var resp string
132
+ if rangeResponse != nil {
133
+ resp = fmt .Sprintf ("<range_response_count:%d size:%d>" , len (rangeResponse .Kvs ), safeSize (rangeResponse ))
134
+ }
135
+ warnOfExpensiveGenericRequest (lg , now , reqStringer , "read-only range " , resp , err )
136
+ }
137
+
138
+ func warnOfExpensiveGenericRequest (lg * zap.Logger , now time.Time , reqStringer fmt.Stringer , prefix string , resp string , err error ) {
111
139
// TODO: add metrics
112
140
d := time .Since (now )
113
141
if d > warnApplyDuration {
@@ -117,11 +145,30 @@ func warnOfExpensiveGenericRequest(lg *zap.Logger, now time.Time, stringer fmt.S
117
145
zap .Duration ("took" , d ),
118
146
zap .Duration ("expected-duration" , warnApplyDuration ),
119
147
zap .String ("prefix" , prefix ),
120
- zap .String ("request" , stringer .String ()),
148
+ zap .String ("request" , reqStringer .String ()),
149
+ zap .String ("response" , resp ),
150
+ zap .Error (err ),
121
151
)
122
152
} else {
123
- plog .Warningf ("%srequest %q took too long (%v) to execute" , prefix , stringer .String (), d )
153
+ var result string
154
+ if err != nil {
155
+ result = fmt .Sprintf ("<error:%v>" , err )
156
+ } else {
157
+ result = resp
158
+ }
159
+ plog .Warningf ("%srequest %q with result %q took too long (%v) to execute" , prefix , reqStringer .String (), result , d )
124
160
}
125
161
slowApplies .Inc ()
126
162
}
127
163
}
164
+
165
+ // safeSize attempt to calculate size using proto.Size, but recovers from panics and return -1 in those cases.
166
+ // TODO: Remove once https://github.com/golang/protobuf/issues/631 is resolved.
167
+ func safeSize (msg proto.Message ) (size int ) {
168
+ defer func () {
169
+ if r := recover (); r != nil {
170
+ size = - 1
171
+ }
172
+ }()
173
+ return proto .Size (msg )
174
+ }
0 commit comments