Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do not use the flow style in the diff output #4170

Merged
merged 2 commits into from Mar 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 6 additions & 1 deletion internal/bson2/array.go
Expand Up @@ -148,7 +148,12 @@
// 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)

Check warning on line 151 in internal/bson2/array.go

View check run for this annotation

Codecov / codecov/patch

internal/bson2/array.go#L151

Added line #L151 was not covered by tests
}

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

Check warning on line 156 in internal/bson2/array.go

View check run for this annotation

Codecov / codecov/patch

internal/bson2/array.go#L155-L156

Added lines #L155 - L156 were not covered by tests
}

// 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 @@
}

// 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)

Check warning on line 95 in internal/bson2/raw_array.go

View check run for this annotation

Codecov / codecov/patch

internal/bson2/raw_array.go#L94-L95

Added lines #L94 - L95 were not covered by tests
}

// 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)

Check warning on line 101 in internal/bson2/raw_array.go

View check run for this annotation

Codecov / codecov/patch

internal/bson2/raw_array.go#L100-L101

Added lines #L100 - L101 were not covered by tests
}

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

Check warning on line 106 in internal/bson2/raw_array.go

View check run for this annotation

Codecov / codecov/patch

internal/bson2/raw_array.go#L105-L106

Added lines #L105 - L106 were not covered by tests
}

// check interfaces
Expand Down
13 changes: 9 additions & 4 deletions internal/bson2/raw_document.go
Expand Up @@ -162,14 +162,19 @@
}

// 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 warning on line 177 in internal/bson2/raw_document.go

View check run for this annotation

Codecov / codecov/patch

internal/bson2/raw_document.go#L176-L177

Added lines #L176 - L177 were not covered by tests
}

// check interfaces
Expand Down
4 changes: 2 additions & 2 deletions internal/clientconn/conn.go
Expand Up @@ -344,11 +344,11 @@
var resBodyString, proxyBodyString string

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

Check warning on line 347 in internal/clientconn/conn.go

View check run for this annotation

Codecov / codecov/patch

internal/clientconn/conn.go#L347

Added line #L347 was not covered by tests
}

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

Check warning on line 351 in internal/clientconn/conn.go

View check run for this annotation

Codecov / codecov/patch

internal/clientconn/conn.go#L351

Added line #L351 was not covered by tests
}

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