Collect more metrics for aquery handling

Test: go test soong tests
Test: m nothing & verify metrics
Change-Id: Id19e004d90dfbaa1b1706c607d5250bf845c0f3b
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index 9ff6b52..9674ba2 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -32,6 +32,7 @@
 	"android/soong/starlark_fmt"
 
 	"github.com/google/blueprint"
+	"github.com/google/blueprint/metrics"
 
 	"android/soong/bazel"
 )
@@ -132,6 +133,10 @@
 	return fmt.Sprintf("cquery(%s,%s,%s)", c.label, c.requestType.Name(), c.configKey)
 }
 
+type invokeBazelContext interface {
+	GetEventHandler() *metrics.EventHandler
+}
+
 // BazelContext is a context object useful for interacting with Bazel during
 // the course of a build. Use of Bazel to evaluate part of the build graph
 // is referred to as a "mixed build". (Some modules are managed by Soong,
@@ -168,7 +173,7 @@
 	// Issues commands to Bazel to receive results for all cquery requests
 	// queued in the BazelContext. The ctx argument is optional and is only
 	// used for performance data collection
-	InvokeBazel(config Config, ctx *Context) error
+	InvokeBazel(config Config, ctx invokeBazelContext) error
 
 	// Returns true if Bazel handling is enabled for the module with the given name.
 	// Note that this only implies "bazel mixed build" allowlisting. The caller
@@ -188,7 +193,7 @@
 
 type bazelRunner interface {
 	createBazelCommand(config Config, paths *bazelPaths, runName bazel.RunName, command bazelCommand, extraFlags ...string) *exec.Cmd
-	issueBazelCommand(bazelCmd *exec.Cmd) (output string, errorMessage string, error error)
+	issueBazelCommand(bazelCmd *exec.Cmd, eventHandler *metrics.EventHandler) (output string, errorMessage string, error error)
 }
 
 type bazelPaths struct {
@@ -296,7 +301,7 @@
 	return result, nil
 }
 
-func (m MockBazelContext) InvokeBazel(_ Config, _ *Context) error {
+func (m MockBazelContext) InvokeBazel(_ Config, _ invokeBazelContext) error {
 	panic("unimplemented")
 }
 
@@ -414,7 +419,7 @@
 	panic("implement me")
 }
 
-func (n noopBazelContext) InvokeBazel(_ Config, _ *Context) error {
+func (n noopBazelContext) InvokeBazel(_ Config, _ invokeBazelContext) error {
 	panic("unimplemented")
 }
 
@@ -592,7 +597,7 @@
 	return cmd
 }
 
-func (r *mockBazelRunner) issueBazelCommand(bazelCmd *exec.Cmd) (string, string, error) {
+func (r *mockBazelRunner) issueBazelCommand(bazelCmd *exec.Cmd, _ *metrics.EventHandler) (string, string, error) {
 	if command, ok := r.tokens[bazelCmd]; ok {
 		return r.bazelCommandResults[command], "", nil
 	}
@@ -605,7 +610,9 @@
 // Returns (stdout, stderr, error). The first and second return values are strings
 // containing the stdout and stderr of the run command, and an error is returned if
 // the invocation returned an error code.
-func (r *builtinBazelRunner) issueBazelCommand(bazelCmd *exec.Cmd) (string, string, error) {
+func (r *builtinBazelRunner) issueBazelCommand(bazelCmd *exec.Cmd, eventHandler *metrics.EventHandler) (string, string, error) {
+	eventHandler.Begin("bazel command")
+	defer eventHandler.End("bazel command")
 	stderr := &bytes.Buffer{}
 	bazelCmd.Stderr = stderr
 	if output, err := bazelCmd.Output(); err != nil {
@@ -982,11 +989,10 @@
 
 // Issues commands to Bazel to receive results for all cquery requests
 // queued in the BazelContext.
-func (context *mixedBuildBazelContext) InvokeBazel(config Config, ctx *Context) error {
-	if ctx != nil {
-		ctx.EventHandler.Begin("bazel")
-		defer ctx.EventHandler.End("bazel")
-	}
+func (context *mixedBuildBazelContext) InvokeBazel(config Config, ctx invokeBazelContext) error {
+	eventHandler := ctx.GetEventHandler()
+	eventHandler.Begin("bazel")
+	defer eventHandler.End("bazel")
 
 	if metricsDir := context.paths.BazelMetricsDir(); metricsDir != "" {
 		if err := os.MkdirAll(metricsDir, 0777); err != nil {
@@ -1009,11 +1015,10 @@
 	return nil
 }
 
-func (context *mixedBuildBazelContext) runCquery(config Config, ctx *Context) error {
-	if ctx != nil {
-		ctx.EventHandler.Begin("cquery")
-		defer ctx.EventHandler.End("cquery")
-	}
+func (context *mixedBuildBazelContext) runCquery(config Config, ctx invokeBazelContext) error {
+	eventHandler := ctx.GetEventHandler()
+	eventHandler.Begin("cquery")
+	defer eventHandler.End("cquery")
 	soongInjectionPath := absolutePath(context.paths.injectedFilesDir())
 	mixedBuildsPath := filepath.Join(soongInjectionPath, "mixed_builds")
 	if _, err := os.Stat(mixedBuildsPath); os.IsNotExist(err) {
@@ -1038,7 +1043,7 @@
 
 	cqueryCommandWithFlag := context.createBazelCommand(config, context.paths, bazel.CqueryBuildRootRunName, cqueryCmd,
 		"--output=starlark", "--starlark:file="+absolutePath(cqueryFileRelpath))
-	cqueryOutput, cqueryErrorMessage, cqueryErr := context.issueBazelCommand(cqueryCommandWithFlag)
+	cqueryOutput, cqueryErrorMessage, cqueryErr := context.issueBazelCommand(cqueryCommandWithFlag, eventHandler)
 	if cqueryErr != nil {
 		return cqueryErr
 	}
@@ -1072,11 +1077,10 @@
 	return nil
 }
 
-func (context *mixedBuildBazelContext) runAquery(config Config, ctx *Context) error {
-	if ctx != nil {
-		ctx.EventHandler.Begin("aquery")
-		defer ctx.EventHandler.End("aquery")
-	}
+func (context *mixedBuildBazelContext) runAquery(config Config, ctx invokeBazelContext) error {
+	eventHandler := ctx.GetEventHandler()
+	eventHandler.Begin("aquery")
+	defer eventHandler.End("aquery")
 	// Issue an aquery command to retrieve action information about the bazel build tree.
 	//
 	// Use jsonproto instead of proto; actual proto parsing would require a dependency on Bazel's
@@ -1102,23 +1106,22 @@
 		}
 	}
 	aqueryOutput, _, err := context.issueBazelCommand(context.createBazelCommand(config, context.paths, bazel.AqueryBuildRootRunName, aqueryCmd,
-		extraFlags...))
+		extraFlags...), eventHandler)
 	if err != nil {
 		return err
 	}
-	context.buildStatements, context.depsets, err = bazel.AqueryBuildStatements([]byte(aqueryOutput))
+	context.buildStatements, context.depsets, err = bazel.AqueryBuildStatements([]byte(aqueryOutput), eventHandler)
 	return err
 }
 
-func (context *mixedBuildBazelContext) generateBazelSymlinks(config Config, ctx *Context) error {
-	if ctx != nil {
-		ctx.EventHandler.Begin("symlinks")
-		defer ctx.EventHandler.End("symlinks")
-	}
+func (context *mixedBuildBazelContext) generateBazelSymlinks(config Config, ctx invokeBazelContext) error {
+	eventHandler := ctx.GetEventHandler()
+	eventHandler.Begin("symlinks")
+	defer eventHandler.End("symlinks")
 	// Issue a build command of the phony root to generate symlink forests for dependencies of the
 	// Bazel build. This is necessary because aquery invocations do not generate this symlink forest,
 	// but some of symlinks may be required to resolve source dependencies of the build.
-	_, _, err := context.issueBazelCommand(context.createBazelCommand(config, context.paths, bazel.BazelBuildPhonyRootRunName, buildCmd))
+	_, _, err := context.issueBazelCommand(context.createBazelCommand(config, context.paths, bazel.BazelBuildPhonyRootRunName, buildCmd), eventHandler)
 	return err
 }
 
diff --git a/android/bazel_handler_test.go b/android/bazel_handler_test.go
index d971802..4a4ecb5 100644
--- a/android/bazel_handler_test.go
+++ b/android/bazel_handler_test.go
@@ -11,11 +11,18 @@
 	"android/soong/bazel/cquery"
 	analysis_v2_proto "prebuilts/bazel/common/proto/analysis_v2"
 
+	"github.com/google/blueprint/metrics"
 	"google.golang.org/protobuf/proto"
 )
 
 var testConfig = TestConfig("out", nil, "", nil)
 
+type testInvokeBazelContext struct{}
+
+func (t *testInvokeBazelContext) GetEventHandler() *metrics.EventHandler {
+	return &metrics.EventHandler{}
+}
+
 func TestRequestResultsAfterInvokeBazel(t *testing.T) {
 	label := "@//foo:bar"
 	cfg := configKey{"arm64_armv8-a", Android}
@@ -23,7 +30,7 @@
 		bazelCommand{command: "cquery", expression: "deps(@soong_injection//mixed_builds:buildroot, 2)"}: `@//foo:bar|arm64_armv8-a|android>>out/foo/bar.txt`,
 	})
 	bazelContext.QueueBazelRequest(label, cquery.GetOutputFiles, cfg)
-	err := bazelContext.InvokeBazel(testConfig, nil)
+	err := bazelContext.InvokeBazel(testConfig, &testInvokeBazelContext{})
 	if err != nil {
 		t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
 	}
@@ -37,7 +44,7 @@
 
 func TestInvokeBazelWritesBazelFiles(t *testing.T) {
 	bazelContext, baseDir := testBazelContext(t, map[bazelCommand]string{})
-	err := bazelContext.InvokeBazel(testConfig, nil)
+	err := bazelContext.InvokeBazel(testConfig, &testInvokeBazelContext{})
 	if err != nil {
 		t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
 	}
@@ -118,7 +125,7 @@
 		bazelContext, _ := testBazelContext(t, map[bazelCommand]string{
 			bazelCommand{command: "aquery", expression: "deps(@soong_injection//mixed_builds:buildroot)"}: string(data)})
 
-		err = bazelContext.InvokeBazel(testConfig, nil)
+		err = bazelContext.InvokeBazel(testConfig, &testInvokeBazelContext{})
 		if err != nil {
 			t.Fatalf("testCase #%d: did not expect error invoking Bazel, but got %s", i+1, err)
 		}
@@ -197,7 +204,7 @@
 func verifyExtraFlags(t *testing.T, config Config, expected string) string {
 	bazelContext, _ := testBazelContext(t, map[bazelCommand]string{})
 
-	err := bazelContext.InvokeBazel(config, nil)
+	err := bazelContext.InvokeBazel(config, &testInvokeBazelContext{})
 	if err != nil {
 		t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
 	}
diff --git a/bazel/aquery.go b/bazel/aquery.go
index 80cf70a..6a5e054 100644
--- a/bazel/aquery.go
+++ b/bazel/aquery.go
@@ -23,9 +23,11 @@
 	"sort"
 	"strings"
 
+	analysis_v2_proto "prebuilts/bazel/common/proto/analysis_v2"
+
+	"github.com/google/blueprint/metrics"
 	"github.com/google/blueprint/proptools"
 	"google.golang.org/protobuf/proto"
-	analysis_v2_proto "prebuilts/bazel/common/proto/analysis_v2"
 )
 
 type artifactId int
@@ -313,7 +315,7 @@
 // action graph, as described by the given action graph json proto.
 // BuildStatements are one-to-one with actions in the given action graph, and AqueryDepsets
 // are one-to-one with Bazel's depSetOfFiles objects.
-func AqueryBuildStatements(aqueryJsonProto []byte) ([]BuildStatement, []AqueryDepset, error) {
+func AqueryBuildStatements(aqueryJsonProto []byte, eventHandler *metrics.EventHandler) ([]BuildStatement, []AqueryDepset, error) {
 	aqueryProto := &analysis_v2_proto.ActionGraphContainer{}
 	err := proto.Unmarshal(aqueryJsonProto, aqueryProto)
 	if err != nil {
@@ -387,74 +389,92 @@
 				ParentId: pathFragmentId(protoPathFragments.ParentId)})
 
 	}
-	aqueryHandler, err := newAqueryHandler(aqueryResult)
-	if err != nil {
-		return nil, nil, err
-	}
 
-	var buildStatements []BuildStatement
-	for _, actionEntry := range aqueryResult.Actions {
-		if shouldSkipAction(actionEntry) {
-			continue
-		}
-
-		var buildStatement BuildStatement
-		if actionEntry.isSymlinkAction() {
-			buildStatement, err = aqueryHandler.symlinkActionBuildStatement(actionEntry)
-		} else if actionEntry.isTemplateExpandAction() && len(actionEntry.Arguments) < 1 {
-			buildStatement, err = aqueryHandler.templateExpandActionBuildStatement(actionEntry)
-		} else if actionEntry.isFileWriteAction() {
-			buildStatement, err = aqueryHandler.fileWriteActionBuildStatement(actionEntry)
-		} else if actionEntry.isSymlinkTreeAction() {
-			buildStatement, err = aqueryHandler.symlinkTreeActionBuildStatement(actionEntry)
-		} else if len(actionEntry.Arguments) < 1 {
-			return nil, nil, fmt.Errorf("received action with no command: [%s]", actionEntry.Mnemonic)
-		} else {
-			buildStatement, err = aqueryHandler.normalActionBuildStatement(actionEntry)
-		}
-
+	var aqueryHandler *aqueryArtifactHandler
+	{
+		eventHandler.Begin("init_handler")
+		defer eventHandler.End("init_handler")
+		aqueryHandler, err = newAqueryHandler(aqueryResult)
 		if err != nil {
 			return nil, nil, err
 		}
-		buildStatements = append(buildStatements, buildStatement)
+	}
+
+	var buildStatements []BuildStatement
+	{
+		eventHandler.Begin("build_statements")
+		defer eventHandler.End("build_statements")
+		for _, actionEntry := range aqueryResult.Actions {
+			if shouldSkipAction(actionEntry) {
+				continue
+			}
+
+			var buildStatement BuildStatement
+			if actionEntry.isSymlinkAction() {
+				buildStatement, err = aqueryHandler.symlinkActionBuildStatement(actionEntry)
+			} else if actionEntry.isTemplateExpandAction() && len(actionEntry.Arguments) < 1 {
+				buildStatement, err = aqueryHandler.templateExpandActionBuildStatement(actionEntry)
+			} else if actionEntry.isFileWriteAction() {
+				buildStatement, err = aqueryHandler.fileWriteActionBuildStatement(actionEntry)
+			} else if actionEntry.isSymlinkTreeAction() {
+				buildStatement, err = aqueryHandler.symlinkTreeActionBuildStatement(actionEntry)
+			} else if len(actionEntry.Arguments) < 1 {
+				err = fmt.Errorf("received action with no command: [%s]", actionEntry.Mnemonic)
+			} else {
+				buildStatement, err = aqueryHandler.normalActionBuildStatement(actionEntry)
+			}
+
+			if err != nil {
+				return nil, nil, err
+			}
+			buildStatements = append(buildStatements, buildStatement)
+		}
 	}
 
 	depsetsByHash := map[string]AqueryDepset{}
 	var depsets []AqueryDepset
-	for _, aqueryDepset := range aqueryHandler.depsetIdToAqueryDepset {
-		if prevEntry, hasKey := depsetsByHash[aqueryDepset.ContentHash]; hasKey {
-			// Two depsets collide on hash. Ensure that their contents are identical.
-			if !reflect.DeepEqual(aqueryDepset, prevEntry) {
-				return nil, nil, fmt.Errorf("two different depsets have the same hash: %v, %v", prevEntry, aqueryDepset)
+	{
+		eventHandler.Begin("depsets")
+		defer eventHandler.End("depsets")
+		for _, aqueryDepset := range aqueryHandler.depsetIdToAqueryDepset {
+			if prevEntry, hasKey := depsetsByHash[aqueryDepset.ContentHash]; hasKey {
+				// Two depsets collide on hash. Ensure that their contents are identical.
+				if !reflect.DeepEqual(aqueryDepset, prevEntry) {
+					return nil, nil, fmt.Errorf("two different depsets have the same hash: %v, %v", prevEntry, aqueryDepset)
+				}
+			} else {
+				depsetsByHash[aqueryDepset.ContentHash] = aqueryDepset
+				depsets = append(depsets, aqueryDepset)
 			}
-		} else {
-			depsetsByHash[aqueryDepset.ContentHash] = aqueryDepset
-			depsets = append(depsets, aqueryDepset)
 		}
 	}
 
-	// Build Statements and depsets must be sorted by their content hash to
-	// preserve determinism between builds (this will result in consistent ninja file
-	// output). Note they are not sorted by their original IDs nor their Bazel ordering,
-	// as Bazel gives nondeterministic ordering / identifiers in aquery responses.
-	sort.Slice(buildStatements, func(i, j int) bool {
-		// For build statements, compare output lists. In Bazel, each output file
-		// may only have one action which generates it, so this will provide
-		// a deterministic ordering.
-		outputs_i := buildStatements[i].OutputPaths
-		outputs_j := buildStatements[j].OutputPaths
-		if len(outputs_i) != len(outputs_j) {
-			return len(outputs_i) < len(outputs_j)
-		}
-		if len(outputs_i) == 0 {
-			// No outputs for these actions, so compare commands.
-			return buildStatements[i].Command < buildStatements[j].Command
-		}
-		// There may be multiple outputs, but the output ordering is deterministic.
-		return outputs_i[0] < outputs_j[0]
+	eventHandler.Do("build_statement_sort", func() {
+		// Build Statements and depsets must be sorted by their content hash to
+		// preserve determinism between builds (this will result in consistent ninja file
+		// output). Note they are not sorted by their original IDs nor their Bazel ordering,
+		// as Bazel gives nondeterministic ordering / identifiers in aquery responses.
+		sort.Slice(buildStatements, func(i, j int) bool {
+			// For build statements, compare output lists. In Bazel, each output file
+			// may only have one action which generates it, so this will provide
+			// a deterministic ordering.
+			outputs_i := buildStatements[i].OutputPaths
+			outputs_j := buildStatements[j].OutputPaths
+			if len(outputs_i) != len(outputs_j) {
+				return len(outputs_i) < len(outputs_j)
+			}
+			if len(outputs_i) == 0 {
+				// No outputs for these actions, so compare commands.
+				return buildStatements[i].Command < buildStatements[j].Command
+			}
+			// There may be multiple outputs, but the output ordering is deterministic.
+			return outputs_i[0] < outputs_j[0]
+		})
 	})
-	sort.Slice(depsets, func(i, j int) bool {
-		return depsets[i].ContentHash < depsets[j].ContentHash
+	eventHandler.Do("depset_sort", func() {
+		sort.Slice(depsets, func(i, j int) bool {
+			return depsets[i].ContentHash < depsets[j].ContentHash
+		})
 	})
 	return buildStatements, depsets, nil
 }
diff --git a/bazel/aquery_test.go b/bazel/aquery_test.go
index 4d1503e..c6b139e 100644
--- a/bazel/aquery_test.go
+++ b/bazel/aquery_test.go
@@ -21,8 +21,10 @@
 	"sort"
 	"testing"
 
-	"google.golang.org/protobuf/proto"
 	analysis_v2_proto "prebuilts/bazel/common/proto/analysis_v2"
+
+	"github.com/google/blueprint/metrics"
+	"google.golang.org/protobuf/proto"
 )
 
 func TestAqueryMultiArchGenrule(t *testing.T) {
@@ -136,7 +138,7 @@
 		t.Error(err)
 		return
 	}
-	actualbuildStatements, actualDepsets, _ := AqueryBuildStatements(data)
+	actualbuildStatements, actualDepsets, _ := AqueryBuildStatements(data, &metrics.EventHandler{})
 	var expectedBuildStatements []BuildStatement
 	for _, arch := range []string{"arm", "arm64", "x86", "x86_64"} {
 		expectedBuildStatements = append(expectedBuildStatements,
@@ -195,7 +197,7 @@
 		t.Error(err)
 		return
 	}
-	_, _, err = AqueryBuildStatements(data)
+	_, _, err = AqueryBuildStatements(data, &metrics.EventHandler{})
 	assertError(t, err, "undefined outputId 3")
 }
 
@@ -226,7 +228,7 @@
 		t.Error(err)
 		return
 	}
-	_, _, err = AqueryBuildStatements(data)
+	_, _, err = AqueryBuildStatements(data, &metrics.EventHandler{})
 	assertError(t, err, "undefined (not even empty) input depsetId 2")
 }
 
@@ -257,7 +259,7 @@
 		t.Error(err)
 		return
 	}
-	_, _, err = AqueryBuildStatements(data)
+	_, _, err = AqueryBuildStatements(data, &metrics.EventHandler{})
 	assertError(t, err, "undefined input depsetId 42 (referenced by depsetId 1)")
 }
 
@@ -288,7 +290,7 @@
 		t.Error(err)
 		return
 	}
-	_, _, err = AqueryBuildStatements(data)
+	_, _, err = AqueryBuildStatements(data, &metrics.EventHandler{})
 	assertError(t, err, "undefined input artifactId 3")
 }
 
@@ -319,7 +321,7 @@
 		t.Error(err)
 		return
 	}
-	_, _, err = AqueryBuildStatements(data)
+	_, _, err = AqueryBuildStatements(data, &metrics.EventHandler{})
 	assertError(t, err, "undefined path fragment id 3")
 }
 
@@ -352,7 +354,7 @@
 		t.Error(err)
 		return
 	}
-	actual, _, err := AqueryBuildStatements(data)
+	actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
 	if err != nil {
 		t.Errorf("Unexpected error %q", err)
 	}
@@ -402,7 +404,7 @@
 		t.Error(err)
 		return
 	}
-	_, _, err = AqueryBuildStatements(data)
+	_, _, err = AqueryBuildStatements(data, &metrics.EventHandler{})
 	assertError(t, err, `found multiple potential depfiles "two.d", "other.d"`)
 }
 
@@ -483,7 +485,7 @@
 		t.Error(err)
 		return
 	}
-	actualbuildStatements, actualDepsets, _ := AqueryBuildStatements(data)
+	actualbuildStatements, actualDepsets, _ := AqueryBuildStatements(data, &metrics.EventHandler{})
 
 	expectedBuildStatements := []BuildStatement{
 		{
@@ -538,7 +540,7 @@
 		t.Error(err)
 		return
 	}
-	actual, _, err := AqueryBuildStatements(data)
+	actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
 	if err != nil {
 		t.Errorf("Unexpected error %q", err)
 	}
@@ -594,7 +596,7 @@
 		t.Error(err)
 		return
 	}
-	actualBuildStatements, actualDepsets, _ := AqueryBuildStatements(data)
+	actualBuildStatements, actualDepsets, _ := AqueryBuildStatements(data, &metrics.EventHandler{})
 	if len(actualDepsets) != 1 {
 		t.Errorf("expected 1 depset but found %#v", actualDepsets)
 		return
@@ -681,7 +683,7 @@
 		t.Error(err)
 		return
 	}
-	actualBuildStatements, actualDepsets, _ := AqueryBuildStatements(data)
+	actualBuildStatements, actualDepsets, _ := AqueryBuildStatements(data, &metrics.EventHandler{})
 	if len(actualDepsets) != 0 {
 		t.Errorf("expected 0 depsets but found %#v", actualDepsets)
 		return
@@ -748,7 +750,7 @@
 		t.Error(err)
 		return
 	}
-	actualBuildStatements, actualDepsets, err := AqueryBuildStatements(data)
+	actualBuildStatements, actualDepsets, err := AqueryBuildStatements(data, &metrics.EventHandler{})
 	if err != nil {
 		t.Errorf("Unexpected error %q", err)
 	}
@@ -845,7 +847,7 @@
 		t.Error(err)
 		return
 	}
-	actual, _, err := AqueryBuildStatements(data)
+	actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
 
 	if err != nil {
 		t.Errorf("Unexpected error %q", err)
@@ -894,7 +896,7 @@
 		t.Error(err)
 		return
 	}
-	actual, _, err := AqueryBuildStatements(data)
+	actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
 	if err != nil {
 		t.Errorf("Unexpected error %q", err)
 	}
@@ -940,7 +942,7 @@
 		t.Error(err)
 		return
 	}
-	_, _, err = AqueryBuildStatements(data)
+	_, _, err = AqueryBuildStatements(data, &metrics.EventHandler{})
 	assertError(t, err, `Expect 1 input and 1 output to symlink action, got: input ["file" "other_file"], output ["symlink"]`)
 }
 
@@ -971,7 +973,7 @@
 		t.Error(err)
 		return
 	}
-	_, _, err = AqueryBuildStatements(data)
+	_, _, err = AqueryBuildStatements(data, &metrics.EventHandler{})
 	assertError(t, err, "undefined outputId 2")
 }
 
@@ -1004,7 +1006,7 @@
 		t.Error(err)
 		return
 	}
-	actual, _, err := AqueryBuildStatements(data)
+	actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
 	if err != nil {
 		t.Errorf("Unexpected error %q", err)
 	}
@@ -1046,7 +1048,7 @@
 		t.Error(err)
 		return
 	}
-	_, _, err = AqueryBuildStatements(data)
+	_, _, err = AqueryBuildStatements(data, &metrics.EventHandler{})
 	assertError(t, err, `Expect 1 output to template expand action, got: output []`)
 }
 
@@ -1074,7 +1076,7 @@
 		t.Error(err)
 		return
 	}
-	actual, _, err := AqueryBuildStatements(data)
+	actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
 	if err != nil {
 		t.Errorf("Unexpected error %q", err)
 	}
@@ -1111,7 +1113,7 @@
 		t.Error(err)
 		return
 	}
-	actual, _, err := AqueryBuildStatements(data)
+	actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
 	if err != nil {
 		t.Errorf("Unexpected error %q", err)
 	}