Skip to content

Commit

Permalink
Do not use the flow style in the diff output (#4170)
Browse files Browse the repository at this point in the history
Closes #4157.
  • Loading branch information
AlekSi committed Mar 13, 2024
1 parent 75f5a74 commit 9993f43
Show file tree
Hide file tree
Showing 14 changed files with 215 additions and 97 deletions.
7 changes: 6 additions & 1 deletion internal/bson2/array.go
Expand Up @@ -148,7 +148,12 @@ func (arr *Array) LogValue() slog.Value {
// somewhat similar (but not identical) to JSON or Go syntax.
// It may change over time.
func (arr *Array) LogMessage() string {
return logMessage(arr)
return logMessage(arr, logMaxFlowLength, "", 1)
}

// LogMessageBlock is a variant of [Array.LogMessage] that never uses a flow style.
func (arr *Array) LogMessageBlock() string {
return logMessage(arr, 0, "", 1)
}

// check interfaces
Expand Down
7 changes: 6 additions & 1 deletion internal/bson2/document.go
Expand Up @@ -182,7 +182,12 @@ func (doc *Document) LogValue() slog.Value {
// somewhat similar (but not identical) to JSON or Go syntax.
// It may change over time.
func (doc *Document) LogMessage() string {
return logMessage(doc)
return logMessage(doc, logMaxFlowLength, "", 1)
}

// LogMessageBlock is a variant of [Document.LogMessage] that never uses a flow style.
func (doc *Document) LogMessageBlock() string {
return logMessage(doc, 0, "", 1)
}

// check interfaces
Expand Down
31 changes: 13 additions & 18 deletions internal/bson2/logging.go
Expand Up @@ -25,13 +25,13 @@ import (
"time"
)

// logMaxFlowLength is the maximum length of a flow/inline/compact representation of a BSON value.
// It may be set to 0 to disable flow representation.
const logMaxFlowLength = 80

// logMaxDepth is the maximum depth of a recursive representation of a BSON value.
const logMaxDepth = 20

// logMaxFlowLength is the maximum length of a flow/inline/compact representation of a BSON value.
// It may be set to 0 to always disable flow representation.
const logMaxFlowLength = 80

// nanBits is the most common pattern of a NaN float64 value, the same as math.Float64bits(math.NaN()).
const nanBits = 0b111111111111000000000000000000000000000000000000000000000000001

Expand Down Expand Up @@ -141,12 +141,7 @@ func slogValue(v any, depth int) slog.Value {
//
// The result is optimized for large values such as full request documents.
// All information is preserved.
func logMessage(v any) string {
return logMessageIndent(v, "", 1)
}

// logMessageIndent is a variant of [logMessage] with an indentation and depth for recursive calls.
func logMessageIndent(v any, indent string, depth int) string {
func logMessage(v any, maxFlowLength int, indent string, depth int) string {
switch v := v.(type) {
case *Document:
l := len(v.fields)
Expand All @@ -158,12 +153,12 @@ func logMessageIndent(v any, indent string, depth int) string {
return "{...}"
}

if logMaxFlowLength > 0 {
if maxFlowLength > 0 {
res := "{"

for i, f := range v.fields {
res += strconv.Quote(f.name) + `: `
res += logMessageIndent(f.value, "", depth+1)
res += logMessage(f.value, maxFlowLength, "", depth+1)

if i != l-1 {
res += ", "
Expand All @@ -172,7 +167,7 @@ func logMessageIndent(v any, indent string, depth int) string {

res += `}`

if len(res) < logMaxFlowLength {
if len(res) < maxFlowLength {
return res
}
}
Expand All @@ -182,7 +177,7 @@ func logMessageIndent(v any, indent string, depth int) string {
for _, f := range v.fields {
res += indent + " "
res += strconv.Quote(f.name) + `: `
res += logMessageIndent(f.value, indent+" ", depth+1) + ",\n"
res += logMessage(f.value, maxFlowLength, indent+" ", depth+1) + ",\n"
}

res += indent + `}`
Expand All @@ -202,11 +197,11 @@ func logMessageIndent(v any, indent string, depth int) string {
return "[...]"
}

if logMaxFlowLength > 0 {
if maxFlowLength > 0 {
res := "["

for i, e := range v.elements {
res += logMessageIndent(e, "", depth+1)
res += logMessage(e, maxFlowLength, "", depth+1)

if i != l-1 {
res += ", "
Expand All @@ -215,7 +210,7 @@ func logMessageIndent(v any, indent string, depth int) string {

res += `]`

if len(res) < logMaxFlowLength {
if len(res) < maxFlowLength {
return res
}
}
Expand All @@ -224,7 +219,7 @@ func logMessageIndent(v any, indent string, depth int) string {

for _, e := range v.elements {
res += indent + " "
res += logMessageIndent(e, indent+" ", depth+1) + ",\n"
res += logMessage(e, maxFlowLength, indent+" ", depth+1) + ",\n"
}

res += indent + `]`
Expand Down
100 changes: 92 additions & 8 deletions internal/bson2/logging_test.go
Expand Up @@ -51,14 +51,15 @@ func TestLogging(t *testing.T) {

for _, tc := range []struct {
name string
v slog.LogValuer
doc *Document
t string
j string
m string
b string
}{
{
name: "Numbers",
v: must.NotFail(NewDocument(
doc: must.NotFail(NewDocument(
"f64", 42.0,
"inf", float64(math.Inf(1)),
"neg_inf", float64(math.Inf(-1)),
Expand All @@ -81,10 +82,21 @@ func TestLogging(t *testing.T) {
"i32": 42,
"i64": int64(42),
}`,
b: `
{
"f64": 42.0,
"inf": +Inf,
"neg_inf": -Inf,
"zero": 0.0,
"neg_zero": -0.0,
"nan": NaN,
"i32": 42,
"i64": int64(42),
}`,
},
{
name: "Scalars",
v: must.NotFail(NewDocument(
doc: must.NotFail(NewDocument(
"null", Null,
"id", ObjectID{0x42},
"bool", true,
Expand All @@ -99,10 +111,17 @@ func TestLogging(t *testing.T) {
"bool": true,
"time": 2023-03-06T09:14:42.123Z,
}`,
b: `
{
"null": null,
"id": ObjectID(420000000000000000000000),
"bool": true,
"time": 2023-03-06T09:14:42.123Z,
}`,
},
{
name: "Composites",
v: must.NotFail(NewDocument(
doc: must.NotFail(NewDocument(
"doc", must.NotFail(NewDocument(
"foo", "bar",
"baz", must.NotFail(NewDocument(
Expand All @@ -128,10 +147,29 @@ func TestLogging(t *testing.T) {
"doc_empty": {},
"array": ["foo", "bar", ["baz", "qux"]],
}`,
b: `
{
"doc": {
"foo": "bar",
"baz": {
"qux": "quux",
},
},
"doc_raw": RawDocument<1>,
"doc_empty": {},
"array": [
"foo",
"bar",
[
"baz",
"qux",
],
],
}`,
},
{
name: "Nested",
v: makeNested(false, 20).(*Document),
doc: makeNested(false, 20).(*Document),
t: `v.f.0.f.0.f.0.f.0.f.0.f.0.f.0.f.0.f.0.f.0=<nil>`,
j: `{"v":{"f":{"0":{"f":{"0":{"f":{"0":{"f":{"0":{"f":{"0":{"f":{"0":` +
`{"f":{"0":{"f":{"0":{"f":{"0":{"f":{"0":null}}}}}}}}}}}}}}}}}}}}}`,
Expand All @@ -143,18 +181,64 @@ func TestLogging(t *testing.T) {
},
],
}`,
b: `
{
"f": [
{
"f": [
{
"f": [
{
"f": [
{
"f": [
{
"f": [
{
"f": [
{
"f": [
{
"f": [
{
"f": [
null,
],
},
],
},
],
},
],
},
],
},
],
},
],
},
],
},
],
},
],
}`,
},
} {
t.Run(tc.name, func(t *testing.T) {
tlog.InfoContext(ctx, "", slog.Any("v", tc.v))
tlog.InfoContext(ctx, "", slog.Any("v", tc.doc))
assert.Equal(t, tc.t+"\n", tbuf.String())
tbuf.Reset()

jlog.InfoContext(ctx, "", slog.Any("v", tc.v))
jlog.InfoContext(ctx, "", slog.Any("v", tc.doc))
assert.Equal(t, tc.j+"\n", jbuf.String())
jbuf.Reset()

assert.Equal(t, testutil.Unindent(t, tc.m), logMessage(tc.v))
m := tc.doc.LogMessage()
assert.Equal(t, testutil.Unindent(t, tc.m), m, "actual:\n%s", m)

b := tc.doc.LogMessageBlock()
assert.Equal(t, testutil.Unindent(t, tc.b), b, "actual:\n%s", b)
})
}
}
Expand Down
13 changes: 9 additions & 4 deletions internal/bson2/raw_array.go
Expand Up @@ -91,14 +91,19 @@ func (raw RawArray) decode(mode decodeMode) (*Array, error) {
}

// LogValue implements slog.LogValuer interface.
func (doc RawArray) LogValue() slog.Value {
return slogValue(doc, 1)
func (raw RawArray) LogValue() slog.Value {
return slogValue(raw, 1)
}

// LogMessage returns a representation as a string.
// It may change over time.
func (doc RawArray) LogMessage() string {
return logMessage(doc)
func (raw RawArray) LogMessage() string {
return logMessage(raw, logMaxFlowLength, "", 1)
}

// LogMessageBlock is a variant of [RawArray.LogMessage] that never uses a flow style.
func (raw RawArray) LogMessageBlock() string {
return logMessage(raw, 0, "", 1)
}

// check interfaces
Expand Down
13 changes: 9 additions & 4 deletions internal/bson2/raw_document.go
Expand Up @@ -162,14 +162,19 @@ func (raw RawDocument) decode(mode decodeMode) (*Document, error) {
}

// LogValue implements slog.LogValuer interface.
func (doc RawDocument) LogValue() slog.Value {
return slogValue(doc, 1)
func (raw RawDocument) LogValue() slog.Value {
return slogValue(raw, 1)
}

// LogMessage returns a representation as a string.
// It may change over time.
func (doc RawDocument) LogMessage() string {
return logMessage(doc)
func (raw RawDocument) LogMessage() string {
return logMessage(raw, logMaxFlowLength, "", 1)
}

// LogMessageBlock is a variant of [RawDocument.LogMessage] that never uses a flow style.
func (raw RawDocument) LogMessageBlock() string {
return logMessage(raw, 0, "", 1)
}

// check interfaces
Expand Down
4 changes: 2 additions & 2 deletions internal/clientconn/conn.go
Expand Up @@ -344,11 +344,11 @@ func (c *conn) run(ctx context.Context) (err error) {
var resBodyString, proxyBodyString string

if resBody != nil {
resBodyString = resBody.String()
resBodyString = resBody.StringBlock()
}

if proxyBody != nil {
proxyBodyString = proxyBody.String()
proxyBodyString = proxyBody.StringBlock()
}

var diffBody string
Expand Down
3 changes: 3 additions & 0 deletions internal/wire/msg_body.go
Expand Up @@ -40,6 +40,9 @@ type MsgBody interface {

encoding.BinaryMarshaler
fmt.Stringer

// StringBlock returns an indented string representation for logging.
StringBlock() string
}

// ErrZeroRead is returned when zero bytes was read from connection,
Expand Down
18 changes: 16 additions & 2 deletions internal/wire/op_msg.go
Expand Up @@ -421,8 +421,8 @@ func (msg *OpMsg) MarshalBinary() ([]byte, error) {
return b, nil
}

// String returns a string representation for logging.
func (msg *OpMsg) String() string {
// logMessage returns a string representation for logging.
func (msg *OpMsg) logMessage(block bool) string {
if msg == nil {
return "<nil>"
}
Expand Down Expand Up @@ -471,9 +471,23 @@ func (msg *OpMsg) String() string {

must.NoError(m.Add("Sections", sections))

if block {
return m.LogMessageBlock()
}

return m.LogMessage()
}

// String returns a string representation for logging.
func (msg *OpMsg) String() string {
return msg.logMessage(false)
}

// StringBlock returns an indented string representation for logging.
func (msg *OpMsg) StringBlock() string {
return msg.logMessage(true)
}

// check interfaces
var (
_ MsgBody = (*OpMsg)(nil)
Expand Down

0 comments on commit 9993f43

Please sign in to comment.