|
@@ -16,11 +16,15 @@ package etcdserver
|
|
|
|
|
|
|
|
import (
|
|
import (
|
|
|
"fmt"
|
|
"fmt"
|
|
|
|
|
+ "reflect"
|
|
|
|
|
+ "strings"
|
|
|
"time"
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/coreos/etcd/etcdserver/api/membership"
|
|
"github.com/coreos/etcd/etcdserver/api/membership"
|
|
|
"github.com/coreos/etcd/etcdserver/api/rafthttp"
|
|
"github.com/coreos/etcd/etcdserver/api/rafthttp"
|
|
|
|
|
+ pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
|
|
|
"github.com/coreos/etcd/pkg/types"
|
|
"github.com/coreos/etcd/pkg/types"
|
|
|
|
|
+ "github.com/golang/protobuf/proto"
|
|
|
|
|
|
|
|
"go.uber.org/zap"
|
|
"go.uber.org/zap"
|
|
|
)
|
|
)
|
|
@@ -99,15 +103,40 @@ func (nc *notifier) notify(err error) {
|
|
|
close(nc.c)
|
|
close(nc.c)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-func warnOfExpensiveRequest(lg *zap.Logger, now time.Time, stringer fmt.Stringer) {
|
|
|
|
|
- warnOfExpensiveGenericRequest(lg, now, stringer, "")
|
|
|
|
|
|
|
+func warnOfExpensiveRequest(lg *zap.Logger, now time.Time, reqStringer fmt.Stringer, respMsg proto.Message, err error) {
|
|
|
|
|
+ var resp string
|
|
|
|
|
+ if !isNil(respMsg) {
|
|
|
|
|
+ resp = fmt.Sprintf("size:%d", proto.Size(respMsg))
|
|
|
|
|
+ }
|
|
|
|
|
+ warnOfExpensiveGenericRequest(lg, now, reqStringer, "", resp, err)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func warnOfExpensiveReadOnlyTxnRequest(lg *zap.Logger, now time.Time, reqStringer fmt.Stringer, txnResponse *pb.TxnResponse, err error) {
|
|
|
|
|
+ var resp string
|
|
|
|
|
+ if !isNil(txnResponse) {
|
|
|
|
|
+ var resps []string
|
|
|
|
|
+ for _, r := range txnResponse.Responses {
|
|
|
|
|
+ switch op := r.Response.(type) {
|
|
|
|
|
+ case *pb.ResponseOp_ResponseRange:
|
|
|
|
|
+ resps = append(resps, fmt.Sprintf("range_response_count:%d", len(op.ResponseRange.Kvs)))
|
|
|
|
|
+ default:
|
|
|
|
|
+ // only range responses should be in a read only txn request
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ resp = fmt.Sprintf("responses:<%s> size:%d", strings.Join(resps, " "), proto.Size(txnResponse))
|
|
|
|
|
+ }
|
|
|
|
|
+ warnOfExpensiveGenericRequest(lg, now, reqStringer, "read-only range ", resp, err)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-func warnOfExpensiveReadOnlyRangeRequest(lg *zap.Logger, now time.Time, stringer fmt.Stringer) {
|
|
|
|
|
- warnOfExpensiveGenericRequest(lg, now, stringer, "read-only range ")
|
|
|
|
|
|
|
+func warnOfExpensiveReadOnlyRangeRequest(lg *zap.Logger, now time.Time, reqStringer fmt.Stringer, rangeResponse *pb.RangeResponse, err error) {
|
|
|
|
|
+ var resp string
|
|
|
|
|
+ if !isNil(rangeResponse) {
|
|
|
|
|
+ resp = fmt.Sprintf("range_response_count:%d size:%d", len(rangeResponse.Kvs), proto.Size(rangeResponse))
|
|
|
|
|
+ }
|
|
|
|
|
+ warnOfExpensiveGenericRequest(lg, now, reqStringer, "read-only range ", resp, err)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-func warnOfExpensiveGenericRequest(lg *zap.Logger, now time.Time, stringer fmt.Stringer, prefix string) {
|
|
|
|
|
|
|
+func warnOfExpensiveGenericRequest(lg *zap.Logger, now time.Time, reqStringer fmt.Stringer, prefix string, resp string, err error) {
|
|
|
// TODO: add metrics
|
|
// TODO: add metrics
|
|
|
d := time.Since(now)
|
|
d := time.Since(now)
|
|
|
if d > warnApplyDuration {
|
|
if d > warnApplyDuration {
|
|
@@ -117,11 +146,23 @@ func warnOfExpensiveGenericRequest(lg *zap.Logger, now time.Time, stringer fmt.S
|
|
|
zap.Duration("took", d),
|
|
zap.Duration("took", d),
|
|
|
zap.Duration("expected-duration", warnApplyDuration),
|
|
zap.Duration("expected-duration", warnApplyDuration),
|
|
|
zap.String("prefix", prefix),
|
|
zap.String("prefix", prefix),
|
|
|
- zap.String("request", stringer.String()),
|
|
|
|
|
|
|
+ zap.String("request", reqStringer.String()),
|
|
|
|
|
+ zap.String("response", resp),
|
|
|
|
|
+ zap.Error(err),
|
|
|
)
|
|
)
|
|
|
} else {
|
|
} else {
|
|
|
- plog.Warningf("%srequest %q took too long (%v) to execute", prefix, stringer.String(), d)
|
|
|
|
|
|
|
+ var result string
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ result = fmt.Sprintf("error:%v", err)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ result = resp
|
|
|
|
|
+ }
|
|
|
|
|
+ plog.Warningf("%srequest %q with result %q took too long (%v) to execute", prefix, reqStringer.String(), result, d)
|
|
|
}
|
|
}
|
|
|
slowApplies.Inc()
|
|
slowApplies.Inc()
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+func isNil(msg proto.Message) bool {
|
|
|
|
|
+ return msg == nil || reflect.ValueOf(msg).IsNil()
|
|
|
|
|
+}
|