From e73d442e327299ec50aae6ad66bfb2a3c5dc2848 Mon Sep 17 00:00:00 2001 From: Ben Darnell Date: Wed, 21 Jan 2015 14:12:58 -0500 Subject: [PATCH] raft: Add support for custom formatters in DescribeMessage/DescribeEntry --- raft/util.go | 30 ++++++++++++++++++++++++++---- raft/util_test.go | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 4 deletions(-) create mode 100644 raft/util_test.go diff --git a/raft/util.go b/raft/util.go index 91898ae0c..792fd1c68 100644 --- a/raft/util.go +++ b/raft/util.go @@ -54,9 +54,13 @@ func IsResponseMsg(m pb.Message) bool { return m.Type == pb.MsgAppResp || m.Type == pb.MsgVoteResp || m.Type == pb.MsgHeartbeatResp } +// EntryFormatter can be implemented by the application to provide human-readable formatting +// of entry data. Nil is a valid EntryFormatter and will use a default format. +type EntryFormatter func([]byte) string + // DescribeMessage returns a concise human-readable description of a // Message for debugging. -func DescribeMessage(m pb.Message) string { +func (f EntryFormatter) DescribeMessage(m pb.Message) string { var buf bytes.Buffer fmt.Fprintf(&buf, "%d->%d %s Term:%d Log:%d/%d", m.From, m.To, m.Type, m.Term, m.LogTerm, m.Index) if m.Reject { @@ -68,7 +72,7 @@ func DescribeMessage(m pb.Message) string { if len(m.Entries) > 0 { fmt.Fprintf(&buf, " Entries:[") for _, e := range m.Entries { - buf.WriteString(DescribeEntry(e)) + buf.WriteString(f.DescribeEntry(e)) } fmt.Fprintf(&buf, "]") } @@ -80,6 +84,24 @@ func DescribeMessage(m pb.Message) string { // DescribeEntry returns a concise human-readable description of an // Entry for debugging. -func DescribeEntry(e pb.Entry) string { - return fmt.Sprintf("%d/%d %s %q", e.Term, e.Index, e.Type, string(e.Data)) +func (f EntryFormatter) DescribeEntry(e pb.Entry) string { + var formatted string + if f == nil { + formatted = fmt.Sprintf("%q", e.Data) + } else { + formatted = f(e.Data) + } + return fmt.Sprintf("%d/%d %s %s", e.Term, e.Index, e.Type, formatted) +} + +// DescribeMessage returns a concise human-readable description of a +// Message for debugging using the default formatter. +func DescribeMessage(m pb.Message) string { + return EntryFormatter(nil).DescribeMessage(m) +} + +// DescribeEntry returns a concise human-readable description of an +// Entry for debugging using the default formatter. +func DescribeEntry(e pb.Entry) string { + return EntryFormatter(nil).DescribeEntry(e) } diff --git a/raft/util_test.go b/raft/util_test.go new file mode 100644 index 000000000..21b7908c9 --- /dev/null +++ b/raft/util_test.go @@ -0,0 +1,47 @@ +/* + Copyright 2014 CoreOS, Inc. + + 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 raft + +import ( + "strings" + "testing" + + pb "github.com/coreos/etcd/raft/raftpb" +) + +var testFormatter EntryFormatter = func(data []byte) string { + return strings.ToUpper(string(data)) +} + +func TestDescribeEntry(t *testing.T) { + entry := pb.Entry{ + Term: 1, + Index: 2, + Type: pb.EntryNormal, + Data: []byte("hello\x00world"), + } + + defaultFormatted := DescribeEntry(entry) + if defaultFormatted != "1/2 EntryNormal \"hello\\x00world\"" { + t.Errorf("unexpected default output: %s", defaultFormatted) + } + + customFormatted := testFormatter.DescribeEntry(entry) + if customFormatted != "1/2 EntryNormal HELLO\x00WORLD" { + t.Errorf("unexpected custom output: %s", customFormatted) + } +}