mirror of
https://github.com/tendermint/tendermint.git
synced 2026-09-20 15:04:22 +00:00
logging: implement lazy sprinting (#8898)
shout out to @joeabbey for the inspiration. This makes the lazy functions internal by default to prevent potential misuse by external callers. Should backport cleanly into 0.36 and I'll handle a messy merge into 0.35
This commit is contained in:
@@ -3,8 +3,94 @@ package strings
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
tmbytes "github.com/tendermint/tendermint/libs/bytes"
|
||||
)
|
||||
|
||||
type lazyStringf struct {
|
||||
tmpl string
|
||||
args []interface{}
|
||||
out string
|
||||
}
|
||||
|
||||
func (s *lazyStringf) String() string {
|
||||
if s.out == "" && s.tmpl != "" {
|
||||
s.out = fmt.Sprintf(s.tmpl, s.args)
|
||||
s.args = nil
|
||||
s.tmpl = ""
|
||||
}
|
||||
return s.out
|
||||
}
|
||||
|
||||
// LazySprintf creates a fmt.Stringer implementation with similar
|
||||
// semantics as fmt.Sprintf, *except* that the string is built when
|
||||
// String() is called on the object. This means that format arguments
|
||||
// are resolved/captured into string format when String() is called,
|
||||
// and not, as in fmt.Sprintf when that function returns.
|
||||
//
|
||||
// As a result, if you use this type in go routines or defer
|
||||
// statements it's possible to pass an argument to LazySprintf which
|
||||
// has one value at the call site and a different value when the
|
||||
// String() is evaluated, which may lead to unexpected outcomes. In
|
||||
// these situations, either be *extremely* careful about the arguments
|
||||
// passed to this function or use fmt.Sprintf.
|
||||
//
|
||||
// The implementation also caches the output of the underlying
|
||||
// fmt.Sprintf statement when String() is called, so subsequent calls
|
||||
// will produce the same result.
|
||||
func LazySprintf(t string, args ...interface{}) fmt.Stringer {
|
||||
return &lazyStringf{tmpl: t, args: args}
|
||||
}
|
||||
|
||||
type lazyStringer struct {
|
||||
val fmt.Stringer
|
||||
out string
|
||||
}
|
||||
|
||||
func (l *lazyStringer) String() string {
|
||||
if l.out == "" && l.val != nil {
|
||||
l.out = l.val.String()
|
||||
l.val = nil
|
||||
}
|
||||
return l.out
|
||||
}
|
||||
|
||||
// LazyStringer captures a fmt.Stringer implementation resolving the
|
||||
// underlying string *only* when the String() method is called and
|
||||
// caching the result for future use.
|
||||
func LazyStringer(v fmt.Stringer) fmt.Stringer { return &lazyStringer{val: v} }
|
||||
|
||||
type lazyBlockHash struct {
|
||||
block interface{ Hash() tmbytes.HexBytes }
|
||||
out string
|
||||
}
|
||||
|
||||
// LazyBlockHash defers block Hash until the Stringer interface is invoked.
|
||||
// This is particularly useful for avoiding calling Sprintf when debugging is not
|
||||
// active.
|
||||
//
|
||||
// As a result, if you use this type in go routines or defer
|
||||
// statements it's possible to pass an argument to LazyBlockHash that
|
||||
// has one value at the call site and a different value when the
|
||||
// String() is evaluated, which may lead to unexpected outcomes. In
|
||||
// these situations, either be *extremely* careful about the arguments
|
||||
// passed to this function or use fmt.Sprintf.
|
||||
//
|
||||
// The implementation also caches the output of the string form of the
|
||||
// block hash when String() is called, so subsequent calls will
|
||||
// produce the same result.
|
||||
func LazyBlockHash(block interface{ Hash() tmbytes.HexBytes }) fmt.Stringer {
|
||||
return &lazyBlockHash{block: block}
|
||||
}
|
||||
|
||||
func (l *lazyBlockHash) String() string {
|
||||
if l.out == "" && l.block != nil {
|
||||
l.out = l.block.Hash().String()
|
||||
l.block = nil
|
||||
}
|
||||
return l.out
|
||||
}
|
||||
|
||||
// SplitAndTrimEmpty slices s into all subslices separated by sep and returns a
|
||||
// slice of the string s with all leading and trailing Unicode code points
|
||||
// contained in cutset removed. If sep is empty, SplitAndTrim splits after each
|
||||
|
||||
Reference in New Issue
Block a user