litble/Multi-Docker-Eval huggingface dataset:
Repository: polarsignals/frostdb (go)

Issue:
unsupport aggregation specific dynamic column
When I defined value column as dynamic column, I use select sum(value)  group by labels.method that is ok, but I use select sum(value.request)  group by labels.method that return: 
<details><summary>Details</summary>
<p>
        invalid aggregation
        Aggregation [sum(value.request)] Group: [labels.method]
          TableScan Table: 3469660e-d808-44bf-baf3-006abef8751d Projection: [] Filter: <nil> Distinct: []
          -> invalid expression: column not found: value.request: sum(value.request)

</p>
</details> 

I found logicalplan/validate.go no support dynamic clolumn:
```go
		column, found := schema.ColumnByName(named.Name())
		if !found {
			return &ExprValidationError{
				message: fmt.Sprintf("column not found: %s", named.Name()),
				expr:    expr,
			}
		}
``` 
The above code may need to be modified to support specific dynamic columns


Discussion:
Thank you for the report! 

Patch:
diff --git a/query/logicalplan/validate.go b/query/logicalplan/validate.go
--- a/query/logicalplan/validate.go
+++ b/query/logicalplan/validate.go
@@ -203,7 +203,8 @@ func ValidateAggregationExpr(plan *LogicalPlan) *ExprValidationError {
 			named = dynColFinder.result
 		}
 
-		column, found := schema.ColumnByName(named.Name())
+		name, _, _ := strings.Cut(named.Name(), ".")
+		column, found := schema.ColumnByName(name)
 		if !found {
 			return &ExprValidationError{
 				message: fmt.Sprintf("column not found: %s", named.Name()),


Test patch:
diff --git a/table_test.go b/table_test.go
--- a/table_test.go
+++ b/table_test.go
@@ -1165,3 +1165,60 @@ func TestTable_write_ptr_struct(t *testing.T) {
 	})
 	require.Nil(t, err)
 }
+
+func Test_Issue685(t *testing.T) {
+	c, err := New()
+	require.NoError(t, err)
+	t.Cleanup(func() {
+		c.Close()
+	})
+
+	db, err := c.DB(context.Background(), "test")
+	require.NoError(t, err)
+
+	type ColMap struct {
+		Value      map[string]int64
+		Attributes map[string]string
+	}
+	table, err := NewGenericTable[ColMap](
+		db, "test", memory.NewGoAllocator(),
+	)
+	require.NoError(t, err)
+	defer table.Release()
+
+	_, err = table.Write(context.Background(), ColMap{
+		Value: map[string]int64{
+			"age": 9999,
+		},
+		Attributes: map[string]string{
+			"age": "9999",
+		},
+	})
+	require.NoError(t, err)
+
+	_, err = table.Write(context.Background(), ColMap{
+		Value: map[string]int64{
+			"other": 1234,
+			"age":   3,
+		},
+		Attributes: map[string]string{
+			"age": "9999",
+		},
+	})
+	require.NoError(t, err)
+
+	engine := query.NewEngine(memory.NewGoAllocator(), db.TableProvider())
+	err = engine.ScanTable("test").
+		Aggregate(
+			[]logicalplan.Expr{
+				logicalplan.Sum(logicalplan.Col("value.age")),
+			},
+			nil,
+		).
+		Execute(context.Background(), func(ctx context.Context, r arrow.Record) error {
+			require.Equal(t, int64(1), r.NumRows())
+			require.Equal(t, int64(10002), r.Column(0).(*array.Int64).Value(0))
+			return nil
+		})
+	require.NoError(t, err)
+}
Repository: polarsignals/frostdb (go)

Issue:
An exception that generates an empty parquet file
If frostdb does not inject data and then closes frost db normally, it will generate an empty parquet file.
Because close frostdb will write active block，but active block is null，so generate an empty parquet file，blow logs:
<details><summary>Details</summary>
<p>

timestamp=2024-05-09T11:34:00.051+0800 level=info logger=smart caller=frostdb/db.go:1004 message="closing DB" component=frostdb
timestamp=2024-05-09T11:34:00.052+0800 level=error logger=smart caller=frostdb/table.go:514 message="failed to persist block" component=frostdb
timestamp=2024-05-09T11:34:00.052+0800 level=error logger=smart caller=frostdb/table.go:515 message="failed to upload block reading magic header of parquet file: EOF" component=frostdb

</p>
</details> 

<details><summary>Details</summary>
<p>

-rw-rw-r-- 1      0 5月   9 10:37 01HXDKDDGH00S0NG9NPA5J13H0.parquet
-rw-rw-r-- 1     0 5月   9 10:40 01HXDKHYEV95AYPSFPATATEABD.parquet
-rw-rw-r-- 1     0 5月   9 10:43 01HXDKRAC4JPK7PSH84HA21SZS.parquet


</p>
</details> 

Although Iceberg's Maintenance can clean up these useless files, it is best to check when writing parquet files to avoid the generation of useless files and logs


Discussion:

Patch:
diff --git a/table.go b/table.go
--- a/table.go
+++ b/table.go
@@ -506,7 +506,7 @@ func (t *Table) writeBlock(block *TableBlock, skipPersist, snapshotDB bool) {
 
 	// Persist the block
 	var err error
-	if !skipPersist {
+	if !skipPersist && block.index.Size() != 0 {
 		err = block.Persist()
 	}
 	t.dropPendingBlock(block)


Test patch:
diff --git a/db_test.go b/db_test.go
--- a/db_test.go
+++ b/db_test.go
@@ -3110,3 +3110,46 @@ func (b *TestBucket) GetRange(ctx context.Context, path string, offset, length i
 	b.Unlock()
 	return b.Bucket.GetRange(ctx, path, offset, length)
 }
+
+// Test_DB_EmptyPersist ensures that we don't write an empty block when the db is shutdown and there is no data.
+func Test_DB_EmptyPersist(t *testing.T) {
+	config := NewTableConfig(
+		dynparquet.SampleDefinition(),
+	)
+
+	logger := newTestLogger(t)
+	assertBucket := &AssertBucket{
+		Bucket: objstore.NewInMemBucket(),
+		uploadFunc: func(ctx context.Context, path string, r io.Reader) error {
+			t.Fatal("unexpected upload")
+			return nil
+		},
+	}
+
+	sinksource := NewDefaultObjstoreBucket(assertBucket)
+
+	c, err := New(
+		WithLogger(logger),
+		WithReadWriteStorage(sinksource),
+	)
+	require.NoError(t, err)
+	db, err := c.DB(context.Background(), "test")
+	require.NoError(t, err)
+	_, err = db.Table("test", config)
+	require.NoError(t, err)
+
+	require.NoError(t, c.Close())
+}
+
+type AssertBucket struct {
+	objstore.Bucket
+
+	uploadFunc func(ctx context.Context, path string, r io.Reader) error
+}
+
+func (a *AssertBucket) Upload(ctx context.Context, path string, r io.Reader) error {
+	if a.uploadFunc != nil {
+		return a.uploadFunc(ctx, path, r)
+	}
+	return a.Bucket.Upload(ctx, path, r)
+}
Repository: Altinity/clickhouse-backup (go)

Issue:
Make it so that Clean doesn't fail if shadow directory doesn't exist
Hi again,

I was wondering if you'd be OK with changing the backuper Clean function such that when the shadow directory doesn't exist, no error is returned. The reason why I'd like this change is that the shadow directory not existing is the end state for the Clean function, and so the absence of the shadow directory implies that the local directory is clean (if I am understanding this correctly...)

Currently, the behavior is that if you call the Clean function twice back to back with the initial state being an extant shadow directory, the second invocation will return an error.


Discussion:

Patch:
diff --git a/pkg/backup/delete.go b/pkg/backup/delete.go
--- a/pkg/backup/delete.go
+++ b/pkg/backup/delete.go
@@ -3,11 +3,6 @@ package backup
 import (
 	"context"
 	"fmt"
-	"github.com/Altinity/clickhouse-backup/pkg/custom"
-	"github.com/Altinity/clickhouse-backup/pkg/status"
-	"github.com/Altinity/clickhouse-backup/pkg/storage/object_disk"
-	"github.com/Altinity/clickhouse-backup/pkg/utils"
-	"github.com/pkg/errors"
 	"io/fs"
 	"os"
 	"path"
@@ -16,9 +11,14 @@ import (
 	"time"
 
 	"github.com/Altinity/clickhouse-backup/pkg/clickhouse"
+	"github.com/Altinity/clickhouse-backup/pkg/custom"
+	"github.com/Altinity/clickhouse-backup/pkg/status"
 	"github.com/Altinity/clickhouse-backup/pkg/storage"
+	"github.com/Altinity/clickhouse-backup/pkg/storage/object_disk"
+	"github.com/Altinity/clickhouse-backup/pkg/utils"
 
 	apexLog "github.com/apex/log"
+	"github.com/pkg/errors"
 )
 
 // Clean - removed all data in shadow folder
@@ -48,6 +48,9 @@ func (b *Backuper) Clean(ctx context.Context) error {
 
 func (b *Backuper) cleanDir(dirName string) error {
 	if items, err := os.ReadDir(dirName); err != nil {
+		if os.IsNotExist(err) {
+			return nil
+		}
 		return err
 	} else {
 		for _, item := range items {


Test patch:
diff --git a/pkg/backup/delete_test.go b/pkg/backup/delete_test.go
new file mode 100644
--- /dev/null
+++ b/pkg/backup/delete_test.go
@@ -0,0 +1,37 @@
+package backup
+
+import (
+	"os"
+	"path"
+	"testing"
+)
+
+func TestCleanDir(t *testing.T) {
+	t.Run("Test deletion of nonexistent directory",
+		func(t *testing.T) {
+			b := &Backuper{}
+
+			dir := path.Join(t.TempDir(), t.Name(), "does-not-exist")
+			if err := b.cleanDir(dir); err != nil {
+				t.Fatalf("unexpected error when deleting nonexistent dir: %v", err)
+			}
+		},
+	)
+
+	t.Run("Test deletion of existing directory",
+		func(t *testing.T) {
+			b := &Backuper{}
+
+			dir := t.TempDir()
+			if err := os.MkdirAll(dir, 0644); err != nil {
+				t.Fatalf("unexpected error while creating temporary directory: %v", err)
+			}
+			if err := b.cleanDir(dir); err != nil {
+				t.Fatalf("unexpected error while deleting existing dir: %v", err)
+			}
+			if err := b.cleanDir(dir); err != nil {
+				t.Fatalf("unexpected error during back to back invocation of delete: %v", err)
+			}
+		},
+	)
+}
Repository: uber-go/atomic (go)

Issue:
Add atomic.Bool which wraps an atomic.Int32



Discussion:

Patch:
diff --git a/atomic.go b/atomic.go
--- a/atomic.go
+++ b/atomic.go
@@ -195,3 +195,42 @@ func (i *Uint64) Store(n uint64) {
 func (i *Uint64) Swap(n uint64) uint64 {
 	return atomic.SwapUint64(&i.uint64, n)
 }
+
+// Bool is an atomic Boolean.
+type Bool struct{ uint32 }
+
+// NewBool creates a Bool.
+func NewBool(initial bool) *Bool {
+	return &Bool{boolToInt(initial)}
+}
+
+// Load atomically loads the Boolean.
+func (b *Bool) Load() bool {
+	return truthy(atomic.LoadUint32(&b.uint32))
+}
+
+// Store atomically stores the passed value.
+func (b *Bool) Store(new bool) {
+	atomic.StoreUint32(&b.uint32, boolToInt(new))
+}
+
+// Swap sets the given value and returns the previous value.
+func (b *Bool) Swap(new bool) bool {
+	return truthy(atomic.SwapUint32(&b.uint32, boolToInt(new)))
+}
+
+// Toggle atomically negates the Boolean and returns the previous value.
+func (b *Bool) Toggle() bool {
+	return truthy(atomic.AddUint32(&b.uint32, 1) - 1)
+}
+
+func truthy(n uint32) bool {
+	return n&1 == 1
+}
+
+func boolToInt(b bool) uint32 {
+	if b {
+		return 1
+	}
+	return 0
+}


Test patch:
diff --git a/atomic_test.go b/atomic_test.go
--- a/atomic_test.go
+++ b/atomic_test.go
@@ -97,3 +97,18 @@ func TestUint64(t *testing.T) {
 	atom.Store(42)
 	require.Equal(t, uint64(42), atom.Load(), "Store didn't set the correct value.")
 }
+
+func TestBool(t *testing.T) {
+	atom := NewBool(false)
+	require.False(t, atom.Toggle(), "Expected swap to return previous value.")
+	require.True(t, atom.Load(), "Unexpected state after swap.")
+
+	atom.Store(false)
+	require.False(t, atom.Load(), "Unexpected state after store.")
+
+	prev := atom.Swap(false)
+	require.False(t, prev, "Expected Swap to return previous value.")
+
+	prev = atom.Swap(true)
+	require.False(t, prev, "Expected Swap to return previous value.")
+}
diff --git a/stress_test.go b/stress_test.go
--- a/stress_test.go
+++ b/stress_test.go
@@ -99,3 +99,20 @@ func TestStressUint64(t *testing.T) {
 		}()
 	}
 }
+
+func TestStressBool(t *testing.T) {
+	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(_parallelism))
+	atom := NewBool(false)
+	for i := 0; i < _parallelism; i++ {
+		go func() {
+			for j := 0; j < _iterations; j++ {
+				atom.Load()
+				atom.Store(false)
+				atom.Swap(true)
+				atom.Load()
+				atom.Toggle()
+				atom.Toggle()
+			}
+		}()
+	}
+}
Repository: polarsignals/frostdb (go)

Issue:
why the test case " Benchmark_Table_Insert_100Rows_100Iters_100Writers" cannot pass  tests? 
Hi, frostdb is a great project, I use newest frostdb to benchmark table instert, i found  Benchmark_Table_Insert_100Rows_100Iters_100Writers(table_test.go) can't pass, output below wrong:
    table_test.go:278: 
        	Error Trace:	/media/vdc/workspace/src/github.com/polarsignals/frostdb/table_test.go:278
        	            				/media/vdc/workspace/src/github.com/polarsignals/frostdb/table_test.go:177
        	Error:      	Not equal: 
        	            	expected: 1000000
        	            	actual  : 528400
        	Test:       	Benchmark_Table_Insert_100Rows_100Iters_100Writers
--- FAIL: Benchmark_Table_Insert_100Rows_100Iters_100Writers-8

Benchmark_Table_Insert_1000Rows_10Iters_10Writers and Benchmark_Table_Insert_100Rows_1000Iters_1Writers  are passed


Discussion:
Hmm, thanks for catching this. This looks like a legitimate failure, we have to look into this.

Patch:
diff --git a/parts/part.go b/parts/part.go
--- a/parts/part.go
+++ b/parts/part.go
@@ -306,6 +306,7 @@ func FindMaximumNonOverlappingSet(schema *dynparquet.Schema, parts []*Part) ([]*
 	}
 	nonOverlapping := make([]*Part, 0, len(parts))
 	overlapping := make([]*Part, 0, len(parts))
+	var missing *Part
 	for i := 1; i < len(parts); i++ {
 		start, err := parts[i].Least()
 		if err != nil {
@@ -334,6 +335,10 @@ func FindMaximumNonOverlappingSet(schema *dynparquet.Schema, parts []*Part) ([]*
 			// The current part must be removed. Don't update prevEnd or prev,
 			// this will be used in the next iteration and must stay the same.
 			overlapping = append(overlapping, parts[i])
+
+			if i == len(parts)-1 { // This is the last iteration mark this one as missing
+				missing = parts[prev]
+			}
 		}
 	}
 	if len(overlapping) == 0 || overlapping[len(overlapping)-1] != parts[len(parts)-1] {
@@ -342,6 +347,8 @@ func FindMaximumNonOverlappingSet(schema *dynparquet.Schema, parts []*Part) ([]*
 		// previous part is in the overlapping slice). The last part must be
 		// appended to nonOverlapping.
 		nonOverlapping = append(nonOverlapping, parts[len(parts)-1])
+	} else if missing != nil {
+		overlapping = append(overlapping, missing)
 	}
 	return nonOverlapping, overlapping, nil
 }


Test patch:
diff --git a/parts/part_test.go b/parts/part_test.go
--- a/parts/part_test.go
+++ b/parts/part_test.go
@@ -74,6 +74,12 @@ func TestFindMaximumNonOverlappingSet(t *testing.T) {
 			expectedNonOverlapping: []rng{{1, 3}, {4, 5}, {6, 7}},
 			expectedOverlapping:    []rng{{2, 4}},
 		},
+		{
+			name:                   "OnlyTwoOverlap",
+			ranges:                 []rng{{1, 3}, {2, 4}},
+			expectedNonOverlapping: []rng{},
+			expectedOverlapping:    []rng{{2, 4}, {1, 3}},
+		},
 	} {
 		t.Run(tc.name, func(t *testing.T) {
 			parts := make([]*Part, len(tc.ranges))
Repository: stephenafamo/bob (go)

Issue:
Limit/offset should allow parameters
In SQL it is possible to use parameters for `LIMIT` and `OFFSET`, like `LIMIT $1`, but the current `Limit` function only accepts int64, maybe it should accept `any` like other functions so we could use `psql.Arg`?


Discussion:

Patch:
diff --git a/dialect/psql/dialect/select.go b/dialect/psql/dialect/select.go
--- a/dialect/psql/dialect/select.go
+++ b/dialect/psql/dialect/select.go
@@ -100,17 +100,19 @@ func (s SelectQuery) WriteSQL(w io.Writer, d bob.Dialect, start int) ([]any, err
 	}
 	args = append(args, orderArgs...)
 
-	_, err = bob.ExpressIf(w, d, start+len(args), s.Limit,
+	limitArgs, err := bob.ExpressIf(w, d, start+len(args), s.Limit,
 		s.Limit.Count != nil, "\n", "")
 	if err != nil {
 		return nil, err
 	}
+	args = append(args, limitArgs...)
 
-	_, err = bob.ExpressIf(w, d, start+len(args), s.Offset,
+	offsetArgs, err := bob.ExpressIf(w, d, start+len(args), s.Offset,
 		s.Offset.Count != nil, "\n", "")
 	if err != nil {
 		return nil, err
 	}
+	args = append(args, offsetArgs...)
 
 	_, err = bob.ExpressIf(w, d, start+len(args), s.Fetch,
 		s.Fetch.Count != nil, "\n", "")
diff --git a/dialect/psql/sm/qm.go b/dialect/psql/sm/qm.go
--- a/dialect/psql/sm/qm.go
+++ b/dialect/psql/sm/qm.go
@@ -104,13 +104,13 @@ func OrderBy(e any) dialect.OrderBy[*dialect.SelectQuery] {
 	})
 }
 
-func Limit(count int64) bob.Mod[*dialect.SelectQuery] {
+func Limit(count any) bob.Mod[*dialect.SelectQuery] {
 	return mods.Limit[*dialect.SelectQuery]{
 		Count: count,
 	}
 }
 
-func Offset(count int64) bob.Mod[*dialect.SelectQuery] {
+func Offset(count any) bob.Mod[*dialect.SelectQuery] {
 	return mods.Offset[*dialect.SelectQuery]{
 		Count: count,
 	}


Test patch:
diff --git a/dialect/psql/select_test.go b/dialect/psql/select_test.go
--- a/dialect/psql/select_test.go
+++ b/dialect/psql/select_test.go
@@ -110,6 +110,17 @@ func TestSelect(t *testing.T) {
 			ExpectedSQL:  "SELECT id, name FROM users WHERE (id, employee_id) IN (($1, $2), ($3, $4))",
 			ExpectedArgs: []any{100, 200, 300, 400},
 		},
+		"simple limit offset arg": {
+			Doc:          "Simple select with limit and offset as argument",
+			ExpectedSQL:  "SELECT id, name FROM users LIMIT $1 OFFSET $2",
+			ExpectedArgs: []any{10, 15},
+			Query: psql.Select(
+				sm.Columns("id", "name"),
+				sm.From("users"),
+				sm.Offset(psql.Arg(15)),
+				sm.Limit(psql.Arg(10)),
+			),
+		},
 	}
 
 	testutils.RunTests(t, examples, formatter)
Repository: kagkarlsson/db-scheduler (java)

Issue:
Recurring tasks without data get priority MEDIUM instead of HIGH
When a recurring task (without data / state) is scheduled, it gets priority MEDIUM (50), while if it has data / state, it gets priority HIGH (90), which matches the default priority for recurring tasks.

This seems like an oversight; recurring tasks should always get their default priority HIGH, no?


Discussion:

Patch:
diff --git a/db-scheduler/src/main/java/com/github/kagkarlsson/scheduler/task/AbstractTask.java b/db-scheduler/src/main/java/com/github/kagkarlsson/scheduler/task/AbstractTask.java
--- a/db-scheduler/src/main/java/com/github/kagkarlsson/scheduler/task/AbstractTask.java
+++ b/db-scheduler/src/main/java/com/github/kagkarlsson/scheduler/task/AbstractTask.java
@@ -50,12 +50,12 @@ public TaskInstance<T> instance(String id) {
 
   @Override
   public TaskInstance<T> instance(String id, T data) {
-    return instanceBuilder(id).priority(getDefaultPriority()).data(data).build();
+    return instanceBuilder(id).data(data).build();
   }
 
   @Override
   public TaskInstance.Builder<T> instanceBuilder(String id) {
-    return new Builder<>(this.name, id);
+    return new Builder<T>(this.name, id).priority(getDefaultPriority());
   }
 
   @Override


Test patch:
diff --git a/db-scheduler/src/test/java/com/github/kagkarlsson/scheduler/task/AbstractTaskTest.java b/db-scheduler/src/test/java/com/github/kagkarlsson/scheduler/task/AbstractTaskTest.java
new file mode 100644
--- /dev/null
+++ b/db-scheduler/src/test/java/com/github/kagkarlsson/scheduler/task/AbstractTaskTest.java
@@ -0,0 +1,39 @@
+package com.github.kagkarlsson.scheduler.task;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import com.github.kagkarlsson.scheduler.task.helper.RecurringTask;
+import com.github.kagkarlsson.scheduler.task.helper.Tasks;
+import com.github.kagkarlsson.scheduler.task.schedule.Daily;
+import java.time.LocalTime;
+import org.junit.jupiter.api.Test;
+
+class AbstractTaskTest {
+
+  @Test
+  void test_default_priority_with_data() {
+    RecurringTask<String> task =
+        Tasks.recurring("task", new Daily(LocalTime.MIDNIGHT), String.class)
+            .executeStateful((taskInstance, executionContext) -> "");
+
+    assertEquals(task.getDefaultPriority(), task.instance("id", "data").getPriority());
+  }
+
+  @Test
+  void test_default_priority_without_data() {
+    RecurringTask<Void> task =
+        Tasks.recurring("task", new Daily(LocalTime.MIDNIGHT))
+            .execute((taskInstance, executionContext) -> {});
+
+    assertEquals(task.getDefaultPriority(), task.instance("id").getPriority());
+  }
+
+  @Test
+  void test_default_priority_with_instance_builder() {
+    RecurringTask<Void> task =
+        Tasks.recurring("task", new Daily(LocalTime.MIDNIGHT))
+            .execute((taskInstance, executionContext) -> {});
+
+    assertEquals(task.getDefaultPriority(), task.instanceBuilder("id").build().getPriority());
+  }
+}
Repository: pinojs/pino-pretty (javascript)

Issue:
handle msg key wrongly
I use pino-pretty v2.2.0, pino v5.6.1
Origin pino can handle `msg` key properly, like this
```
pino().info({ msg: { a: 1 } })
// output includes 'msg: {a: 1}'
```
But when use pino-pretty, `msg` is outputted as `[object Object]`, code like this
```
pino({  prettyPrint: { forceColor: true } }).info({ msg: { a: 1 } })
```


Discussion:

Patch:
diff --git a/index.js b/index.js
--- a/index.js
+++ b/index.js
@@ -153,7 +153,7 @@ module.exports = function prettyFactory (options) {
 
     line += ': '
 
-    if (log[messageKey]) {
+    if (log[messageKey] && typeof log[messageKey] === 'string') {
       line += color.message(log[messageKey])
     }
 
@@ -190,7 +190,7 @@ module.exports = function prettyFactory (options) {
         }
       }
     } else {
-      line += filterObjects(log, messageKey, errorLikeObjectKeys)
+      line += filterObjects(log, typeof log[messageKey] === 'string' ? messageKey : undefined, errorLikeObjectKeys)
     }
 
     return line
@@ -207,7 +207,11 @@ module.exports = function prettyFactory (options) {
       errorLikeObjectKeys = errorLikeObjectKeys || []
 
       const keys = Object.keys(value)
-      const filteredKeys = [messageKey]
+      const filteredKeys = []
+
+      if (messageKey) {
+        filteredKeys.push(messageKey)
+      }
 
       if (excludeStandardKeys !== false) {
         Array.prototype.push.apply(filteredKeys, standardKeys)


Test patch:
diff --git a/test/basic.test.js b/test/basic.test.js
--- a/test/basic.test.js
+++ b/test/basic.test.js
@@ -5,7 +5,16 @@ const os = require('os')
 const test = require('tap').test
 const pino = require('pino')
 const dateformat = require('dateformat')
-const prettyFactory = require('../')
+const _prettyFactory = require('../')
+
+function prettyFactory (opts) {
+  if (!opts) {
+    opts = { colorize: false }
+  } else if (!opts.hasOwnProperty('colorize')) {
+    opts.colorize = false
+  }
+  return _prettyFactory(opts)
+}
 
 // All dates are computed from 'Fri, 30 Mar 2018 17:35:28 GMT'
 const epoch = 1522431328992
@@ -451,5 +460,30 @@ test('basic prettifier tests', (t) => {
     log.info('foo')
   })
 
+  t.test('prettifies msg object', (t) => {
+    t.plan(6)
+    const expectedLines = [
+      '    msg: {',
+      '      "b": {',
+      '        "c": "d"',
+      '      }',
+      '    }'
+    ]
+    const pretty = prettyFactory()
+    const log = pino({}, new Writable({
+      write (chunk, enc, cb) {
+        const formatted = pretty(chunk.toString())
+        const lines = formatted.split('\n')
+        t.is(lines.length, expectedLines.length + 2)
+        lines.shift(); lines.pop()
+        for (var i = 0; i < lines.length; i += 1) {
+          t.is(lines[i], expectedLines[i])
+        }
+        cb()
+      }
+    }))
+    log.info({ msg: { b: { c: 'd' } } })
+  })
+
   t.end()
 })