m/p/logtree: implement WithAddedStackDepth

This is a prerequisite to easily pass over trace-based events into
logtree. It allows a testing/Test.Helper()-like mechanism to skip some
stackframes within a call tree to the logger in order to log pertinent
log origins instead of a wrapper.

Change-Id: Ida9732f8505ff4a400e689045bea318a185f7983
Reviewed-on: https://review.monogon.dev/c/monogon/+/538
Reviewed-by: Leopold Schabel <leo@nexantic.com>
diff --git a/metropolis/pkg/logtree/logtree_test.go b/metropolis/pkg/logtree/logtree_test.go
index b900201..315dbc3 100644
--- a/metropolis/pkg/logtree/logtree_test.go
+++ b/metropolis/pkg/logtree/logtree_test.go
@@ -209,3 +209,31 @@
 		t.Fatalf("wanted entry %q, got %q", want, got)
 	}
 }
+
+func TestAddedStackDepth(t *testing.T) {
+	tree := New()
+	helper := func(msg string) {
+		tree.MustLeveledFor("main").WithAddedStackDepth(1).Infof("oh no: %s", msg)
+	}
+
+	// The next three lines are tested to be next to each other.
+	helper("it failed")
+	tree.MustLeveledFor("main").Infof("something else")
+
+	reader, err := tree.Read("main", WithBacklog(BacklogAllAvailable))
+	if err != nil {
+		t.Fatalf("Read: %v", err)
+	}
+	if want, got := 2, len(reader.Backlog); want != got {
+		t.Fatalf("wanted %d entries, got %d", want, got)
+	}
+	if want, got := "oh no: it failed", reader.Backlog[0].Leveled.MessagesJoined(); want != got {
+		t.Errorf("wanted entry %q, got %q", want, got)
+	}
+	if want, got := "something else", reader.Backlog[1].Leveled.MessagesJoined(); want != got {
+		t.Errorf("wanted entry %q, got %q", want, got)
+	}
+	if first, second := reader.Backlog[0].Leveled.line, reader.Backlog[1].Leveled.line; first+1 != second {
+		t.Errorf("first entry at %d, second at %d, wanted one after the other", first, second)
+	}
+}