func Stringify(msg Message) string {
	var cv uint64
	if msg, ok := msg.(CertifiedMessage); ok {
		cv = msg.UI().Counter
	}
	switch msg := msg.(type) {
	case Hello:
		return fmt.Sprintf("<HELLO replica=%d>", msg.ReplicaID())
	case Request:
		return fmt.Sprintf("<REQUEST client=%d seq=%d operation=%q>",
			msg.ClientID(), msg.Sequence(),
			shortString(string(msg.Operation()), maxStringWidth))
	case Reply:
		return fmt.Sprintf("<REPLY replica=%d seq=%d result=%q>",
			msg.ReplicaID(), msg.Sequence(),
			shortString(string(msg.Result()), maxStringWidth))
	case Prepare:
		req := msg.Request()
		return fmt.Sprintf("<PREPARE cv=%d replica=%d view=%d client=%d seq=%d>",
			cv, msg.ReplicaID(), msg.View(),
			req.ClientID(), req.Sequence())
	case Commit:
		return fmt.Sprintf("<COMMIT cv=%d replica=%d prepare=%s>",
			cv, msg.ReplicaID(), Stringify(msg.Prepare()))
	case ReqViewChange:
		return fmt.Sprintf("<REQ-VIEW-CHANGE replica=%d newView=%d>",
			msg.ReplicaID(), msg.NewView())
	case ViewChange:
		return fmt.Sprintf("<VIEW-CHANGE cv=%d replica=%d newView=%d vcCert=%s>",
			cv, msg.ReplicaID(), msg.NewView(), vcCertString(msg.ViewChangeCert()))
	}
	return "(unknown message)"
}
Stringify returns a human-readable string representing the message
content that is sufficient for diagnostic output.
package messages
import (
	"fmt"
)
const maxStringWidth = 256