Provide more reporting options to SkyFunctions 

With more specific information to be reported by Skyfunctions, e.g.,
to inform the build-event protocol on missing files, the EventHandler
interface is no longer enough. Therefore, provide an enriched context
for reporting events.

--
Change-Id: I2d06166fe4d5b9054e24ad8c752fafc039e3f9f8
Reviewed-on: https://cr.bazel.build/8794
PiperOrigin-RevId: 148463437
MOS_MIGRATED_REVID=148463437
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/AnalysisEnvironment.java b/src/main/java/com/google/devtools/build/lib/analysis/AnalysisEnvironment.java
index 3c02666..eb559ea 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/AnalysisEnvironment.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/AnalysisEnvironment.java
@@ -24,7 +24,7 @@
 import com.google.devtools.build.lib.actions.Root;
 import com.google.devtools.build.lib.analysis.buildinfo.BuildInfoFactory.BuildInfoKey;
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.vfs.PathFragment;
 import com.google.devtools.build.skyframe.SkyFunction;
 
@@ -38,10 +38,8 @@
  * names of any implementation of this class.
  */
 public interface AnalysisEnvironment extends ActionRegistry {
-  /**
-   * Returns a callback to be used in this build for reporting analysis errors.
-   */
-  EventHandler getEventHandler();
+  /** Returns a callback to be used in this build for reporting analysis errors. */
+  ExtendedEventHandler getEventHandler();
 
   /**
    * Returns whether any errors were reported to this instance.
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/BuildView.java b/src/main/java/com/google/devtools/build/lib/analysis/BuildView.java
index 77cefb5..df50202 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/BuildView.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/BuildView.java
@@ -48,7 +48,7 @@
 import com.google.devtools.build.lib.collect.nestedset.Order;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadCompatible;
 import com.google.devtools.build.lib.events.Event;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.events.StoredEventHandler;
 import com.google.devtools.build.lib.packages.AspectClass;
 import com.google.devtools.build.lib.packages.AspectDescriptor;
@@ -437,7 +437,7 @@
       List<String> aspects,
       Options viewOptions,
       TopLevelArtifactContext topLevelOptions,
-      EventHandler eventHandler,
+      ExtendedEventHandler eventHandler,
       EventBus eventBus)
       throws ViewCreationFailedException, InterruptedException {
     LOG.info("Starting analysis");
@@ -564,12 +564,12 @@
   }
 
   private AnalysisResult createResult(
-      EventHandler eventHandler,
+      ExtendedEventHandler eventHandler,
       LoadingResult loadingResult,
       TopLevelArtifactContext topLevelOptions,
       BuildView.Options viewOptions,
       SkyframeAnalysisResult skyframeAnalysisResult)
-          throws InterruptedException {
+      throws InterruptedException {
     Collection<Target> testsToRun = loadingResult.getTestsToRun();
     Collection<ConfiguredTarget> configuredTargets = skyframeAnalysisResult.getConfiguredTargets();
     Collection<AspectValue> aspects = skyframeAnalysisResult.getAspects();
@@ -806,8 +806,10 @@
    * <p>Preserves the original input ordering.
    */
   private List<TargetAndConfiguration> nodesForTopLevelTargets(
-      BuildConfigurationCollection configurations, Collection<Target> targets,
-      EventHandler eventHandler) throws InterruptedException {
+      BuildConfigurationCollection configurations,
+      Collection<Target> targets,
+      ExtendedEventHandler eventHandler)
+      throws InterruptedException {
     // We use a hash set here to remove duplicate nodes; this can happen for input files and package
     // groups.
     LinkedHashSet<TargetAndConfiguration> nodes = new LinkedHashSet<>(targets.size());
@@ -823,24 +825,23 @@
   }
 
   /**
-   * <p>If {@link BuildConfiguration.Options#trimConfigurations()} is true, transforms a collection
-   * of <Target, Configuration> pairs by trimming each target's
-   * configuration to only the fragments the target and its transitive dependencies need.
+   * If {@link BuildConfiguration.Options#trimConfigurations()} is true, transforms a collection of
+   * <Target, Configuration> pairs by trimming each target's configuration to only the fragments the
+   * target and its transitive dependencies need.
    *
    * <p>Else returns configurations that unconditionally include all fragments.
    *
    * <p>Preserves the original input order. Uses original (untrimmed) configurations for targets
    * that can't be evaluated (e.g. due to loading phase errors).
    *
-   * <p>This is suitable for feeding {@link ConfiguredTargetValue} keys: as general principle
-   * {@link ConfiguredTarget}s should have exactly as much information in their configurations as
-   * they need to evaluate and no more (e.g. there's no need for Android settings in a C++
-   * configured target).
+   * <p>This is suitable for feeding {@link ConfiguredTargetValue} keys: as general principle {@link
+   * ConfiguredTarget}s should have exactly as much information in their configurations as they need
+   * to evaluate and no more (e.g. there's no need for Android settings in a C++ configured target).
    */
   // TODO(bazel-team): error out early for targets that fail - untrimmed configurations should
   // never make it through analysis (and especially not seed ConfiguredTargetValues)
   private List<TargetAndConfiguration> getDynamicConfigurations(
-      Iterable<TargetAndConfiguration> inputs, EventHandler eventHandler)
+      Iterable<TargetAndConfiguration> inputs, ExtendedEventHandler eventHandler)
       throws InterruptedException {
     Map<Label, Target> labelsToTargets = new LinkedHashMap<>();
     // We'll get the configs from SkyframeExecutor#getConfigurations, which gets configurations
@@ -912,8 +913,9 @@
    * includes all fragments.
    */
   @VisibleForTesting
-  public BuildConfiguration getDynamicConfigurationForTesting(Target target,
-      BuildConfiguration config, EventHandler eventHandler) throws InterruptedException {
+  public BuildConfiguration getDynamicConfigurationForTesting(
+      Target target, BuildConfiguration config, ExtendedEventHandler eventHandler)
+      throws InterruptedException {
     return Iterables.getOnlyElement(getDynamicConfigurations(
         ImmutableList.<TargetAndConfiguration>of(new TargetAndConfiguration(target, config)),
         eventHandler)).getConfiguration();
@@ -962,7 +964,8 @@
   // For testing
   @VisibleForTesting
   public Iterable<ConfiguredTarget> getDirectPrerequisitesForTesting(
-      EventHandler eventHandler, ConfiguredTarget ct, BuildConfigurationCollection configurations)
+      ExtendedEventHandler eventHandler, ConfiguredTarget ct,
+      BuildConfigurationCollection configurations)
       throws EvalException, InvalidConfigurationException,
       InterruptedException, InconsistentAspectOrderException {
     return skyframeExecutor.getConfiguredTargets(
@@ -974,7 +977,8 @@
 
   @VisibleForTesting
   public OrderedSetMultimap<Attribute, Dependency> getDirectPrerequisiteDependenciesForTesting(
-      final EventHandler eventHandler, final ConfiguredTarget ct,
+      final ExtendedEventHandler eventHandler,
+      final ConfiguredTarget ct,
       BuildConfigurationCollection configurations)
       throws EvalException, InvalidConfigurationException, InterruptedException,
              InconsistentAspectOrderException {
@@ -1042,7 +1046,7 @@
    * present in this rule's attributes.
    */
   private ImmutableMap<Label, ConfigMatchingProvider> getConfigurableAttributeKeysForTesting(
-      EventHandler eventHandler, TargetAndConfiguration ctg) {
+      ExtendedEventHandler eventHandler, TargetAndConfiguration ctg) {
     if (!(ctg.getTarget() instanceof Rule)) {
       return ImmutableMap.of();
     }
@@ -1063,7 +1067,8 @@
   }
 
   private OrderedSetMultimap<Attribute, ConfiguredTarget> getPrerequisiteMapForTesting(
-      final EventHandler eventHandler, ConfiguredTarget target,
+      final ExtendedEventHandler eventHandler,
+      ConfiguredTarget target,
       BuildConfigurationCollection configurations)
       throws EvalException, InvalidConfigurationException,
              InterruptedException, InconsistentAspectOrderException {
@@ -1082,12 +1087,12 @@
   }
 
   /**
-   * Returns a configured target for the specified target and configuration. Returns {@code null}
-   * if something goes wrong.
+   * Returns a configured target for the specified target and configuration. Returns {@code null} if
+   * something goes wrong.
    */
   @VisibleForTesting
   public ConfiguredTarget getConfiguredTargetForTesting(
-      EventHandler eventHandler, Label label, BuildConfiguration config) {
+      ExtendedEventHandler eventHandler, Label label, BuildConfiguration config) {
     return skyframeExecutor.getConfiguredTargetForTesting(eventHandler, label, config);
   }
 
@@ -1114,7 +1119,8 @@
    * given configured target.
    */
   @VisibleForTesting
-  public RuleContext getRuleContextForTesting(EventHandler eventHandler, ConfiguredTarget target,
+  public RuleContext getRuleContextForTesting(ExtendedEventHandler eventHandler,
+      ConfiguredTarget target,
       AnalysisEnvironment env, BuildConfigurationCollection configurations)
       throws EvalException, InvalidConfigurationException, InterruptedException,
              InconsistentAspectOrderException {
@@ -1137,13 +1143,14 @@
   }
 
   /**
-   * For a configured target dependentTarget, returns the desired configured target
-   * that is depended upon. Useful for obtaining the a target with aspects
-   * required by the dependent.
+   * For a configured target dependentTarget, returns the desired configured target that is depended
+   * upon. Useful for obtaining the a target with aspects required by the dependent.
    */
   @VisibleForTesting
   public ConfiguredTarget getPrerequisiteConfiguredTargetForTesting(
-      EventHandler eventHandler, ConfiguredTarget dependentTarget, Label desiredTarget,
+      ExtendedEventHandler eventHandler,
+      ConfiguredTarget dependentTarget,
+      Label desiredTarget,
       BuildConfigurationCollection configurations)
       throws EvalException, InvalidConfigurationException, InterruptedException,
              InconsistentAspectOrderException {
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/CachingAnalysisEnvironment.java b/src/main/java/com/google/devtools/build/lib/analysis/CachingAnalysisEnvironment.java
index 7a768c9..426b00f 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/CachingAnalysisEnvironment.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/CachingAnalysisEnvironment.java
@@ -27,7 +27,7 @@
 import com.google.devtools.build.lib.analysis.buildinfo.BuildInfoFactory;
 import com.google.devtools.build.lib.analysis.buildinfo.BuildInfoFactory.BuildInfoKey;
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.events.StoredEventHandler;
 import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.lib.skyframe.BuildInfoCollectionValue;
@@ -78,7 +78,7 @@
 
   private boolean enabled = true;
   private MiddlemanFactory middlemanFactory;
-  private EventHandler errorEventListener;
+  private ExtendedEventHandler errorEventListener;
   private SkyFunction.Environment skyframeEnv;
   private Map<Artifact, String> artifacts;
 
@@ -88,9 +88,13 @@
    */
   final List<ActionAnalysisMetadata> actions = new ArrayList<>();
 
-  public CachingAnalysisEnvironment(ArtifactFactory artifactFactory,
-      ArtifactOwner owner, boolean isSystemEnv, boolean extendedSanityChecks,
-      EventHandler errorEventListener, SkyFunction.Environment env,
+  public CachingAnalysisEnvironment(
+      ArtifactFactory artifactFactory,
+      ArtifactOwner owner,
+      boolean isSystemEnv,
+      boolean extendedSanityChecks,
+      ExtendedEventHandler errorEventListener,
+      SkyFunction.Environment env,
       boolean allowRegisteringActions) {
     this.artifactFactory = artifactFactory;
     this.owner = Preconditions.checkNotNull(owner);
@@ -181,7 +185,7 @@
   }
 
   @Override
-  public EventHandler getEventHandler() {
+  public ExtendedEventHandler getEventHandler() {
     return errorEventListener;
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/SkyframePackageRootResolver.java b/src/main/java/com/google/devtools/build/lib/analysis/SkyframePackageRootResolver.java
index ce8a649..0a41135 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/SkyframePackageRootResolver.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/SkyframePackageRootResolver.java
@@ -17,7 +17,7 @@
 import com.google.devtools.build.lib.actions.PackageRootResolutionException;
 import com.google.devtools.build.lib.actions.PackageRootResolver;
 import com.google.devtools.build.lib.actions.Root;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.skyframe.SkyframeExecutor;
 import com.google.devtools.build.lib.vfs.PathFragment;
 import java.util.Map;
@@ -30,9 +30,9 @@
  */
 public final class SkyframePackageRootResolver implements PackageRootResolver {
   private final SkyframeExecutor executor;
-  private final EventHandler eventHandler;
+  private final ExtendedEventHandler eventHandler;
 
-  public SkyframePackageRootResolver(SkyframeExecutor executor, EventHandler eventHandler) {
+  public SkyframePackageRootResolver(SkyframeExecutor executor, ExtendedEventHandler eventHandler) {
     this.executor = executor;
     this.eventHandler = eventHandler;
   }
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigurationEnvironment.java b/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigurationEnvironment.java
index 2713eca..3378d6c 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigurationEnvironment.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigurationEnvironment.java
@@ -17,7 +17,7 @@
 import com.google.devtools.build.lib.analysis.BlazeDirectories;
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration.Fragment;
 import com.google.devtools.build.lib.cmdline.Label;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.packages.NoSuchPackageException;
 import com.google.devtools.build.lib.packages.NoSuchTargetException;
 import com.google.devtools.build.lib.packages.Package;
@@ -38,7 +38,7 @@
    * Returns an event handler to report errors to. Note that reporting an error does not cause the
    * computation to abort - you also need to throw an exception.
    */
-  EventHandler getEventHandler();
+  ExtendedEventHandler getEventHandler();
 
   /**
    * Returns a target for the given label, loading it if necessary, and throwing an exception if it
@@ -67,19 +67,21 @@
     private final LoadedPackageProvider packageProvider;
     private final BlazeDirectories blazeDirectories;
 
-    public TargetProviderEnvironment(PackageProvider packageProvider,
-        EventHandler eventHandler, BlazeDirectories blazeDirectories) {
+    public TargetProviderEnvironment(
+        PackageProvider packageProvider,
+        ExtendedEventHandler eventHandler,
+        BlazeDirectories blazeDirectories) {
       this.packageProvider = new LoadedPackageProvider(packageProvider, eventHandler);
       this.blazeDirectories = blazeDirectories;
     }
 
-    public TargetProviderEnvironment(PackageProvider packageProvider,
-        EventHandler eventHandler) {
+    public TargetProviderEnvironment(
+        PackageProvider packageProvider, ExtendedEventHandler eventHandler) {
       this(packageProvider, eventHandler, null);
     }
 
     @Override
-    public EventHandler getEventHandler() {
+    public ExtendedEventHandler getEventHandler() {
       return packageProvider.getEventHandler();
     }
 
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/PackageProviderForConfigurations.java b/src/main/java/com/google/devtools/build/lib/analysis/config/PackageProviderForConfigurations.java
index e493e48..ecbefd2 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/config/PackageProviderForConfigurations.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/config/PackageProviderForConfigurations.java
@@ -17,7 +17,7 @@
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration.Fragment;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.packages.NoSuchPackageException;
 import com.google.devtools.build.lib.packages.NoSuchTargetException;
 import com.google.devtools.build.lib.packages.Package;
@@ -28,7 +28,7 @@
  * A variant of PackageProvider which is used during a creation of BuildConfiguration.Fragments.
  */
 public interface PackageProviderForConfigurations {
-  EventHandler getEventHandler();
+  ExtendedEventHandler getEventHandler();
 
   /**
    * Adds dependency to fileName if needed. Used only in skyframe, for creating correct dependencies
diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/SkyframeBuilder.java b/src/main/java/com/google/devtools/build/lib/buildtool/SkyframeBuilder.java
index c74cfc80..038d951 100644
--- a/src/main/java/com/google/devtools/build/lib/buildtool/SkyframeBuilder.java
+++ b/src/main/java/com/google/devtools/build/lib/buildtool/SkyframeBuilder.java
@@ -31,7 +31,7 @@
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.TopLevelArtifactContext;
 import com.google.devtools.build.lib.buildtool.buildevent.ExecutionProgressReceiverAvailableEvent;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.events.Reporter;
 import com.google.devtools.build.lib.packages.BuildFileNotFoundException;
 import com.google.devtools.build.lib.rules.test.TestProvider;
@@ -226,15 +226,14 @@
   /**
    * Process the Skyframe update, taking into account the keepGoing setting.
    *
-   * <p> Returns optional {@link ExitCode} based on following conditions:
-   *    1. null, if result had no errors.
-   *    2. Optional.absent(), if result had errors but none of the errors specified an exit code.
-   *    3. Optional.of(e), if result had errors and one of them specified exit code 'e'.
-   * Throws on fail-fast failures.
+   * <p>Returns optional {@link ExitCode} based on following conditions: 1. null, if result had no
+   * errors. 2. Optional.absent(), if result had errors but none of the errors specified an exit
+   * code. 3. Optional.of(e), if result had errors and one of them specified exit code 'e'. Throws
+   * on fail-fast failures.
    */
   @Nullable
   private static Optional<ExitCode> processResult(
-      EventHandler eventHandler,
+      ExtendedEventHandler eventHandler,
       EvaluationResult<?> result,
       boolean keepGoing,
       SkyframeExecutor skyframeExecutor)
diff --git a/src/main/java/com/google/devtools/build/lib/events/DelegatingEventHandler.java b/src/main/java/com/google/devtools/build/lib/events/DelegatingEventHandler.java
index 9b09d23..84858e3 100644
--- a/src/main/java/com/google/devtools/build/lib/events/DelegatingEventHandler.java
+++ b/src/main/java/com/google/devtools/build/lib/events/DelegatingEventHandler.java
@@ -17,13 +17,13 @@
 import com.google.devtools.build.lib.util.Preconditions;
 
 /**
- * An EventHandler which delegates to another EventHandler.
- * Primarily useful as a base class for extending behavior.
+ * An EventHandler which delegates to another EventHandler. Primarily useful as a base class for
+ * extending behavior.
  */
-public class DelegatingEventHandler implements EventHandler {
-  protected final EventHandler delegate;
+public class DelegatingEventHandler implements ExtendedEventHandler {
+  protected final ExtendedEventHandler delegate;
 
-  public DelegatingEventHandler(EventHandler delegate) {
+  public DelegatingEventHandler(ExtendedEventHandler delegate) {
     super();
     this.delegate = Preconditions.checkNotNull(delegate);
   }
@@ -32,4 +32,9 @@
   public void handle(Event e) {
     delegate.handle(e);
   }
+
+  @Override
+  public void post(ExtendedEventHandler.Postable obj) {
+    delegate.post(obj);
+  }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/events/ErrorSensingEventHandler.java b/src/main/java/com/google/devtools/build/lib/events/ErrorSensingEventHandler.java
index fb12d76..3286efa 100644
--- a/src/main/java/com/google/devtools/build/lib/events/ErrorSensingEventHandler.java
+++ b/src/main/java/com/google/devtools/build/lib/events/ErrorSensingEventHandler.java
@@ -22,7 +22,7 @@
 
   private volatile boolean hasErrors;
 
-  public ErrorSensingEventHandler(EventHandler eventHandler) {
+  public ErrorSensingEventHandler(ExtendedEventHandler eventHandler) {
     super(eventHandler);
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/events/ExtendedEventHandler.java b/src/main/java/com/google/devtools/build/lib/events/ExtendedEventHandler.java
index 1457b58..f05cbab 100644
--- a/src/main/java/com/google/devtools/build/lib/events/ExtendedEventHandler.java
+++ b/src/main/java/com/google/devtools/build/lib/events/ExtendedEventHandler.java
@@ -16,13 +16,13 @@
 
 /**
  * Interface for reporting events during the build. It extends the {@link EventHandler} by also
- * allowing posting arbitrary objects on the event bus.
+ * allowing posting more structured information.
  */
 public interface ExtendedEventHandler extends EventHandler {
 
   /** Interface for declaring events that can be posted via the extended event handler */
   public interface Postable {}
 
-  /** Report arbitrary information over the event bus. */
+  /** Post an postable object with more refined information about an important build event */
   void post(Postable obj);
 }
diff --git a/src/main/java/com/google/devtools/build/lib/events/NullEventHandler.java b/src/main/java/com/google/devtools/build/lib/events/NullEventHandler.java
index c606219..522d350 100644
--- a/src/main/java/com/google/devtools/build/lib/events/NullEventHandler.java
+++ b/src/main/java/com/google/devtools/build/lib/events/NullEventHandler.java
@@ -14,15 +14,16 @@
 
 package com.google.devtools.build.lib.events;
 
-/**
- * An ErrorEventListener which does nothing.
- */
-public final class NullEventHandler implements EventHandler {
-  public static final EventHandler INSTANCE = new NullEventHandler();
+/** An ErrorEventListener which does nothing. */
+public final class NullEventHandler implements ExtendedEventHandler {
+  public static final ExtendedEventHandler INSTANCE = new NullEventHandler();
 
   private NullEventHandler() {}  // Prevent instantiation
 
   @Override
   public void handle(Event e) {
   }
+
+  @Override
+  public void post(ExtendedEventHandler.Postable e) {}
 }
diff --git a/src/main/java/com/google/devtools/build/lib/events/Reporter.java b/src/main/java/com/google/devtools/build/lib/events/Reporter.java
index a970d58..12039e3 100644
--- a/src/main/java/com/google/devtools/build/lib/events/Reporter.java
+++ b/src/main/java/com/google/devtools/build/lib/events/Reporter.java
@@ -13,31 +13,29 @@
 // limitations under the License.
 package com.google.devtools.build.lib.events;
 
+import com.google.common.eventbus.EventBus;
 import com.google.devtools.build.lib.util.Preconditions;
 import com.google.devtools.build.lib.util.io.OutErr;
-
 import java.io.PrintStream;
 import java.util.ArrayList;
 import java.util.List;
 
 /**
- * The reporter is the primary means of reporting events such as errors,
- * warnings, progress information and diagnostic information to the user.  It
- * is not intended as a logging mechanism for developer-only messages; use a
- * Logger for that.
+ * The reporter is the primary means of reporting events such as errors, warnings, progress
+ * information and diagnostic information to the user. It is not intended as a logging mechanism for
+ * developer-only messages; use a Logger for that.
  *
- * <p>The reporter instance is consumed by the build system, and passes events to
- * {@link EventHandler} instances. These handlers are registered via {@link
- * #addHandler(EventHandler)}. The reporter's main use is in the blaze runtime
- * and its lifetime is the lifetime of the blaze server.
+ * <p>The reporter instance is consumed by the build system, and passes events to {@link
+ * EventHandler} instances. These handlers are registered via {@link #addHandler(EventHandler)}. The
+ * reporter's main use is in the blaze runtime and its lifetime is the lifetime of the blaze server.
  *
- * <p>Thread-safe: calls to {@code #report} may be made on any thread.
- * Handlers may be run in an arbitary thread (but right now, they will not be
- * run concurrently).
+ * <p>Thread-safe: calls to {@code #report} may be made on any thread. Handlers may be run in an
+ * arbitary thread (but right now, they will not be run concurrently).
  */
-public final class Reporter implements EventHandler, ExceptionListener {
+public final class Reporter implements ExtendedEventHandler, ExceptionListener {
 
   private final List<EventHandler> handlers = new ArrayList<>();
+  private EventBus eventBus;
 
   /** An OutErr that sends all of its output to this Reporter.
    * Each write will (when flushed) get mapped to an EventKind.STDOUT or EventKind.STDERR event.
@@ -48,7 +46,9 @@
   private EventHandler ansiStrippingHandler;
   private boolean ansiAllowingHandlerRegistered;
 
-  public Reporter() {}
+  public Reporter(EventBus eventBus) {
+    this.eventBus = eventBus;
+  }
 
   public static OutErr outErrForReporter(EventHandler rep) {
     return OutErr.create(
@@ -64,12 +64,12 @@
    */
   public Reporter(Reporter template) {
     handlers.addAll(template.handlers);
+    this.eventBus = template.eventBus;
   }
 
-  /**
-   * Constructor which configures a reporter with the specified handlers.
-   */
-  public Reporter(EventHandler... handlers) {
+  /** Constructor which configures a reporter with the specified handlers. */
+  public Reporter(EventBus eventBus, EventHandler... handlers) {
+    this.eventBus = eventBus;
     for (EventHandler handler: handlers) {
       addHandler(handler);
     }
@@ -111,6 +111,17 @@
     }
   }
 
+  @Override
+  public void post(ExtendedEventHandler.Postable obj) {
+    if (eventBus != null) {
+      eventBus.post(obj);
+    }
+  }
+
+  public void clearEventBus() {
+    eventBus = null;
+  }
+
   /**
    * Reports the start of a particular task.
    * Is a wrapper around report() with event kind START.
diff --git a/src/main/java/com/google/devtools/build/lib/events/StoredEventHandler.java b/src/main/java/com/google/devtools/build/lib/events/StoredEventHandler.java
index 9edea8d..e68c5d2 100644
--- a/src/main/java/com/google/devtools/build/lib/events/StoredEventHandler.java
+++ b/src/main/java/com/google/devtools/build/lib/events/StoredEventHandler.java
@@ -14,16 +14,14 @@
 package com.google.devtools.build.lib.events;
 
 import com.google.common.collect.ImmutableList;
-
 import java.util.ArrayList;
 import java.util.List;
 
-/**
- * Stores error and warning events, and later replays them. Thread-safe.
- */
-public class StoredEventHandler implements EventHandler {
+/** Stores error and warning events, and later replays them. Thread-safe. */
+public class StoredEventHandler implements ExtendedEventHandler {
 
   private final List<Event> events = new ArrayList<>();
+  private final List<ExtendedEventHandler.Postable> posts = new ArrayList<>();
   private boolean hasErrors;
 
   public synchronized ImmutableList<Event> getEvents() {
@@ -32,7 +30,7 @@
 
   /** Returns true if there are no stored events. */
   public synchronized boolean isEmpty() {
-    return events.isEmpty();
+    return events.isEmpty() && posts.isEmpty();
   }
 
 
@@ -42,11 +40,17 @@
     events.add(e);
   }
 
-  /**
-   * Replay all events stored in this object on the given eventHandler, in the same order.
-   */
-  public synchronized void replayOn(EventHandler eventHandler) {
+  @Override
+  public synchronized void post(ExtendedEventHandler.Postable e) {
+    posts.add(e);
+  }
+
+  /** Replay all events stored in this object on the given eventHandler, in the same order. */
+  public synchronized void replayOn(ExtendedEventHandler eventHandler) {
     Event.replayEventsOn(eventHandler, events);
+    for (ExtendedEventHandler.Postable obj : posts) {
+      eventHandler.post(obj);
+    }
   }
 
   /**
@@ -58,6 +62,7 @@
 
   public synchronized void clear() {
     events.clear();
+    posts.clear();
     hasErrors = false;
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/packages/TestTargetUtils.java b/src/main/java/com/google/devtools/build/lib/packages/TestTargetUtils.java
index 8a6dafc..1ab2511 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/TestTargetUtils.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/TestTargetUtils.java
@@ -20,11 +20,10 @@
 import com.google.devtools.build.lib.cmdline.ResolvedTargets;
 import com.google.devtools.build.lib.cmdline.TargetParsingException;
 import com.google.devtools.build.lib.events.Event;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.pkgcache.TargetProvider;
 import com.google.devtools.build.lib.syntax.Type;
 import com.google.devtools.build.lib.util.Pair;
-
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
@@ -76,8 +75,8 @@
    * the specified languages. The reporter and the list of rule names are only used to warn about
    * unknown languages.
    */
-  public static Predicate<Target> testLangFilter(List<String> langFilterList,
-      EventHandler reporter, Set<String> allRuleNames) {
+  public static Predicate<Target> testLangFilter(
+      List<String> langFilterList, ExtendedEventHandler reporter, Set<String> allRuleNames) {
     final Set<String> requiredLangs = new HashSet<>();
     final Set<String> excludedLangs = new HashSet<>();
 
@@ -178,19 +177,22 @@
    * Returns the (new, mutable) set of test rules, expanding all 'test_suite' rules into the
    * individual tests they group together and preserving other test target instances.
    *
-   * Method assumes that passed collection contains only *_test and test_suite rules. While, at this
-   * point it will successfully preserve non-test rules as well, there is no guarantee that this
-   * behavior will be kept in the future.
+   * <p>Method assumes that passed collection contains only *_test and test_suite rules. While, at
+   * this point it will successfully preserve non-test rules as well, there is no guarantee that
+   * this behavior will be kept in the future.
    *
    * @param targetProvider a target provider
    * @param eventHandler a failure eventHandler to report loading failures to
    * @param targets Collection of the *_test and test_suite configured targets
    * @return a duplicate-free iterable of the tests under the specified targets
    */
-  public static ResolvedTargets<Target> expandTestSuites(TargetProvider targetProvider,
-      EventHandler eventHandler, Iterable<? extends Target> targets, boolean strict,
+  public static ResolvedTargets<Target> expandTestSuites(
+      TargetProvider targetProvider,
+      ExtendedEventHandler eventHandler,
+      Iterable<? extends Target> targets,
+      boolean strict,
       boolean keepGoing)
-          throws TargetParsingException {
+      throws TargetParsingException {
     Closure closure = new Closure(targetProvider, eventHandler, strict, keepGoing);
     ResolvedTargets.Builder<Target> result = ResolvedTargets.builder();
     for (Target target : targets) {
@@ -213,7 +215,7 @@
   private static final class Closure {
     private final TargetProvider targetProvider;
 
-    private final EventHandler eventHandler;
+    private final ExtendedEventHandler eventHandler;
 
     private final boolean keepGoing;
 
@@ -223,7 +225,10 @@
 
     private boolean hasError;
 
-    public Closure(TargetProvider targetProvider, EventHandler eventHandler, boolean strict,
+    public Closure(
+        TargetProvider targetProvider,
+        ExtendedEventHandler eventHandler,
+        boolean strict,
         boolean keepGoing) {
       this.targetProvider = targetProvider;
       this.eventHandler = eventHandler;
diff --git a/src/main/java/com/google/devtools/build/lib/pkgcache/CompileOneDependencyTransformer.java b/src/main/java/com/google/devtools/build/lib/pkgcache/CompileOneDependencyTransformer.java
index dd2bcbd..b23b62c 100644
--- a/src/main/java/com/google/devtools/build/lib/pkgcache/CompileOneDependencyTransformer.java
+++ b/src/main/java/com/google/devtools/build/lib/pkgcache/CompileOneDependencyTransformer.java
@@ -18,7 +18,7 @@
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.cmdline.ResolvedTargets;
 import com.google.devtools.build.lib.cmdline.TargetParsingException;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.packages.BuildType;
 import com.google.devtools.build.lib.packages.FileTarget;
 import com.google.devtools.build.lib.packages.NoSuchThingException;
@@ -50,7 +50,7 @@
    * input file as a source.
    */
   public ResolvedTargets<Target> transformCompileOneDependency(
-      EventHandler eventHandler, ResolvedTargets<Target> original)
+      ExtendedEventHandler eventHandler, ResolvedTargets<Target> original)
       throws TargetParsingException, InterruptedException {
     if (original.hasError()) {
       return original;
@@ -89,7 +89,7 @@
    * filegroups.
    */
   private boolean listContainsFile(
-      EventHandler eventHandler,
+      ExtendedEventHandler eventHandler,
       Collection<Label> srcLabels,
       Label source,
       Set<Label> visitedRuleLabels)
@@ -131,7 +131,7 @@
     return false;
   }
 
-  private Target transformCompileOneDependency(EventHandler eventHandler, Target target)
+  private Target transformCompileOneDependency(ExtendedEventHandler eventHandler, Target target)
       throws TargetParsingException, InterruptedException {
     if (!(target instanceof FileTarget)) {
       throw new TargetParsingException(
diff --git a/src/main/java/com/google/devtools/build/lib/pkgcache/LoadedPackageProvider.java b/src/main/java/com/google/devtools/build/lib/pkgcache/LoadedPackageProvider.java
index 09ad33d..f7fc7ca 100644
--- a/src/main/java/com/google/devtools/build/lib/pkgcache/LoadedPackageProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/pkgcache/LoadedPackageProvider.java
@@ -14,7 +14,7 @@
 package com.google.devtools.build.lib.pkgcache;
 
 import com.google.devtools.build.lib.cmdline.Label;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.packages.NoSuchPackageException;
 import com.google.devtools.build.lib.packages.NoSuchTargetException;
 import com.google.devtools.build.lib.packages.Target;
@@ -27,14 +27,14 @@
  */
 public final class LoadedPackageProvider {
   private final PackageProvider packageProvider;
-  private final EventHandler eventHandler;
+  private final ExtendedEventHandler eventHandler;
 
-  public LoadedPackageProvider(PackageProvider packageProvider, EventHandler eventHandler) {
+  public LoadedPackageProvider(PackageProvider packageProvider, ExtendedEventHandler eventHandler) {
     this.packageProvider = packageProvider;
     this.eventHandler = eventHandler;
   }
 
-  public EventHandler getEventHandler() {
+  public ExtendedEventHandler getEventHandler() {
     return eventHandler;
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/pkgcache/LoadingPhaseRunner.java b/src/main/java/com/google/devtools/build/lib/pkgcache/LoadingPhaseRunner.java
index 1ef720f..cb1936e 100644
--- a/src/main/java/com/google/devtools/build/lib/pkgcache/LoadingPhaseRunner.java
+++ b/src/main/java/com/google/devtools/build/lib/pkgcache/LoadingPhaseRunner.java
@@ -19,7 +19,7 @@
 import com.google.devtools.build.lib.cmdline.PackageIdentifier;
 import com.google.devtools.build.lib.cmdline.TargetParsingException;
 import com.google.devtools.build.lib.events.Event;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.packages.NonconfigurableAttributeMapper;
 import com.google.devtools.build.lib.packages.Package;
 import com.google.devtools.build.lib.packages.Rule;
@@ -49,7 +49,7 @@
 public abstract class LoadingPhaseRunner {
   /** Performs target pattern evaluation and test suite expansion (if requested). */
   public abstract LoadingResult execute(
-      EventHandler eventHandler,
+      ExtendedEventHandler eventHandler,
       EventBus eventBus,
       List<String> targetPatterns,
       PathFragment relativeWorkingDirectory,
@@ -80,7 +80,8 @@
    * <i>wanting</i> to build it are different things.
    */
   // Public for use by skyframe.TargetPatternPhaseFunction until this class goes away.
-  public static void maybeReportDeprecation(EventHandler eventHandler, Collection<Target> targets) {
+  public static void maybeReportDeprecation(
+      ExtendedEventHandler eventHandler, Collection<Target> targets) {
     for (Rule rule : Iterables.filter(targets, Rule.class)) {
       if (rule.isAttributeValueExplicitlySpecified("deprecation")) {
         eventHandler.handle(Event.warn(rule.getLocation(), String.format(
diff --git a/src/main/java/com/google/devtools/build/lib/pkgcache/PackageProvider.java b/src/main/java/com/google/devtools/build/lib/pkgcache/PackageProvider.java
index 23464b4..b44f6a1 100644
--- a/src/main/java/com/google/devtools/build/lib/pkgcache/PackageProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/pkgcache/PackageProvider.java
@@ -15,7 +15,7 @@
 package com.google.devtools.build.lib.pkgcache;
 
 import com.google.devtools.build.lib.cmdline.PackageIdentifier;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.packages.NoSuchPackageException;
 import com.google.devtools.build.lib.packages.Package;
 
@@ -27,21 +27,20 @@
 public interface PackageProvider extends TargetProvider {
 
   /**
-   * Returns the {@link Package} named "packageName". If there is no such package (e.g.
-   * {@code isPackage(packageName)} returns false), throws a {@link NoSuchPackageException}.
+   * Returns the {@link Package} named "packageName". If there is no such package (e.g. {@code
+   * isPackage(packageName)} returns false), throws a {@link NoSuchPackageException}.
    *
-   * <p>The returned package may contain lexical/grammatical errors, in which
-   * case <code>pkg.containsErrors() == true</code>.  Such packages may be
-   * missing some rules.  Any rules that are present may soundly be used for
-   * builds, though.
+   * <p>The returned package may contain lexical/grammatical errors, in which case <code>
+   * pkg.containsErrors() == true</code>. Such packages may be missing some rules. Any rules that
+   * are present may soundly be used for builds, though.
    *
-   * @param eventHandler the eventHandler on which to report warning and errors; if the package
-   *        has been loaded by another thread, this eventHandler won't see any warnings or errors
+   * @param eventHandler the eventHandler on which to report warning and errors; if the package has
+   *     been loaded by another thread, this eventHandler won't see any warnings or errors
    * @param packageName a legal package name.
    * @throws NoSuchPackageException if the package could not be found.
    * @throws InterruptedException if the package loading was interrupted.
    */
-  Package getPackage(EventHandler eventHandler, PackageIdentifier packageName)
+  Package getPackage(ExtendedEventHandler eventHandler, PackageIdentifier packageName)
       throws NoSuchPackageException, InterruptedException;
 
   /**
@@ -49,9 +48,9 @@
    * following hold
    *
    * <ol>
-   * <li>{@code packageName} is a valid package name
-   * <li>there is a BUILD file for the package
-   * <li>the package is not considered deleted via --deleted_packages
+   *   <li>{@code packageName} is a valid package name
+   *   <li>there is a BUILD file for the package
+   *   <li>the package is not considered deleted via --deleted_packages
    * </ol>
    *
    * <p>If these don't hold, then attempting to read the package with {@link #getPackage} may fail
@@ -60,6 +59,6 @@
    * @param eventHandler the eventHandler on which to report warnings and errors
    * @param packageName the name of the package.
    */
-  boolean isPackage(EventHandler eventHandler, PackageIdentifier packageName)
+  boolean isPackage(ExtendedEventHandler eventHandler, PackageIdentifier packageName)
       throws InterruptedException;
 }
diff --git a/src/main/java/com/google/devtools/build/lib/pkgcache/RecursivePackageProvider.java b/src/main/java/com/google/devtools/build/lib/pkgcache/RecursivePackageProvider.java
index bdf3baa..6366ebc 100644
--- a/src/main/java/com/google/devtools/build/lib/pkgcache/RecursivePackageProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/pkgcache/RecursivePackageProvider.java
@@ -16,7 +16,7 @@
 import com.google.common.collect.ImmutableSet;
 import com.google.devtools.build.lib.cmdline.PackageIdentifier;
 import com.google.devtools.build.lib.cmdline.RepositoryName;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.packages.NoSuchPackageException;
 import com.google.devtools.build.lib.packages.Package;
 import com.google.devtools.build.lib.vfs.PathFragment;
@@ -31,8 +31,9 @@
   /**
    * Returns the names of all the packages under a given directory.
    *
-   * <p>Packages returned by this method and passed into {@link #bulkGetPackages(EventHandler,
-   * Iterable)} are expected to return successful {@link Package} values.
+   * <p>Packages returned by this method and passed into {@link
+   * #bulkGetPackages(ExtendedEventHandler, Iterable)} are expected to return successful {@link
+   * Package} values.
    *
    * @param directory a {@link RootedPath} specifying the directory to search
    * @param excludedSubdirectories a set of {@link PathFragment}s, all of which are beneath {@code
@@ -44,22 +45,22 @@
       ImmutableSet<PathFragment> excludedSubdirectories)
       throws InterruptedException;
 
-
   /**
    * Returns the {@link Package} corresponding to each Package in "pkgIds". If any of the packages
-   * does not exist (e.g. {@code isPackage(pkgIds)} returns false), throws a
-   * {@link NoSuchPackageException}.
+   * does not exist (e.g. {@code isPackage(pkgIds)} returns false), throws a {@link
+   * NoSuchPackageException}.
    *
-   * <p>The returned package may contain lexical/grammatical errors, in which case
-   * <code>pkg.containsErrors() == true</code>.  Such packages may be missing some rules. Any rules
-   * that are present may soundly be used for builds, though.
+   * <p>The returned package may contain lexical/grammatical errors, in which case <code>
+   * pkg.containsErrors() == true</code>. Such packages may be missing some rules. Any rules that
+   * are present may soundly be used for builds, though.
    *
-   * @param eventHandler the eventHandler on which to report warning and errors; if the package
-   *        has been loaded by another thread, this eventHandler won't see any warnings or errors
+   * @param eventHandler the eventHandler on which to report warning and errors; if the package has
+   *     been loaded by another thread, this eventHandler won't see any warnings or errors
    * @param pkgIds an Iterable of PackageIdentifier objects.
    * @throws NoSuchPackageException if any package could not be found.
    * @throws InterruptedException if the package loading was interrupted.
    */
-  Map<PackageIdentifier, Package> bulkGetPackages(EventHandler eventHandler,
-          Iterable<PackageIdentifier> pkgIds) throws NoSuchPackageException, InterruptedException;
+  Map<PackageIdentifier, Package> bulkGetPackages(
+      ExtendedEventHandler eventHandler, Iterable<PackageIdentifier> pkgIds)
+      throws NoSuchPackageException, InterruptedException;
 }
diff --git a/src/main/java/com/google/devtools/build/lib/pkgcache/TargetPatternEvaluator.java b/src/main/java/com/google/devtools/build/lib/pkgcache/TargetPatternEvaluator.java
index 63de060..a9e69bd 100644
--- a/src/main/java/com/google/devtools/build/lib/pkgcache/TargetPatternEvaluator.java
+++ b/src/main/java/com/google/devtools/build/lib/pkgcache/TargetPatternEvaluator.java
@@ -19,10 +19,9 @@
 import com.google.devtools.build.lib.cmdline.TargetParsingException;
 import com.google.devtools.build.lib.concurrent.ThreadSafety;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadHostile;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.lib.vfs.PathFragment;
-
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
@@ -46,27 +45,28 @@
   static FilteringPolicy DEFAULT_FILTERING_POLICY = FilteringPolicies.NO_FILTER;
 
   /**
-   * Attempts to parse an ordered list of target patterns, computing the union
-   * of the set of targets represented by each pattern, unless it is preceded by
-   * "-", in which case the set difference is computed.  Implements the
-   * specification described in the class-level comment.
+   * Attempts to parse an ordered list of target patterns, computing the union of the set of targets
+   * represented by each pattern, unless it is preceded by "-", in which case the set difference is
+   * computed. Implements the specification described in the class-level comment.
    */
-  ResolvedTargets<Target> parseTargetPatternList(EventHandler eventHandler,
-      List<String> targetPatterns, FilteringPolicy policy, boolean keepGoing)
+  ResolvedTargets<Target> parseTargetPatternList(
+      ExtendedEventHandler eventHandler,
+      List<String> targetPatterns,
+      FilteringPolicy policy,
+      boolean keepGoing)
       throws TargetParsingException, InterruptedException;
 
   /**
-  * Attempts to parse a single target pattern while consulting the package
-   * cache to check for the existence of packages and directories and the build
-   * targets in them.  Implements the specification described in the
-   * class-level comment.  Returns a {@link ResolvedTargets} object.
+   * Attempts to parse a single target pattern while consulting the package cache to check for the
+   * existence of packages and directories and the build targets in them. Implements the
+   * specification described in the class-level comment. Returns a {@link ResolvedTargets} object.
    *
-   * <p>If an error is encountered, a {@link TargetParsingException} is thrown,
-   * unless {@code keepGoing} is set to true. In that case, the returned object
-   * will have its error bit set.
+   * <p>If an error is encountered, a {@link TargetParsingException} is thrown, unless {@code
+   * keepGoing} is set to true. In that case, the returned object will have its error bit set.
    */
-  ResolvedTargets<Target> parseTargetPattern(EventHandler eventHandler, String pattern,
-      boolean keepGoing) throws TargetParsingException, InterruptedException;
+  ResolvedTargets<Target> parseTargetPattern(
+      ExtendedEventHandler eventHandler, String pattern, boolean keepGoing)
+      throws TargetParsingException, InterruptedException;
 
   /**
    * Attempts to parse and load the given collection of patterns; the returned map contains the
@@ -76,9 +76,9 @@
    * keepGoing} is set to true. In that case, the patterns that failed to load have the error flag
    * set.
    */
-  Map<String, ResolvedTargets<Target>> preloadTargetPatterns(EventHandler eventHandler,
-      Collection<String> patterns, boolean keepGoing)
-          throws TargetParsingException, InterruptedException;
+  Map<String, ResolvedTargets<Target>> preloadTargetPatterns(
+      ExtendedEventHandler eventHandler, Collection<String> patterns, boolean keepGoing)
+      throws TargetParsingException, InterruptedException;
 
   /**
    * Update the parser's offset, given the workspace and working directory.
diff --git a/src/main/java/com/google/devtools/build/lib/pkgcache/TargetProvider.java b/src/main/java/com/google/devtools/build/lib/pkgcache/TargetProvider.java
index 35dbb84..e369ed4 100644
--- a/src/main/java/com/google/devtools/build/lib/pkgcache/TargetProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/pkgcache/TargetProvider.java
@@ -15,7 +15,7 @@
 package com.google.devtools.build.lib.pkgcache;
 
 import com.google.devtools.build.lib.cmdline.Label;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.packages.NoSuchPackageException;
 import com.google.devtools.build.lib.packages.NoSuchTargetException;
 import com.google.devtools.build.lib.packages.Target;
@@ -31,10 +31,10 @@
    * not already loaded.
    *
    * @throws NoSuchPackageException if the package could not be found
-   * @throws NoSuchTargetException if the package was loaded successfully, but
-   *         the specified {@link Target} was not found in it
+   * @throws NoSuchTargetException if the package was loaded successfully, but the specified {@link
+   *     Target} was not found in it
    * @throws InterruptedException if the package loading was interrupted
    */
-  Target getTarget(EventHandler eventHandler, Label label) throws NoSuchPackageException,
-      NoSuchTargetException, InterruptedException;
+  Target getTarget(ExtendedEventHandler eventHandler, Label label)
+      throws NoSuchPackageException, NoSuchTargetException, InterruptedException;
 }
diff --git a/src/main/java/com/google/devtools/build/lib/pkgcache/TestFilter.java b/src/main/java/com/google/devtools/build/lib/pkgcache/TestFilter.java
index e00dc3d..ee18660 100644
--- a/src/main/java/com/google/devtools/build/lib/pkgcache/TestFilter.java
+++ b/src/main/java/com/google/devtools/build/lib/pkgcache/TestFilter.java
@@ -15,17 +15,15 @@
 
 import com.google.common.base.Predicate;
 import com.google.common.base.Predicates;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.lib.packages.TargetUtils;
 import com.google.devtools.build.lib.packages.TestSize;
 import com.google.devtools.build.lib.packages.TestTargetUtils;
 import com.google.devtools.build.lib.packages.TestTimeout;
-
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
-
 import javax.annotation.Nullable;
 
 /**
@@ -33,11 +31,9 @@
  * Implements {@link #hashCode} and {@link #equals} so it can be used as a Skyframe key.
  */
 public final class TestFilter implements Predicate<Target> {
-  /**
-   * Convert the options into a test filter.
-   */
-  public static TestFilter forOptions(LoadingOptions options, EventHandler eventHandler,
-      Set<String> ruleNames) {
+  /** Convert the options into a test filter. */
+  public static TestFilter forOptions(
+      LoadingOptions options, ExtendedEventHandler eventHandler, Set<String> ruleNames) {
     Predicate<Target> testFilter = Predicates.alwaysTrue();
     if (!options.testSizeFilterSet.isEmpty()) {
       testFilter = Predicates.and(testFilter,
diff --git a/src/main/java/com/google/devtools/build/lib/pkgcache/TransitivePackageLoader.java b/src/main/java/com/google/devtools/build/lib/pkgcache/TransitivePackageLoader.java
index 0b40bda8..d76cbf9 100644
--- a/src/main/java/com/google/devtools/build/lib/pkgcache/TransitivePackageLoader.java
+++ b/src/main/java/com/google/devtools/build/lib/pkgcache/TransitivePackageLoader.java
@@ -14,7 +14,7 @@
 package com.google.devtools.build.lib.pkgcache;
 
 import com.google.devtools.build.lib.cmdline.Label;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import java.util.Set;
 
 /**
@@ -23,17 +23,19 @@
 public interface TransitivePackageLoader {
 
   /**
-   * Visit the specified labels and follow the transitive closure of their
-   * outbound dependencies. If the targets have previously been visited,
-   * may do an up-to-date check which will not trigger any of the observers.
+   * Visit the specified labels and follow the transitive closure of their outbound dependencies. If
+   * the targets have previously been visited, may do an up-to-date check which will not trigger any
+   * of the observers.
    *
    * @param eventHandler the error and warnings eventHandler; must be thread-safe
    * @param labelsToVisit the labels to visit in addition to the targets
    * @param keepGoing if false, stop visitation upon first error
    * @param parallelThreads number of threads to use in the visitation
    */
-  boolean sync(EventHandler eventHandler,
-               Set<Label> labelsToVisit,
-               boolean keepGoing,
-               int parallelThreads) throws InterruptedException;
+  boolean sync(
+      ExtendedEventHandler eventHandler,
+      Set<Label> labelsToVisit,
+      boolean keepGoing,
+      int parallelThreads)
+      throws InterruptedException;
 }
diff --git a/src/main/java/com/google/devtools/build/lib/query2/AbstractBlazeQueryEnvironment.java b/src/main/java/com/google/devtools/build/lib/query2/AbstractBlazeQueryEnvironment.java
index 696eee2..644adcf 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/AbstractBlazeQueryEnvironment.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/AbstractBlazeQueryEnvironment.java
@@ -21,7 +21,7 @@
 import com.google.devtools.build.lib.cmdline.TargetParsingException;
 import com.google.devtools.build.lib.events.ErrorSensingEventHandler;
 import com.google.devtools.build.lib.events.Event;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.packages.DependencyFilter;
 import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.lib.query2.engine.OutputFormatterCallback;
@@ -63,10 +63,11 @@
   private static final Logger logger =
       Logger.getLogger(AbstractBlazeQueryEnvironment.class.getName());
 
-  protected AbstractBlazeQueryEnvironment(boolean keepGoing,
+  protected AbstractBlazeQueryEnvironment(
+      boolean keepGoing,
       boolean strictScope,
       Predicate<Label> labelFilter,
-      EventHandler eventHandler,
+      ExtendedEventHandler eventHandler,
       Set<Setting> settings,
       Iterable<QueryFunction> extraFunctions,
       QueryExpressionEvalListener<T> evalListener) {
diff --git a/src/main/java/com/google/devtools/build/lib/query2/BlazeQueryEnvironment.java b/src/main/java/com/google/devtools/build/lib/query2/BlazeQueryEnvironment.java
index eb39b01..867ec3d 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/BlazeQueryEnvironment.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/BlazeQueryEnvironment.java
@@ -22,7 +22,7 @@
 import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
 import com.google.devtools.build.lib.cmdline.ResolvedTargets;
 import com.google.devtools.build.lib.cmdline.TargetParsingException;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.graph.Digraph;
 import com.google.devtools.build.lib.graph.Node;
 import com.google.devtools.build.lib.packages.Attribute;
@@ -89,22 +89,24 @@
   /**
    * Note that the correct operation of this class critically depends on the Reporter being a
    * singleton object, shared by all cooperating classes contributing to Query.
+   *
    * @param strictScope if true, fail the whole query if a label goes out of scope.
-   * @param loadingPhaseThreads the number of threads to use during loading
-   *     the packages for the query.
-   * @param labelFilter a predicate that determines if a specific label is
-   *     allowed to be visited during query execution. If it returns false,
-   *     the query execution is stopped with an error message.
+   * @param loadingPhaseThreads the number of threads to use during loading the packages for the
+   *     query.
+   * @param labelFilter a predicate that determines if a specific label is allowed to be visited
+   *     during query execution. If it returns false, the query execution is stopped with an error
+   *     message.
    * @param settings a set of enabled settings
    */
-  BlazeQueryEnvironment(TransitivePackageLoader transitivePackageLoader,
+  BlazeQueryEnvironment(
+      TransitivePackageLoader transitivePackageLoader,
       TargetProvider targetProvider,
       TargetPatternEvaluator targetPatternEvaluator,
       boolean keepGoing,
       boolean strictScope,
       int loadingPhaseThreads,
       Predicate<Label> labelFilter,
-      EventHandler eventHandler,
+      ExtendedEventHandler eventHandler,
       Set<Setting> settings,
       Iterable<QueryFunction> extraFunctions,
       QueryExpressionEvalListener<Target> evalListener) {
diff --git a/src/main/java/com/google/devtools/build/lib/query2/LabelVisitor.java b/src/main/java/com/google/devtools/build/lib/query2/LabelVisitor.java
index aa84dee..80785ca 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/LabelVisitor.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/LabelVisitor.java
@@ -24,7 +24,7 @@
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.concurrent.AbstractQueueVisitor;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.packages.AggregatingAttributeMapper;
 import com.google.devtools.build.lib.packages.AspectDefinition;
 import com.google.devtools.build.lib.packages.Attribute;
@@ -208,9 +208,14 @@
     this.edgeFilter = edgeFilter;
   }
 
-  boolean syncWithVisitor(EventHandler eventHandler, Collection<Target> targetsToVisit,
-      boolean keepGoing, int parallelThreads, int maxDepth, TargetEdgeObserver... observers)
-          throws InterruptedException {
+  boolean syncWithVisitor(
+      ExtendedEventHandler eventHandler,
+      Collection<Target> targetsToVisit,
+      boolean keepGoing,
+      int parallelThreads,
+      int maxDepth,
+      TargetEdgeObserver... observers)
+      throws InterruptedException {
     VisitationAttributes nextVisitation = new VisitationAttributes();
     nextVisitation.targetsToVisit = targetsToVisit;
     nextVisitation.maxDepth = maxDepth;
@@ -229,12 +234,13 @@
   }
 
   // Does a bounded transitive visitation starting at the given top-level targets.
-  private boolean redoVisitation(EventHandler eventHandler,
-                                 VisitationAttributes visitation,
-                                 boolean keepGoing,
-                                 int parallelThreads,
-                                 int maxDepth,
-                                 TargetEdgeObserver... observers)
+  private boolean redoVisitation(
+      ExtendedEventHandler eventHandler,
+      VisitationAttributes visitation,
+      boolean keepGoing,
+      int parallelThreads,
+      int maxDepth,
+      TargetEdgeObserver... observers)
       throws InterruptedException {
     visitedMap.clear();
     visitedTargets.clear();
@@ -264,7 +270,7 @@
 
     private final static String THREAD_NAME = "LabelVisitor";
 
-    private final EventHandler eventHandler;
+    private final ExtendedEventHandler eventHandler;
     private final boolean keepGoing;
     private final int maxDepth;
     private final Iterable<TargetEdgeObserver> observers;
@@ -273,8 +279,12 @@
     private static final boolean CONCURRENT = true;
 
 
-    public Visitor(EventHandler eventHandler, boolean keepGoing, int parallelThreads,
-                   int maxDepth, TargetEdgeObserver... observers) {
+    public Visitor(
+        ExtendedEventHandler eventHandler,
+        boolean keepGoing,
+        int parallelThreads,
+        int maxDepth,
+        TargetEdgeObserver... observers) {
       // Observing the loading phase of a typical large package (with all subpackages) shows
       // maximum thread-level concurrency of ~20. Limiting the total number of threads to 200 is
       // therefore conservative and should help us avoid hitting native limits.
diff --git a/src/main/java/com/google/devtools/build/lib/query2/QueryEnvironmentFactory.java b/src/main/java/com/google/devtools/build/lib/query2/QueryEnvironmentFactory.java
index d419b64..f8c8327 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/QueryEnvironmentFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/QueryEnvironmentFactory.java
@@ -15,7 +15,7 @@
 
 import com.google.common.base.Predicate;
 import com.google.devtools.build.lib.cmdline.Label;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.packages.Rule;
 import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
@@ -35,12 +35,19 @@
 public class QueryEnvironmentFactory {
   /** Creates an appropriate {@link AbstractBlazeQueryEnvironment} based on the given options. */
   public AbstractBlazeQueryEnvironment<Target> create(
-      TransitivePackageLoader transitivePackageLoader, WalkableGraphFactory graphFactory,
+      TransitivePackageLoader transitivePackageLoader,
+      WalkableGraphFactory graphFactory,
       TargetProvider targetProvider,
-      TargetPatternEvaluator targetPatternEvaluator, boolean keepGoing, boolean strictScope,
-      boolean orderedResults, List<String> universeScope, int loadingPhaseThreads,
+      TargetPatternEvaluator targetPatternEvaluator,
+      boolean keepGoing,
+      boolean strictScope,
+      boolean orderedResults,
+      List<String> universeScope,
+      int loadingPhaseThreads,
       Predicate<Label> labelFilter,
-      EventHandler eventHandler, Set<Setting> settings, Iterable<QueryFunction> functions,
+      ExtendedEventHandler eventHandler,
+      Set<Setting> settings,
+      Iterable<QueryFunction> functions,
       QueryExpressionEvalListener<Target> evalListener,
       @Nullable PathPackageLocator packagePath) {
     Preconditions.checkNotNull(universeScope);
diff --git a/src/main/java/com/google/devtools/build/lib/query2/SkyQueryEnvironment.java b/src/main/java/com/google/devtools/build/lib/query2/SkyQueryEnvironment.java
index 93e4b11..3e1410f 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/SkyQueryEnvironment.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/SkyQueryEnvironment.java
@@ -39,7 +39,7 @@
 import com.google.devtools.build.lib.concurrent.NamedForkJoinPool;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
 import com.google.devtools.build.lib.events.Event;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.graph.Digraph;
 import com.google.devtools.build.lib.packages.BuildFileContainsErrorsException;
 import com.google.devtools.build.lib.packages.DependencyFilter;
@@ -148,7 +148,7 @@
   public SkyQueryEnvironment(
       boolean keepGoing,
       int loadingPhaseThreads,
-      EventHandler eventHandler,
+      ExtendedEventHandler eventHandler,
       Set<Setting> settings,
       Iterable<QueryFunction> extraFunctions,
       QueryExpressionEvalListener<Target> evalListener,
@@ -176,7 +176,7 @@
       boolean keepGoing,
       int loadingPhaseThreads,
       int queryEvaluationParallelismLevel,
-      EventHandler eventHandler,
+      ExtendedEventHandler eventHandler,
       Set<Setting> settings,
       Iterable<QueryFunction> extraFunctions,
       QueryExpressionEvalListener<Target> evalListener,
diff --git a/src/main/java/com/google/devtools/build/lib/query2/output/AspectResolver.java b/src/main/java/com/google/devtools/build/lib/query2/output/AspectResolver.java
index 7120100..2994aa0 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/output/AspectResolver.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/output/AspectResolver.java
@@ -15,13 +15,12 @@
 
 import com.google.common.collect.ImmutableMultimap;
 import com.google.devtools.build.lib.cmdline.Label;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.packages.Attribute;
 import com.google.devtools.build.lib.packages.DependencyFilter;
 import com.google.devtools.build.lib.packages.Package;
 import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.lib.pkgcache.PackageProvider;
-
 import java.util.Collection;
 import java.util.Set;
 
@@ -35,7 +34,8 @@
     // Do not report aspect dependencies
     OFF {
       @Override
-      public AspectResolver createResolver(PackageProvider provider, EventHandler eventHandler) {
+      public AspectResolver createResolver(
+          PackageProvider provider, ExtendedEventHandler eventHandler) {
         return new NullAspectResolver();
       }
     },
@@ -44,7 +44,8 @@
     // triggered
     CONSERVATIVE {
       @Override
-      public AspectResolver createResolver(PackageProvider provider, EventHandler eventHandler) {
+      public AspectResolver createResolver(
+          PackageProvider provider, ExtendedEventHandler eventHandler) {
         return new ConservativeAspectResolver();
       }
     },
@@ -52,13 +53,14 @@
     // Load direct dependencies and report aspects that can be triggered based on their types.
     PRECISE {
       @Override
-      public AspectResolver createResolver(PackageProvider provider, EventHandler eventHandler) {
+      public AspectResolver createResolver(
+          PackageProvider provider, ExtendedEventHandler eventHandler) {
         return new PreciseAspectResolver(provider, eventHandler);
       }
     };
 
     public abstract AspectResolver createResolver(
-        PackageProvider provider, EventHandler eventHandler);
+        PackageProvider provider, ExtendedEventHandler eventHandler);
   }
 
   /** The way aspect dependencies for a BUILD file are calculated. */
diff --git a/src/main/java/com/google/devtools/build/lib/query2/output/PreciseAspectResolver.java b/src/main/java/com/google/devtools/build/lib/query2/output/PreciseAspectResolver.java
index 4035d22..1cd1403 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/output/PreciseAspectResolver.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/output/PreciseAspectResolver.java
@@ -19,7 +19,7 @@
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
 import com.google.devtools.build.lib.cmdline.PackageIdentifier;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.packages.Aspect;
 import com.google.devtools.build.lib.packages.AspectDefinition;
 import com.google.devtools.build.lib.packages.Attribute;
@@ -31,11 +31,9 @@
 import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.lib.pkgcache.PackageProvider;
 import com.google.devtools.build.lib.util.BinaryPredicate;
-
 import java.util.LinkedHashSet;
 import java.util.Map.Entry;
 import java.util.Set;
-
 import javax.annotation.Nullable;
 
 /**
@@ -46,9 +44,9 @@
  */
 public class PreciseAspectResolver implements AspectResolver {
   private final PackageProvider packageProvider;
-  private final EventHandler eventHandler;
+  private final ExtendedEventHandler eventHandler;
 
-  public PreciseAspectResolver(PackageProvider packageProvider, EventHandler eventHandler) {
+  public PreciseAspectResolver(PackageProvider packageProvider, ExtendedEventHandler eventHandler) {
     this.packageProvider = packageProvider;
     this.eventHandler = eventHandler;
   }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/genquery/GenQuery.java b/src/main/java/com/google/devtools/build/lib/rules/genquery/GenQuery.java
index 87925af..589822b 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/genquery/GenQuery.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/genquery/GenQuery.java
@@ -39,7 +39,7 @@
 import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
 import com.google.devtools.build.lib.collect.nestedset.Order;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.packages.BuildType;
 import com.google.devtools.build.lib.packages.NoSuchPackageException;
 import com.google.devtools.build.lib.packages.NoSuchTargetException;
@@ -192,7 +192,7 @@
    * DO NOT USE! We should get rid of this method: errors reported directly to this object don't set
    * the error flag in {@link ConfiguredTarget}.
    */
-  private EventHandler getEventHandler(RuleContext ruleContext) {
+  private ExtendedEventHandler getEventHandler(RuleContext ruleContext) {
     return ruleContext.getAnalysisEnvironment().getEventHandler();
   }
 
@@ -396,7 +396,7 @@
 
     @Override
     public Map<String, ResolvedTargets<Target>> preloadTargetPatterns(
-        EventHandler eventHandler, Collection<String> patterns, boolean keepGoing)
+        ExtendedEventHandler eventHandler, Collection<String> patterns, boolean keepGoing)
         throws TargetParsingException, InterruptedException {
       Preconditions.checkArgument(!keepGoing);
       boolean ok = true;
@@ -481,16 +481,18 @@
     }
 
     @Override
-    public ResolvedTargets<Target> parseTargetPatternList(EventHandler eventHandler,
-                                                          List<String> targetPatterns,
-                                                          FilteringPolicy policy, boolean keepGoing)
+    public ResolvedTargets<Target> parseTargetPatternList(
+        ExtendedEventHandler eventHandler,
+        List<String> targetPatterns,
+        FilteringPolicy policy,
+        boolean keepGoing)
         throws TargetParsingException {
       throw new UnsupportedOperationException();
     }
 
     @Override
-    public ResolvedTargets<Target> parseTargetPattern(EventHandler eventHandler, String pattern,
-                                                      boolean keepGoing)
+    public ResolvedTargets<Target> parseTargetPattern(
+        ExtendedEventHandler eventHandler, String pattern, boolean keepGoing)
         throws TargetParsingException {
       throw new UnsupportedOperationException();
     }
@@ -521,7 +523,7 @@
     }
 
     @Override
-    public Package getPackage(EventHandler eventHandler, PackageIdentifier packageId)
+    public Package getPackage(ExtendedEventHandler eventHandler, PackageIdentifier packageId)
         throws NoSuchPackageException {
       Package pkg = pkgMap.get(packageId);
       if (pkg != null) {
@@ -532,7 +534,7 @@
     }
 
     @Override
-    public Target getTarget(EventHandler eventHandler, Label label)
+    public Target getTarget(ExtendedEventHandler eventHandler, Label label)
         throws NoSuchPackageException, NoSuchTargetException {
       // Try to perform only one map lookup in the common case.
       Target target = labelToTarget.get(label);
@@ -545,7 +547,7 @@
     }
 
     @Override
-    public boolean isPackage(EventHandler eventHandler, PackageIdentifier packageName) {
+    public boolean isPackage(ExtendedEventHandler eventHandler, PackageIdentifier packageName) {
       throw new UnsupportedOperationException();
     }
   }
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/BlazeRuntime.java b/src/main/java/com/google/devtools/build/lib/runtime/BlazeRuntime.java
index 0d98786..2612048 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/BlazeRuntime.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/BlazeRuntime.java
@@ -442,6 +442,7 @@
     } catch (IOException e) {
       env.getReporter().handle(Event.error("Error while writing profile file: " + e.getMessage()));
     }
+    env.getReporter().clearEventBus();
   }
 
   // Make sure we keep a strong reference to this logger, so that the
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/CommandEnvironment.java b/src/main/java/com/google/devtools/build/lib/runtime/CommandEnvironment.java
index 3590138..f981715 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/CommandEnvironment.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/CommandEnvironment.java
@@ -129,7 +129,7 @@
     this.workspace = workspace;
     this.directories = workspace.getDirectories();
     this.commandId = null; // Will be set once we get the client environment
-    this.reporter = new Reporter();
+    this.reporter = new Reporter(eventBus);
     this.eventBus = eventBus;
     this.commandThread = commandThread;
     this.blazeModuleEnvironment = new BlazeModuleEnvironment();
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/AbstractLabelCycleReporter.java b/src/main/java/com/google/devtools/build/lib/skyframe/AbstractLabelCycleReporter.java
index 9e358d8..438d906 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/AbstractLabelCycleReporter.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/AbstractLabelCycleReporter.java
@@ -19,7 +19,7 @@
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.concurrent.Uninterruptibles;
 import com.google.devtools.build.lib.events.Event;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.packages.NoSuchPackageException;
 import com.google.devtools.build.lib.packages.NoSuchTargetException;
 import com.google.devtools.build.lib.packages.NoSuchThingException;
@@ -49,13 +49,16 @@
   protected abstract boolean canReportCycle(SkyKey topLevelKey, CycleInfo cycleInfo);
 
   protected String getAdditionalMessageAboutCycle(
-      EventHandler eventHandler, SkyKey topLevelKey, CycleInfo cycleInfo) {
+      ExtendedEventHandler eventHandler, SkyKey topLevelKey, CycleInfo cycleInfo) {
     return "";
   }
 
   @Override
-  public boolean maybeReportCycle(SkyKey topLevelKey, CycleInfo cycleInfo,
-      boolean alreadyReported, EventHandler eventHandler) {
+  public boolean maybeReportCycle(
+      SkyKey topLevelKey,
+      CycleInfo cycleInfo,
+      boolean alreadyReported,
+      ExtendedEventHandler eventHandler) {
     Preconditions.checkNotNull(eventHandler);
     if (!canReportCycle(topLevelKey, cycleInfo)) {
       return false;
@@ -125,7 +128,8 @@
     return cycleValue;
   }
 
-  protected final Target getTargetForLabel(final EventHandler eventHandler, final Label label) {
+  protected final Target getTargetForLabel(
+      final ExtendedEventHandler eventHandler, final Label label) {
     try {
       return Uninterruptibles.callUninterruptibly(new Callable<Target>() {
         @Override
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ConfigurationCollectionFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/ConfigurationCollectionFunction.java
index 691cf6f..7326fb1 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ConfigurationCollectionFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ConfigurationCollectionFunction.java
@@ -26,7 +26,7 @@
 import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException;
 import com.google.devtools.build.lib.analysis.config.PackageProviderForConfigurations;
 import com.google.devtools.build.lib.events.ErrorSensingEventHandler;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.packages.Attribute;
 import com.google.devtools.build.lib.packages.RuleClassProvider;
 import com.google.devtools.build.lib.skyframe.ConfigurationCollectionValue.ConfigurationCollectionKey;
@@ -155,7 +155,7 @@
   @Nullable
   private BuildConfiguration createConfiguration(
       Cache<String, BuildConfiguration> cache,
-      EventHandler originalEventListener,
+      ExtendedEventHandler originalEventListener,
       PackageProviderForConfigurations loadedPackageProvider,
       BuildOptions buildOptions,
       String cpuOverride)
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ConfigurationFragmentFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/ConfigurationFragmentFunction.java
index d560b8a..db5aae9 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ConfigurationFragmentFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ConfigurationFragmentFunction.java
@@ -24,7 +24,7 @@
 import com.google.devtools.build.lib.analysis.config.PackageProviderForConfigurations;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.packages.NoSuchPackageException;
 import com.google.devtools.build.lib.packages.NoSuchTargetException;
 import com.google.devtools.build.lib.packages.Package;
@@ -105,7 +105,7 @@
     }
 
     @Override
-    public EventHandler getEventHandler() {
+    public ExtendedEventHandler getEventHandler() {
       return packageProvider.getEventHandler();
     }
 
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetCycleReporter.java b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetCycleReporter.java
index ca05c1c..aee158e 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetCycleReporter.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetCycleReporter.java
@@ -20,7 +20,7 @@
 import com.google.common.base.Predicates;
 import com.google.common.collect.Iterables;
 import com.google.devtools.build.lib.cmdline.Label;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.pkgcache.PackageProvider;
 import com.google.devtools.build.lib.skyframe.AspectValue.AspectKey;
 import com.google.devtools.build.skyframe.CycleInfo;
@@ -72,7 +72,7 @@
 
   @Override
   protected String getAdditionalMessageAboutCycle(
-      EventHandler eventHandler, SkyKey topLevelKey, CycleInfo cycleInfo) {
+      ExtendedEventHandler eventHandler, SkyKey topLevelKey, CycleInfo cycleInfo) {
     if (Iterables.all(cycleInfo.getCycle(), IS_TRANSITIVE_TARGET_SKY_KEY)) {
       // The problem happened strictly in loading, so delegate the explanation to
       // TransitiveTargetCycleReporter.
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/EnvironmentBackedRecursivePackageProvider.java b/src/main/java/com/google/devtools/build/lib/skyframe/EnvironmentBackedRecursivePackageProvider.java
index 96a65b5..e254c58 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/EnvironmentBackedRecursivePackageProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/EnvironmentBackedRecursivePackageProvider.java
@@ -21,7 +21,7 @@
 import com.google.devtools.build.lib.cmdline.RepositoryName;
 import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
 import com.google.devtools.build.lib.events.Event;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.packages.BuildFileContainsErrorsException;
 import com.google.devtools.build.lib.packages.NoSuchPackageException;
 import com.google.devtools.build.lib.packages.NoSuchTargetException;
@@ -54,7 +54,7 @@
   }
 
   @Override
-  public Package getPackage(EventHandler eventHandler, PackageIdentifier packageName)
+  public Package getPackage(ExtendedEventHandler eventHandler, PackageIdentifier packageName)
       throws NoSuchPackageException, MissingDepException, InterruptedException {
     SkyKey pkgKey = PackageValue.key(packageName);
     PackageValue pkgValue =
@@ -80,9 +80,9 @@
   }
 
   @Override
-  public Map<PackageIdentifier, Package> bulkGetPackages(EventHandler eventHandler,
-          Iterable<PackageIdentifier> pkgIds)
-          throws NoSuchPackageException, InterruptedException {
+  public Map<PackageIdentifier, Package> bulkGetPackages(
+      ExtendedEventHandler eventHandler, Iterable<PackageIdentifier> pkgIds)
+      throws NoSuchPackageException, InterruptedException {
     ImmutableMap.Builder<PackageIdentifier, Package> builder = ImmutableMap.builder();
     for (PackageIdentifier pkgId : pkgIds) {
       builder.put(pkgId, getPackage(eventHandler, pkgId));
@@ -91,7 +91,7 @@
   }
 
   @Override
-  public boolean isPackage(EventHandler eventHandler, PackageIdentifier packageId)
+  public boolean isPackage(ExtendedEventHandler eventHandler, PackageIdentifier packageId)
       throws MissingDepException, InterruptedException {
     SkyKey packageLookupKey = PackageLookupValue.key(packageId);
     try {
@@ -156,7 +156,7 @@
   }
 
   @Override
-  public Target getTarget(EventHandler eventHandler, Label label)
+  public Target getTarget(ExtendedEventHandler eventHandler, Label label)
       throws NoSuchPackageException, NoSuchTargetException, MissingDepException,
           InterruptedException {
     return getPackage(eventHandler, label.getPackageIdentifier()).getTarget(label.getName());
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/GraphBackedRecursivePackageProvider.java b/src/main/java/com/google/devtools/build/lib/skyframe/GraphBackedRecursivePackageProvider.java
index 9f922da..2140b06 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/GraphBackedRecursivePackageProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/GraphBackedRecursivePackageProvider.java
@@ -30,7 +30,7 @@
 import com.google.devtools.build.lib.cmdline.TargetPattern.Type;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
 import com.google.devtools.build.lib.events.Event;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.packages.BuildFileNotFoundException;
 import com.google.devtools.build.lib.packages.NoSuchPackageException;
 import com.google.devtools.build.lib.packages.NoSuchTargetException;
@@ -77,7 +77,7 @@
   }
 
   @Override
-  public Package getPackage(EventHandler eventHandler, PackageIdentifier packageName)
+  public Package getPackage(ExtendedEventHandler eventHandler, PackageIdentifier packageName)
       throws NoSuchPackageException, InterruptedException {
     SkyKey pkgKey = PackageValue.key(packageName);
 
@@ -100,7 +100,7 @@
 
   @Override
   public Map<PackageIdentifier, Package> bulkGetPackages(
-      EventHandler eventHandler, Iterable<PackageIdentifier> pkgIds)
+      ExtendedEventHandler eventHandler, Iterable<PackageIdentifier> pkgIds)
       throws NoSuchPackageException, InterruptedException {
     Set<SkyKey> pkgKeys = ImmutableSet.copyOf(PackageValue.keys(pkgIds));
 
@@ -135,7 +135,7 @@
 
 
   @Override
-  public boolean isPackage(EventHandler eventHandler, PackageIdentifier packageName)
+  public boolean isPackage(ExtendedEventHandler eventHandler, PackageIdentifier packageName)
       throws InterruptedException {
     SkyKey packageLookupKey = PackageLookupValue.key(packageName);
     PackageLookupValue packageLookupValue = (PackageLookupValue) graph.getValue(packageLookupKey);
@@ -266,7 +266,7 @@
   }
 
   @Override
-  public Target getTarget(EventHandler eventHandler, Label label)
+  public Target getTarget(ExtendedEventHandler eventHandler, Label label)
       throws NoSuchPackageException, NoSuchTargetException, InterruptedException {
     return getPackage(eventHandler, label.getPackageIdentifier()).getTarget(label.getName());
   }
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/LegacyLoadingPhaseRunner.java b/src/main/java/com/google/devtools/build/lib/skyframe/LegacyLoadingPhaseRunner.java
index ee1eaf2..8ba76ff 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/LegacyLoadingPhaseRunner.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/LegacyLoadingPhaseRunner.java
@@ -22,7 +22,7 @@
 import com.google.devtools.build.lib.cmdline.TargetParsingException;
 import com.google.devtools.build.lib.events.DelegatingEventHandler;
 import com.google.devtools.build.lib.events.Event;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.packages.NoSuchPackageException;
 import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.lib.packages.TargetUtils;
@@ -74,10 +74,10 @@
 public final class LegacyLoadingPhaseRunner extends LoadingPhaseRunner {
 
   private static final class ParseFailureListenerImpl extends DelegatingEventHandler
-      implements ParseFailureListener {
+      implements ParseFailureListener, ExtendedEventHandler {
     private final EventBus eventBus;
 
-    private ParseFailureListenerImpl(EventHandler delegate, EventBus eventBus) {
+    private ParseFailureListenerImpl(ExtendedEventHandler delegate, EventBus eventBus) {
       super(delegate);
       this.eventBus = eventBus;
     }
@@ -88,6 +88,11 @@
         eventBus.post(new ParsingFailedEvent(targetPattern, message));
       }
     }
+
+    @Override
+    public void post(ExtendedEventHandler.Postable obj) {
+      eventBus.post(obj);
+    }
   }
 
   private static final Logger LOG = Logger.getLogger(LoadingPhaseRunner.class.getName());
@@ -109,7 +114,7 @@
    */
   @Override
   public LoadingResult execute(
-      EventHandler eventHandler,
+      ExtendedEventHandler eventHandler,
       EventBus eventBus,
       List<String> targetPatterns,
       PathFragment relativeWorkingDirectory,
@@ -127,7 +132,8 @@
     }
 
     targetPatternEvaluator.updateOffset(relativeWorkingDirectory);
-    EventHandler parseFailureListener = new ParseFailureListenerImpl(eventHandler, eventBus);
+    ExtendedEventHandler parseFailureListener =
+        new ParseFailureListenerImpl(eventHandler, eventBus);
     // Determine targets to build:
     ResolvedTargets<Target> targets =
         getTargetsToBuild(
@@ -248,7 +254,7 @@
   }
 
   private ResolvedTargets<Target> expandTestSuites(
-      EventHandler eventHandler, ImmutableSet<Target> targets, boolean keepGoing)
+      ExtendedEventHandler eventHandler, ImmutableSet<Target> targets, boolean keepGoing)
       throws LoadingFailedException, TargetParsingException {
     // We use strict test_suite expansion here to match the analysis-time checks.
     ResolvedTargets<Target> expandedResult =
@@ -269,12 +275,12 @@
    * @throws TargetParsingException if parsing failed and !keepGoing
    */
   private ResolvedTargets<Target> getTargetsToBuild(
-      EventHandler eventHandler,
+      ExtendedEventHandler eventHandler,
       List<String> targetPatterns,
       boolean compileOneDependency,
       List<String> buildTagFilterList,
       boolean keepGoing)
-          throws TargetParsingException, InterruptedException {
+      throws TargetParsingException, InterruptedException {
     ResolvedTargets<Target> evaluated =
         targetPatternEvaluator.parseTargetPatternList(eventHandler, targetPatterns,
             FilteringPolicies.FILTER_MANUAL, keepGoing);
@@ -302,7 +308,7 @@
    * @param keepGoing value of the --keep_going flag
    */
   private ResolvedTargets<Target> determineTests(
-      EventHandler eventHandler,
+      ExtendedEventHandler eventHandler,
       List<String> targetPatterns,
       LoadingOptions options,
       boolean keepGoing)
@@ -318,7 +324,7 @@
     return finalBuilder.build();
   }
 
-  private String getWorkspaceName(EventHandler eventHandler)
+  private String getWorkspaceName(ExtendedEventHandler eventHandler)
       throws InterruptedException, LoadingFailedException {
     try {
       return packageManager
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/RecursivePackageProviderBackedTargetPatternResolver.java b/src/main/java/com/google/devtools/build/lib/skyframe/RecursivePackageProviderBackedTargetPatternResolver.java
index 5492274..5c6bd42 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/RecursivePackageProviderBackedTargetPatternResolver.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/RecursivePackageProviderBackedTargetPatternResolver.java
@@ -33,7 +33,7 @@
 import com.google.devtools.build.lib.concurrent.MultisetSemaphore;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadCompatible;
 import com.google.devtools.build.lib.events.Event;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.packages.NoSuchPackageException;
 import com.google.devtools.build.lib.packages.NoSuchThingException;
 import com.google.devtools.build.lib.packages.Package;
@@ -67,13 +67,13 @@
   private static final int MAX_PACKAGES_BULK_GET = 1000;
 
   private final RecursivePackageProvider recursivePackageProvider;
-  private final EventHandler eventHandler;
+  private final ExtendedEventHandler eventHandler;
   private final FilteringPolicy policy;
   private final MultisetSemaphore<PackageIdentifier> packageSemaphore;
 
   public RecursivePackageProviderBackedTargetPatternResolver(
       RecursivePackageProvider recursivePackageProvider,
-      EventHandler eventHandler,
+      ExtendedEventHandler eventHandler,
       FilteringPolicy policy,
       MultisetSemaphore<PackageIdentifier> packageSemaphore) {
     this.recursivePackageProvider = recursivePackageProvider;
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutor.java b/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutor.java
index 34cde76..ed0f862 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutor.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutor.java
@@ -34,7 +34,7 @@
 import com.google.devtools.build.lib.analysis.config.BinTools;
 import com.google.devtools.build.lib.cmdline.PackageIdentifier;
 import com.google.devtools.build.lib.concurrent.Uninterruptibles;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.packages.Package;
 import com.google.devtools.build.lib.packages.PackageFactory;
 import com.google.devtools.build.lib.packages.Preprocessor;
@@ -272,7 +272,7 @@
 
   @Override
   public void sync(
-      EventHandler eventHandler,
+      ExtendedEventHandler eventHandler,
       PackageCacheOptions packageCacheOptions,
       Path outputBase,
       Path workingDirectory,
@@ -334,17 +334,15 @@
     invalidateDeletedPackages(deletedPackages.get());
   }
 
-  /**
-   * Uses diff awareness on all the package paths to invalidate changed files.
-   */
+  /** Uses diff awareness on all the package paths to invalidate changed files. */
   @VisibleForTesting
-  public void handleDiffs(EventHandler eventHandler) throws InterruptedException {
+  public void handleDiffs(ExtendedEventHandler eventHandler) throws InterruptedException {
     handleDiffs(eventHandler, /*checkOutputFiles=*/false, OptionsClassProvider.EMPTY);
   }
 
   private void handleDiffs(
-      EventHandler eventHandler, boolean checkOutputFiles, OptionsClassProvider options)
-          throws InterruptedException {
+      ExtendedEventHandler eventHandler, boolean checkOutputFiles, OptionsClassProvider options)
+      throws InterruptedException {
     if (lastAnalysisDiscarded) {
       // Values were cleared last build, but they couldn't be deleted because they were needed for
       // the execution phase. We can delete them now.
@@ -415,13 +413,16 @@
   }
 
   /**
-   * Finds and invalidates changed files under path entries whose corresponding
-   * {@link DiffAwareness} said all files may have been modified.
+   * Finds and invalidates changed files under path entries whose corresponding {@link
+   * DiffAwareness} said all files may have been modified.
    */
-  private void handleDiffsWithMissingDiffInformation(EventHandler eventHandler,
+  private void handleDiffsWithMissingDiffInformation(
+      ExtendedEventHandler eventHandler,
       TimestampGranularityMonitor tsgm,
       Set<Pair<Path, DiffAwarenessManager.ProcessableModifiedFileSet>>
-          pathEntriesWithoutDiffInformation, boolean checkOutputFiles) throws InterruptedException {
+          pathEntriesWithoutDiffInformation,
+      boolean checkOutputFiles)
+      throws InterruptedException {
     ExternalFilesKnowledge externalFilesKnowledge =
         externalFilesHelper.getExternalFilesKnowledge();
     if (pathEntriesWithoutDiffInformation.isEmpty()
@@ -559,8 +560,9 @@
   }
 
   @Override
-  public void invalidateFilesUnderPathForTesting(EventHandler eventHandler,
-      ModifiedFileSet modifiedFileSet, Path pathEntry) throws InterruptedException {
+  public void invalidateFilesUnderPathForTesting(
+      ExtendedEventHandler eventHandler, ModifiedFileSet modifiedFileSet, Path pathEntry)
+      throws InterruptedException {
     if (lastAnalysisDiscarded) {
       // Values were cleared last build, but they couldn't be deleted because they were needed for
       // the execution phase. We can delete them now.
@@ -644,13 +646,13 @@
   /**
    * Deletes all ConfiguredTarget values from the Skyframe cache.
    *
-   * <p>After the execution of this method all invalidated and marked for deletion values
-   * (and the values depending on them) will be deleted from the cache.
+   * <p>After the execution of this method all invalidated and marked for deletion values (and the
+   * values depending on them) will be deleted from the cache.
    *
-   * <p>WARNING: Note that a call to this method leaves legacy data inconsistent with Skyframe.
-   * The next build should clear the legacy caches.
+   * <p>WARNING: Note that a call to this method leaves legacy data inconsistent with Skyframe. The
+   * next build should clear the legacy caches.
    */
-  private void dropConfiguredTargetsNow(final EventHandler eventHandler) {
+  private void dropConfiguredTargetsNow(final ExtendedEventHandler eventHandler) {
     dropConfiguredTargets();
     // Run the invalidator to actually delete the values.
     try {
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeBuildView.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeBuildView.java
index 0e2c828..abcf596 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeBuildView.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeBuildView.java
@@ -47,7 +47,7 @@
 import com.google.devtools.build.lib.cmdline.PackageIdentifier;
 import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
 import com.google.devtools.build.lib.events.Event;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.packages.Attribute;
 import com.google.devtools.build.lib.packages.NoSuchPackageException;
 import com.google.devtools.build.lib.packages.NoSuchTargetException;
@@ -195,7 +195,7 @@
    * @return the configured targets that should be built along with a WalkableGraph of the analysis.
    */
   public SkyframeAnalysisResult configureTargets(
-      EventHandler eventHandler,
+      ExtendedEventHandler eventHandler,
       List<ConfiguredTargetKey> values,
       List<AspectValueKey> aspectKeys,
       EventBus eventBus,
@@ -453,7 +453,7 @@
   CachingAnalysisEnvironment createAnalysisEnvironment(
       ArtifactOwner owner,
       boolean isSystemEnv,
-      EventHandler eventHandler,
+      ExtendedEventHandler eventHandler,
       Environment env,
       BuildConfiguration config)
       throws InterruptedException {
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
index 59a0bbc..bf7a64f 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
@@ -77,7 +77,7 @@
 import com.google.devtools.build.lib.cmdline.TargetParsingException;
 import com.google.devtools.build.lib.concurrent.ThreadSafety;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadCompatible;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.events.Reporter;
 import com.google.devtools.build.lib.exec.OutputService;
 import com.google.devtools.build.lib.packages.AspectDescriptor;
@@ -533,7 +533,8 @@
    * This method exists only to allow a module to make a top-level Skyframe call during the
    * transition to making it fully Skyframe-compatible. Do not add additional callers!
    */
-  public SkyValue evaluateSkyKeyForExecutionSetup(final EventHandler eventHandler, final SkyKey key)
+  public SkyValue evaluateSkyKeyForExecutionSetup(
+      final ExtendedEventHandler eventHandler, final SkyKey key)
       throws EnvironmentalExecException, InterruptedException {
     synchronized (valueLookupLock) {
       // We evaluate in keepGoing mode because in the case that the graph does not store its
@@ -734,7 +735,7 @@
   }
 
   /** Returns the build-info.txt and build-changelist.txt artifacts. */
-  public Collection<Artifact> getWorkspaceStatusArtifacts(EventHandler eventHandler)
+  public Collection<Artifact> getWorkspaceStatusArtifacts(ExtendedEventHandler eventHandler)
       throws InterruptedException {
     // Should already be present, unless the user didn't request any targets for analysis.
     EvaluationResult<WorkspaceStatusValue> result = buildDriver.evaluate(
@@ -746,19 +747,19 @@
   }
 
   public Map<PathFragment, Root> getArtifactRootsForFiles(
-      final EventHandler eventHandler, Iterable<PathFragment> execPaths)
+      final ExtendedEventHandler eventHandler, Iterable<PathFragment> execPaths)
       throws PackageRootResolutionException, InterruptedException {
     return getArtifactRoots(eventHandler, execPaths, true);
   }
 
   public Map<PathFragment, Root> getArtifactRoots(
-      final EventHandler eventHandler, Iterable<PathFragment> execPaths)
+      final ExtendedEventHandler eventHandler, Iterable<PathFragment> execPaths)
       throws PackageRootResolutionException, InterruptedException {
     return getArtifactRoots(eventHandler, execPaths, false);
   }
 
   private Map<PathFragment, Root> getArtifactRoots(
-      final EventHandler eventHandler, Iterable<PathFragment> execPaths, boolean forFiles)
+      final ExtendedEventHandler eventHandler, Iterable<PathFragment> execPaths, boolean forFiles)
       throws PackageRootResolutionException, InterruptedException {
     final Map<PathFragment, SkyKey> packageKeys = new HashMap<>();
     for (PathFragment execPath : execPaths) {
@@ -1038,10 +1039,12 @@
    * result. Also invalidates {@link PrecomputedValue#BLAZE_DIRECTORIES} if it has changed.
    */
   public BuildConfigurationCollection createConfigurations(
-      EventHandler eventHandler, ConfigurationFactory configurationFactory,
-      BuildOptions buildOptions, Set<String> multiCpu,
+      ExtendedEventHandler eventHandler,
+      ConfigurationFactory configurationFactory,
+      BuildOptions buildOptions,
+      Set<String> multiCpu,
       boolean keepGoing)
-          throws InvalidConfigurationException, InterruptedException {
+      throws InvalidConfigurationException, InterruptedException {
     this.configurationFactory.set(configurationFactory);
     this.configurationFragments.set(ImmutableList.copyOf(configurationFactory.getFactories()));
 
@@ -1151,8 +1154,12 @@
         outputService);
   }
 
-  EvaluationResult<TargetPatternValue> targetPatterns(Iterable<SkyKey> patternSkyKeys,
-      int numThreads, boolean keepGoing, EventHandler eventHandler) throws InterruptedException {
+  EvaluationResult<TargetPatternValue> targetPatterns(
+      Iterable<SkyKey> patternSkyKeys,
+      int numThreads,
+      boolean keepGoing,
+      ExtendedEventHandler eventHandler)
+      throws InterruptedException {
     checkActive();
     return buildDriver.evaluate(patternSkyKeys, keepGoing, numThreads, eventHandler);
   }
@@ -1168,15 +1175,17 @@
   @ThreadSafety.ThreadSafe
   // TODO(bazel-team): rename this and below methods to something that discourages general use
   public ImmutableList<ConfiguredTarget> getConfiguredTargets(
-      EventHandler eventHandler, BuildConfiguration originalConfig, Iterable<Dependency> keys,
+      ExtendedEventHandler eventHandler,
+      BuildConfiguration originalConfig,
+      Iterable<Dependency> keys,
       boolean useOriginalConfig) {
     return getConfiguredTargetMap(
         eventHandler, originalConfig, keys, useOriginalConfig).values().asList();
   }
 
   /**
-   * Returns a map from {@link Dependency} inputs to the {@link ConfiguredTarget}s corresponding
-   * to those dependencies.
+   * Returns a map from {@link Dependency} inputs to the {@link ConfiguredTarget}s corresponding to
+   * those dependencies.
    *
    * <p>For use for legacy support and tests calling through {@code BuildView} only.
    *
@@ -1185,7 +1194,9 @@
    */
   @ThreadSafety.ThreadSafe
   public ImmutableMultimap<Dependency, ConfiguredTarget> getConfiguredTargetMap(
-      EventHandler eventHandler, BuildConfiguration originalConfig, Iterable<Dependency> keys,
+      ExtendedEventHandler eventHandler,
+      BuildConfiguration originalConfig,
+      Iterable<Dependency> keys,
       boolean useOriginalConfig) {
     checkActive();
 
@@ -1280,14 +1291,14 @@
   }
 
   /**
-   * Retrieves the configurations needed for the given deps. If
-   * {@link BuildConfiguration.Options#trimConfigurations()} is true, trims their fragments to only
-   * those needed by their transitive closures. Else unconditionally includes all fragments.
+   * Retrieves the configurations needed for the given deps. If {@link
+   * BuildConfiguration.Options#trimConfigurations()} is true, trims their fragments to only those
+   * needed by their transitive closures. Else unconditionally includes all fragments.
    *
    * <p>Skips targets with loading phase errors.
    */
-  public Multimap<Dependency, BuildConfiguration> getConfigurations(EventHandler eventHandler,
-      BuildOptions fromOptions, Iterable<Dependency> keys) {
+  public Multimap<Dependency, BuildConfiguration> getConfigurations(
+      ExtendedEventHandler eventHandler, BuildOptions fromOptions, Iterable<Dependency> keys) {
     Multimap<Dependency, BuildConfiguration> builder =
         ArrayListMultimap.<Dependency, BuildConfiguration>create();
     Set<Dependency> depsToEvaluate = new HashSet<>();
@@ -1377,11 +1388,11 @@
   }
 
   /**
-   * Evaluates the given sky keys, blocks, and returns their evaluation results. Fails fast
-   * on the first evaluation error.
+   * Evaluates the given sky keys, blocks, and returns their evaluation results. Fails fast on the
+   * first evaluation error.
    */
   private EvaluationResult<SkyValue> evaluateSkyKeys(
-      final EventHandler eventHandler, final Iterable<SkyKey> skyKeys) {
+      final ExtendedEventHandler eventHandler, final Iterable<SkyKey> skyKeys) {
     return evaluateSkyKeys(eventHandler, skyKeys, false);
   }
 
@@ -1390,7 +1401,9 @@
    * "keep going" on evaluation errors as specified.
    */
   private EvaluationResult<SkyValue> evaluateSkyKeys(
-      final EventHandler eventHandler, final Iterable<SkyKey> skyKeys, final boolean keepGoing) {
+      final ExtendedEventHandler eventHandler,
+      final Iterable<SkyKey> skyKeys,
+      final boolean keepGoing) {
     EvaluationResult<SkyValue> result;
     try {
       result = callUninterruptibly(new Callable<EvaluationResult<SkyValue>>() {
@@ -1418,9 +1431,10 @@
    */
   @VisibleForTesting
   public BuildConfiguration getConfigurationForTesting(
-      EventHandler eventHandler,  Set<Class<? extends BuildConfiguration.Fragment>> fragments,
+      ExtendedEventHandler eventHandler,
+      Set<Class<? extends BuildConfiguration.Fragment>> fragments,
       BuildOptions options)
-          throws InterruptedException {
+      throws InterruptedException {
     SkyKey key = BuildConfigurationValue.key(fragments, options);
     BuildConfigurationValue result = (BuildConfigurationValue) buildDriver
         .evaluate(ImmutableList.of(key), false, DEFAULT_THREAD_COUNT, eventHandler).get(key);
@@ -1435,7 +1449,7 @@
   @VisibleForTesting
   @Nullable
   public ConfiguredTarget getConfiguredTargetForTesting(
-      EventHandler eventHandler, Label label, BuildConfiguration configuration) {
+      ExtendedEventHandler eventHandler, Label label, BuildConfiguration configuration) {
     if (memoizingEvaluator.getExistingValueForTesting(
         PrecomputedValue.WORKSPACE_STATUS_KEY.getKeyForTesting()) == null) {
       injectWorkspaceStatusData(label.getWorkspaceRoot());
@@ -1463,8 +1477,9 @@
    * <p>May throw an {@link InterruptedException}, which means that no values have been invalidated.
    */
   @VisibleForTesting
-  public abstract void invalidateFilesUnderPathForTesting(EventHandler eventHandler,
-      ModifiedFileSet modifiedFileSet, Path pathEntry) throws InterruptedException;
+  public abstract void invalidateFilesUnderPathForTesting(
+      ExtendedEventHandler eventHandler, ModifiedFileSet modifiedFileSet, Path pathEntry)
+      throws InterruptedException;
 
   /**
    * Invalidates SkyFrame values that may have failed for transient reasons.
@@ -1473,7 +1488,7 @@
 
   /** Configures a given set of configured targets. */
   EvaluationResult<ActionLookupValue> configureTargets(
-      EventHandler eventHandler,
+      ExtendedEventHandler eventHandler,
       List<ConfiguredTargetKey> values,
       List<AspectValueKey> aspectKeys,
       boolean keepGoing,
@@ -1497,9 +1512,11 @@
    * error-free from action conflicts.
    */
   public EvaluationResult<PostConfiguredTargetValue> postConfigureTargets(
-      EventHandler eventHandler, List<ConfiguredTargetKey> values, boolean keepGoing,
+      ExtendedEventHandler eventHandler,
+      List<ConfiguredTargetKey> values,
+      boolean keepGoing,
       ImmutableMap<ActionAnalysisMetadata, SkyframeActionExecutor.ConflictException> badActions)
-          throws InterruptedException {
+      throws InterruptedException {
     checkActive();
     PrecomputedValue.BAD_ACTIONS.set(injectable(), badActions);
     // Make sure to not run too many analysis threads. This can cause memory thrashing.
@@ -1524,11 +1541,11 @@
   }
 
   class SkyframeTransitivePackageLoader {
-    /**
-     * Loads the specified {@link TransitiveTargetValue}s.
-     */
+    /** Loads the specified {@link TransitiveTargetValue}s. */
     EvaluationResult<TransitiveTargetValue> loadTransitiveTargets(
-        EventHandler eventHandler, Iterable<Label> labelsToVisit, boolean keepGoing,
+        ExtendedEventHandler eventHandler,
+        Iterable<Label> labelsToVisit,
+        boolean keepGoing,
         int parallelThreads)
         throws InterruptedException {
       List<SkyKey> valueNames = new ArrayList<>();
@@ -1549,7 +1566,8 @@
    */
   @Override
   public EvaluationResult<SkyValue> prepareAndGet(
-      SkyKey universeKey, int numThreads, EventHandler eventHandler) throws InterruptedException {
+      SkyKey universeKey, int numThreads, ExtendedEventHandler eventHandler)
+      throws InterruptedException {
     EvaluationResult<SkyValue> evaluationResult =
         buildDriver.evaluate(ImmutableList.of(universeKey), true, numThreads, eventHandler);
     Preconditions.checkNotNull(evaluationResult.getWalkableGraph(), universeKey);
@@ -1575,11 +1593,9 @@
     return PrepareDepsOfPatternsValue.key(ImmutableList.copyOf(patterns), offset);
   }
 
-  /**
-   * Returns the generating action of a given artifact ({@code null} if it's a source artifact).
-   */
-  private ActionAnalysisMetadata getGeneratingAction(EventHandler eventHandler, Artifact artifact)
-      throws InterruptedException {
+  /** Returns the generating action of a given artifact ({@code null} if it's a source artifact). */
+  private ActionAnalysisMetadata getGeneratingAction(
+      ExtendedEventHandler eventHandler, Artifact artifact) throws InterruptedException {
     if (artifact.isSourceArtifact()) {
       return null;
     }
@@ -1609,7 +1625,7 @@
    *
    * <p>For legacy compatibility only.
    */
-  public ActionGraph getActionGraph(final EventHandler eventHandler) {
+  public ActionGraph getActionGraph(final ExtendedEventHandler eventHandler) {
     return new ActionGraph() {
       @Override
       public ActionAnalysisMetadata getGeneratingAction(final Artifact artifact) {
@@ -1642,7 +1658,7 @@
      * <p>Note that this method needs to be synchronized since InMemoryMemoizingEvaluator.evaluate()
      * method does not support concurrent calls.
      */
-    Package getPackage(EventHandler eventHandler, PackageIdentifier pkgName)
+    Package getPackage(ExtendedEventHandler eventHandler, PackageIdentifier pkgName)
         throws InterruptedException, NoSuchPackageException {
       synchronized (valueLookupLock) {
         SkyKey key = PackageValue.key(pkgName);
@@ -1689,7 +1705,7 @@
   }
 
   public void sync(
-      EventHandler eventHandler,
+      ExtendedEventHandler eventHandler,
       PackageCacheOptions packageCacheOptions,
       Path outputBase,
       Path workingDirectory,
@@ -1726,9 +1742,13 @@
     invalidateTransientErrors();
   }
 
-  protected PathPackageLocator createPackageLocator(EventHandler eventHandler,
-      PackageCacheOptions packageCacheOptions, Path outputBase, Path workspace,
-      Path workingDirectory) throws AbruptExitException {
+  protected PathPackageLocator createPackageLocator(
+      ExtendedEventHandler eventHandler,
+      PackageCacheOptions packageCacheOptions,
+      Path outputBase,
+      Path workspace,
+      Path workingDirectory)
+      throws AbruptExitException {
     return PathPackageLocator.create(
         outputBase, packageCacheOptions.packagePath, eventHandler, workspace, workingDirectory);
   }
@@ -1748,8 +1768,8 @@
   }
 
   /** Convenience method with same semantics as {@link CyclesReporter#reportCycles}. */
-  public void reportCycles(EventHandler eventHandler, Iterable<CycleInfo> cycles,
-      SkyKey topLevelKey) {
+  public void reportCycles(
+      ExtendedEventHandler eventHandler, Iterable<CycleInfo> cycles, SkyKey topLevelKey) {
     getCyclesReporter().reportCycles(cycles, topLevelKey, eventHandler);
   }
 
@@ -1838,7 +1858,7 @@
 
     @Override
     public LoadingResult execute(
-        EventHandler eventHandler,
+        ExtendedEventHandler eventHandler,
         EventBus eventBus,
         List<String> targetPatterns,
         PathFragment relativeWorkingDirectory,
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeLabelVisitor.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeLabelVisitor.java
index 6b1e6ca..742d2fa 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeLabelVisitor.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeLabelVisitor.java
@@ -16,7 +16,7 @@
 import com.google.common.collect.Iterables;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.events.Event;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.pkgcache.TransitivePackageLoader;
 import com.google.devtools.build.lib.skyframe.SkyframeExecutor.SkyframeTransitivePackageLoader;
 import com.google.devtools.build.lib.util.Preconditions;
@@ -45,8 +45,12 @@
 
   // The only remaining non-test caller of this code is BlazeQueryEnvironment.
   @Override
-  public boolean sync(EventHandler eventHandler, Set<Label> labelsToVisit, boolean keepGoing,
-      int parallelThreads) throws InterruptedException {
+  public boolean sync(
+      ExtendedEventHandler eventHandler,
+      Set<Label> labelsToVisit,
+      boolean keepGoing,
+      int parallelThreads)
+      throws InterruptedException {
     EvaluationResult<TransitiveTargetValue> result = transitivePackageLoader.loadTransitiveTargets(
         eventHandler, labelsToVisit, keepGoing, parallelThreads);
 
@@ -121,14 +125,14 @@
         && Iterables.contains(errorInfo.getRootCauses(), TransitiveTargetValue.key(label));
   }
 
-  private static void errorAboutLoadingFailure(Label topLevelLabel, @Nullable Throwable throwable,
-      EventHandler eventHandler) {
+  private static void errorAboutLoadingFailure(
+      Label topLevelLabel, @Nullable Throwable throwable, ExtendedEventHandler eventHandler) {
     eventHandler.handle(Event.error(
         "Loading of target '" + topLevelLabel + "' failed; build aborted" +
             (throwable == null ? "" : ": " + throwable.getMessage())));
   }
 
-  private static void warnAboutLoadingFailure(Label label, EventHandler eventHandler) {
+  private static void warnAboutLoadingFailure(Label label, ExtendedEventHandler eventHandler) {
     eventHandler.handle(Event.warn("errors encountered while loading target '" + label + "'"));
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframePackageLoaderWithValueEnvironment.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframePackageLoaderWithValueEnvironment.java
index ceda171..18f7e98 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframePackageLoaderWithValueEnvironment.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframePackageLoaderWithValueEnvironment.java
@@ -21,7 +21,7 @@
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
 import com.google.devtools.build.lib.cmdline.PackageIdentifier;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.packages.NoSuchPackageException;
 import com.google.devtools.build.lib.packages.NoSuchTargetException;
 import com.google.devtools.build.lib.packages.Package;
@@ -50,7 +50,7 @@
   }
 
   @Override
-  public EventHandler getEventHandler() {
+  public ExtendedEventHandler getEventHandler() {
     return env.getListener();
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframePackageManager.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframePackageManager.java
index ce19bd4..d7c1de7 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframePackageManager.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframePackageManager.java
@@ -16,7 +16,7 @@
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.cmdline.PackageIdentifier;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.packages.NoSuchPackageException;
 import com.google.devtools.build.lib.packages.NoSuchTargetException;
 import com.google.devtools.build.lib.packages.Package;
@@ -67,13 +67,13 @@
 
   @ThreadSafe
   @Override
-  public Package getPackage(EventHandler eventHandler, PackageIdentifier packageIdentifier)
+  public Package getPackage(ExtendedEventHandler eventHandler, PackageIdentifier packageIdentifier)
       throws NoSuchPackageException, InterruptedException {
     return packageLoader.getPackage(eventHandler, packageIdentifier);
   }
 
   @Override
-  public Target getTarget(EventHandler eventHandler, Label label)
+  public Target getTarget(ExtendedEventHandler eventHandler, Label label)
       throws NoSuchPackageException, NoSuchTargetException, InterruptedException {
     return getPackage(eventHandler, label.getPackageIdentifier()).getTarget(label.getName());
   }
@@ -99,7 +99,7 @@
   }
 
   @Override
-  public boolean isPackage(EventHandler eventHandler, PackageIdentifier packageName) {
+  public boolean isPackage(ExtendedEventHandler eventHandler, PackageIdentifier packageName) {
     return getBuildFileForPackage(packageName) != null;
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeTargetPatternEvaluator.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeTargetPatternEvaluator.java
index b0dfa3c..6fc79ef 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeTargetPatternEvaluator.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeTargetPatternEvaluator.java
@@ -20,7 +20,7 @@
 import com.google.devtools.build.lib.cmdline.ResolvedTargets;
 import com.google.devtools.build.lib.cmdline.TargetParsingException;
 import com.google.devtools.build.lib.events.Event;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.lib.pkgcache.FilteringPolicies;
 import com.google.devtools.build.lib.pkgcache.FilteringPolicy;
@@ -33,7 +33,6 @@
 import com.google.devtools.build.skyframe.EvaluationResult;
 import com.google.devtools.build.skyframe.SkyKey;
 import com.google.devtools.build.skyframe.WalkableGraph;
-
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
@@ -50,15 +49,19 @@
   }
 
   @Override
-  public ResolvedTargets<Target> parseTargetPatternList(EventHandler eventHandler,
-      List<String> targetPatterns, FilteringPolicy policy, boolean keepGoing)
+  public ResolvedTargets<Target> parseTargetPatternList(
+      ExtendedEventHandler eventHandler,
+      List<String> targetPatterns,
+      FilteringPolicy policy,
+      boolean keepGoing)
       throws TargetParsingException, InterruptedException {
     return parseTargetPatternList(offset, eventHandler, targetPatterns, policy, keepGoing);
   }
 
   @Override
-  public ResolvedTargets<Target> parseTargetPattern(EventHandler eventHandler,
-      String pattern, boolean keepGoing) throws TargetParsingException, InterruptedException {
+  public ResolvedTargets<Target> parseTargetPattern(
+      ExtendedEventHandler eventHandler, String pattern, boolean keepGoing)
+      throws TargetParsingException, InterruptedException {
     return parseTargetPatternList(eventHandler, ImmutableList.of(pattern),
         DEFAULT_FILTERING_POLICY, keepGoing);
   }
@@ -74,9 +77,9 @@
   }
 
   @Override
-  public Map<String, ResolvedTargets<Target>> preloadTargetPatterns(EventHandler eventHandler,
-      Collection<String> patterns, boolean keepGoing)
-          throws TargetParsingException, InterruptedException {
+  public Map<String, ResolvedTargets<Target>> preloadTargetPatterns(
+      ExtendedEventHandler eventHandler, Collection<String> patterns, boolean keepGoing)
+      throws TargetParsingException, InterruptedException {
     // TODO(bazel-team): This is used only in "blaze query". There are plans to dramatically change
     // how query works on Skyframe, in which case this method is likely to go away.
     // We cannot use an ImmutableMap here because there may be null values.
@@ -92,8 +95,12 @@
    * Loads a list of target patterns (eg, "foo/..."). When policy is set to FILTER_TESTS,
    * test_suites are going to be expanded.
    */
-  ResolvedTargets<Target> parseTargetPatternList(String offset, EventHandler eventHandler,
-      List<String> targetPatterns, FilteringPolicy policy, boolean keepGoing)
+  ResolvedTargets<Target> parseTargetPatternList(
+      String offset,
+      ExtendedEventHandler eventHandler,
+      List<String> targetPatterns,
+      FilteringPolicy policy,
+      boolean keepGoing)
       throws InterruptedException, TargetParsingException {
     Iterable<TargetPatternSkyKeyOrException> keysMaybe =
         TargetPatternValue.keys(targetPatterns, policy, offset);
@@ -118,16 +125,19 @@
         eventHandler, createTargetPatternEvaluatorUtil(policy, eventHandler, keepGoing));
   }
 
-  private TargetPatternsResultBuilder createTargetPatternEvaluatorUtil(FilteringPolicy policy,
-      EventHandler eventHandler, boolean keepGoing) {
+  private TargetPatternsResultBuilder createTargetPatternEvaluatorUtil(
+      FilteringPolicy policy, ExtendedEventHandler eventHandler, boolean keepGoing) {
     return policy == FilteringPolicies.FILTER_TESTS
         ? new TestTargetPatternsResultBuilder(skyframeExecutor.getPackageManager(), eventHandler,
           keepGoing)
         : new BuildTargetPatternsResultBuilder();
   }
 
-  ResolvedTargets<Target> parseTargetPatternKeys(Iterable<SkyKey> patternSkyKeys, int numThreads,
-      boolean keepGoing, EventHandler eventHandler,
+  ResolvedTargets<Target> parseTargetPatternKeys(
+      Iterable<SkyKey> patternSkyKeys,
+      int numThreads,
+      boolean keepGoing,
+      ExtendedEventHandler eventHandler,
       TargetPatternsResultBuilder finalTargetSetEvaluator)
       throws InterruptedException, TargetParsingException {
     EvaluationResult<TargetPatternValue> result =
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkylarkModuleCycleReporter.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkylarkModuleCycleReporter.java
index 3900b1b..cc713bb 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkylarkModuleCycleReporter.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkylarkModuleCycleReporter.java
@@ -21,7 +21,7 @@
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.cmdline.PackageIdentifier;
 import com.google.devtools.build.lib.events.Event;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.skyframe.CycleInfo;
 import com.google.devtools.build.skyframe.CyclesReporter;
 import com.google.devtools.build.skyframe.SkyKey;
@@ -56,8 +56,11 @@
       SkyFunctions.isSkyFunction(SkyFunctions.LOCAL_REPOSITORY_LOOKUP);
 
   @Override
-  public boolean maybeReportCycle(SkyKey topLevelKey, CycleInfo cycleInfo, boolean alreadyReported,
-      EventHandler eventHandler) {
+  public boolean maybeReportCycle(
+      SkyKey topLevelKey,
+      CycleInfo cycleInfo,
+      boolean alreadyReported,
+      ExtendedEventHandler eventHandler) {
     ImmutableList<SkyKey> pathToCycle = cycleInfo.getPathToCycle();
     ImmutableList<SkyKey> cycle = cycleInfo.getCycle();
     if (pathToCycle.isEmpty()) {
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/TestTargetPatternsResultBuilder.java b/src/main/java/com/google/devtools/build/lib/skyframe/TestTargetPatternsResultBuilder.java
index 03e3782..823d107 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/TestTargetPatternsResultBuilder.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/TestTargetPatternsResultBuilder.java
@@ -17,11 +17,10 @@
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.cmdline.ResolvedTargets;
 import com.google.devtools.build.lib.cmdline.TargetParsingException;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.lib.packages.TestTargetUtils;
 import com.google.devtools.build.lib.pkgcache.TargetProvider;
-
 import java.util.ArrayList;
 
 /**
@@ -31,7 +30,7 @@
 class TestTargetPatternsResultBuilder extends TargetPatternsResultBuilder {
   private final ArrayList<ResolvedTargetsOfPattern> labelsOfPatterns = new ArrayList<>(); 
   private final TargetProvider targetProvider;
-  private final EventHandler eventHandler;
+  private final ExtendedEventHandler eventHandler;
   private final boolean keepGoing;
 
   private static class ResolvedTargetsOfPattern {
@@ -52,8 +51,8 @@
     }
   }
 
-  TestTargetPatternsResultBuilder(TargetProvider targetProvider,
-      EventHandler eventHandler, boolean keepGoing) {
+  TestTargetPatternsResultBuilder(
+      TargetProvider targetProvider, ExtendedEventHandler eventHandler, boolean keepGoing) {
     this.targetProvider = targetProvider;
     this.eventHandler = eventHandler;
     this.keepGoing = keepGoing;
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/TransitiveTargetCycleReporter.java b/src/main/java/com/google/devtools/build/lib/skyframe/TransitiveTargetCycleReporter.java
index d2803a2..bb2e412 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/TransitiveTargetCycleReporter.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/TransitiveTargetCycleReporter.java
@@ -18,13 +18,12 @@
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 import com.google.devtools.build.lib.cmdline.Label;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.packages.PackageGroup;
 import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.lib.pkgcache.PackageProvider;
 import com.google.devtools.build.skyframe.CycleInfo;
 import com.google.devtools.build.skyframe.SkyKey;
-
 import java.util.List;
 
 /**
@@ -59,7 +58,7 @@
 
   @Override
   protected String getAdditionalMessageAboutCycle(
-      EventHandler eventHandler, SkyKey topLevelKey, CycleInfo cycleInfo) {
+      ExtendedEventHandler eventHandler, SkyKey topLevelKey, CycleInfo cycleInfo) {
     Target currentTarget = getTargetForLabel(eventHandler, getLabel(topLevelKey));
     List<SkyKey> keys = Lists.newArrayList();
     if (!cycleInfo.getPathToCycle().isEmpty()) {
diff --git a/src/main/java/com/google/devtools/build/skyframe/BuildDriver.java b/src/main/java/com/google/devtools/build/skyframe/BuildDriver.java
index 654dfae..ec6ccbf 100644
--- a/src/main/java/com/google/devtools/build/skyframe/BuildDriver.java
+++ b/src/main/java/com/google/devtools/build/skyframe/BuildDriver.java
@@ -14,7 +14,7 @@
 
 package com.google.devtools.build.skyframe;
 
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.util.AbruptExitException;
 import com.google.devtools.common.options.OptionsClassProvider;
 import javax.annotation.Nullable;
@@ -22,11 +22,11 @@
 /** A BuildDriver wraps a MemoizingEvaluator, passing along the proper Version. */
 public interface BuildDriver {
   /**
-   * See {@link MemoizingEvaluator#evaluate}, which has the same semantics except for the
-   * inclusion of a {@link Version} value.
+   * See {@link MemoizingEvaluator#evaluate}, which has the same semantics except for the inclusion
+   * of a {@link Version} value.
    */
   <T extends SkyValue> EvaluationResult<T> evaluate(
-      Iterable<SkyKey> roots, boolean keepGoing, int numThreads, EventHandler reporter)
+      Iterable<SkyKey> roots, boolean keepGoing, int numThreads, ExtendedEventHandler reporter)
       throws InterruptedException;
 
   /**
diff --git a/src/main/java/com/google/devtools/build/skyframe/CyclesReporter.java b/src/main/java/com/google/devtools/build/skyframe/CyclesReporter.java
index c7aa46e..2a4e999 100644
--- a/src/main/java/com/google/devtools/build/skyframe/CyclesReporter.java
+++ b/src/main/java/com/google/devtools/build/skyframe/CyclesReporter.java
@@ -14,7 +14,7 @@
 package com.google.devtools.build.skyframe;
 
 import com.google.common.collect.ImmutableList;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.util.Preconditions;
 
 /**
@@ -33,17 +33,20 @@
   public interface SingleCycleReporter {
 
     /**
-     * Reports the given cycle and returns {@code true}, or return {@code false} if this
-     * {@link SingleCycleReporter} doesn't know how to report the cycle.
+     * Reports the given cycle and returns {@code true}, or return {@code false} if this {@link
+     * SingleCycleReporter} doesn't know how to report the cycle.
      *
      * @param topLevelKey the top level key that transitively depended on the cycle
      * @param cycleInfo the cycle
-     * @param alreadyReported whether the cycle has already been reported to the
-     *        {@link CyclesReporter}.
+     * @param alreadyReported whether the cycle has already been reported to the {@link
+     *     CyclesReporter}.
      * @param eventHandler the eventHandler to which to report the error
      */
-    boolean maybeReportCycle(SkyKey topLevelKey, CycleInfo cycleInfo, boolean alreadyReported,
-        EventHandler eventHandler);
+    boolean maybeReportCycle(
+        SkyKey topLevelKey,
+        CycleInfo cycleInfo,
+        boolean alreadyReported,
+        ExtendedEventHandler eventHandler);
   }
 
   private final ImmutableList<SingleCycleReporter> cycleReporters;
@@ -64,8 +67,8 @@
    * @param topLevelKey This key represents the top level value key that returned cycle errors.
    * @param eventHandler the eventHandler to which to report the error
    */
-  public void reportCycles(Iterable<CycleInfo> cycles, SkyKey topLevelKey,
-      EventHandler eventHandler) {
+  public void reportCycles(
+      Iterable<CycleInfo> cycles, SkyKey topLevelKey, ExtendedEventHandler eventHandler) {
     Preconditions.checkNotNull(eventHandler);
     for (CycleInfo cycleInfo : cycles) {
       boolean alreadyReported = false;
diff --git a/src/main/java/com/google/devtools/build/skyframe/InMemoryMemoizingEvaluator.java b/src/main/java/com/google/devtools/build/skyframe/InMemoryMemoizingEvaluator.java
index c0f0ed4..68998b3 100644
--- a/src/main/java/com/google/devtools/build/skyframe/InMemoryMemoizingEvaluator.java
+++ b/src/main/java/com/google/devtools/build/skyframe/InMemoryMemoizingEvaluator.java
@@ -21,7 +21,7 @@
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 import com.google.devtools.build.lib.events.Event;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.util.Preconditions;
 import com.google.devtools.build.skyframe.Differencer.Diff;
 import com.google.devtools.build.skyframe.InvalidatingNodeVisitor.DeletingInvalidationState;
@@ -136,8 +136,12 @@
   }
 
   @Override
-  public <T extends SkyValue> EvaluationResult<T> evaluate(Iterable<SkyKey> roots, Version version,
-          boolean keepGoing, int numThreads, EventHandler eventHandler)
+  public <T extends SkyValue> EvaluationResult<T> evaluate(
+      Iterable<SkyKey> roots,
+      Version version,
+      boolean keepGoing,
+      int numThreads,
+      ExtendedEventHandler eventHandler)
       throws InterruptedException {
     // NOTE: Performance critical code. See bug "Null build performance parity".
     IntVersion intVersion = (IntVersion) version;
diff --git a/src/main/java/com/google/devtools/build/skyframe/MemoizingEvaluator.java b/src/main/java/com/google/devtools/build/skyframe/MemoizingEvaluator.java
index 114ccb4..d690c4a 100644
--- a/src/main/java/com/google/devtools/build/skyframe/MemoizingEvaluator.java
+++ b/src/main/java/com/google/devtools/build/skyframe/MemoizingEvaluator.java
@@ -18,7 +18,7 @@
 import com.google.common.collect.ImmutableMap;
 import com.google.devtools.build.lib.collect.nestedset.NestedSetVisitor;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadHostile;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import java.io.PrintStream;
 import java.util.Map;
 import javax.annotation.Nullable;
@@ -49,8 +49,8 @@
       Version version,
       boolean keepGoing,
       int numThreads,
-      EventHandler reporter)
-          throws InterruptedException;
+      ExtendedEventHandler reporter)
+      throws InterruptedException;
 
   /**
    * Ensures that after the next completed {@link #evaluate} call the current values of any value
diff --git a/src/main/java/com/google/devtools/build/skyframe/ParallelEvaluator.java b/src/main/java/com/google/devtools/build/skyframe/ParallelEvaluator.java
index d904805..34515c8 100644
--- a/src/main/java/com/google/devtools/build/skyframe/ParallelEvaluator.java
+++ b/src/main/java/com/google/devtools/build/skyframe/ParallelEvaluator.java
@@ -22,7 +22,7 @@
 import com.google.common.collect.Iterables;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadCompatible;
 import com.google.devtools.build.lib.events.Event;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.profiler.Profiler;
 import com.google.devtools.build.lib.profiler.ProfilerTask;
 import com.google.devtools.build.lib.util.BlazeClock;
@@ -100,7 +100,7 @@
       ProcessableGraph graph,
       Version graphVersion,
       ImmutableMap<SkyFunctionName, ? extends SkyFunction> skyFunctions,
-      final EventHandler reporter,
+      final ExtendedEventHandler reporter,
       EmittedEventState emittedEventState,
       EventFilter storedEventFilter,
       boolean keepGoing,
@@ -127,7 +127,7 @@
       ProcessableGraph graph,
       Version graphVersion,
       ImmutableMap<SkyFunctionName, ? extends SkyFunction> skyFunctions,
-      final EventHandler reporter,
+      final ExtendedEventHandler reporter,
       EmittedEventState emittedEventState,
       EventFilter storedEventFilter,
       boolean keepGoing,
diff --git a/src/main/java/com/google/devtools/build/skyframe/ParallelEvaluatorContext.java b/src/main/java/com/google/devtools/build/skyframe/ParallelEvaluatorContext.java
index 9365ffa..49782ce 100644
--- a/src/main/java/com/google/devtools/build/skyframe/ParallelEvaluatorContext.java
+++ b/src/main/java/com/google/devtools/build/skyframe/ParallelEvaluatorContext.java
@@ -19,7 +19,7 @@
 import com.google.common.collect.ImmutableMap;
 import com.google.devtools.build.lib.collect.nestedset.NestedSetVisitor;
 import com.google.devtools.build.lib.events.Event;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.util.Preconditions;
 import com.google.devtools.build.skyframe.MemoizingEvaluator.EmittedEventState;
 import com.google.devtools.build.skyframe.QueryableGraph.Reason;
@@ -44,7 +44,7 @@
   private final QueryableGraph graph;
   private final Version graphVersion;
   private final ImmutableMap<SkyFunctionName, ? extends SkyFunction> skyFunctions;
-  private final EventHandler reporter;
+  private final ExtendedEventHandler reporter;
   private final NestedSetVisitor<TaggedEvents> replayingNestedSetEventVisitor;
   private final boolean keepGoing;
   private final boolean storeErrorsAlongsideValues;
@@ -62,7 +62,7 @@
       QueryableGraph graph,
       Version graphVersion,
       ImmutableMap<SkyFunctionName, ? extends SkyFunction> skyFunctions,
-      EventHandler reporter,
+      ExtendedEventHandler reporter,
       EmittedEventState emittedEventState,
       boolean keepGoing,
       boolean storeErrorsAlongsideValues,
@@ -95,7 +95,7 @@
       QueryableGraph graph,
       Version graphVersion,
       ImmutableMap<SkyFunctionName, ? extends SkyFunction> skyFunctions,
-      EventHandler reporter,
+      ExtendedEventHandler reporter,
       EmittedEventState emittedEventState,
       boolean keepGoing,
       boolean storeErrorsAlongsideValues,
@@ -191,7 +191,7 @@
     return replayingNestedSetEventVisitor;
   }
 
-  EventHandler getReporter() {
+  ExtendedEventHandler getReporter() {
     return reporter;
   }
 
@@ -210,9 +210,9 @@
   /** Receives the events from the NestedSet and delegates to the reporter. */
   private static class NestedSetEventReceiver implements NestedSetVisitor.Receiver<TaggedEvents> {
 
-    private final EventHandler reporter;
+    private final ExtendedEventHandler reporter;
 
-    public NestedSetEventReceiver(EventHandler reporter) {
+    public NestedSetEventReceiver(ExtendedEventHandler reporter) {
       this.reporter = reporter;
     }
 
diff --git a/src/main/java/com/google/devtools/build/skyframe/QueryableGraphBackedSkyFunctionEnvironment.java b/src/main/java/com/google/devtools/build/skyframe/QueryableGraphBackedSkyFunctionEnvironment.java
index a528dad..684db93 100644
--- a/src/main/java/com/google/devtools/build/skyframe/QueryableGraphBackedSkyFunctionEnvironment.java
+++ b/src/main/java/com/google/devtools/build/skyframe/QueryableGraphBackedSkyFunctionEnvironment.java
@@ -15,7 +15,7 @@
 
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Maps;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.util.Preconditions;
 import com.google.devtools.build.skyframe.QueryableGraph.Reason;
 import java.util.Map;
@@ -27,10 +27,10 @@
  */
 public class QueryableGraphBackedSkyFunctionEnvironment extends AbstractSkyFunctionEnvironment {
   private final QueryableGraph queryableGraph;
-  private final EventHandler eventHandler;
+  private final ExtendedEventHandler eventHandler;
 
   public QueryableGraphBackedSkyFunctionEnvironment(
-      QueryableGraph queryableGraph, EventHandler eventHandler) {
+      QueryableGraph queryableGraph, ExtendedEventHandler eventHandler) {
     this.queryableGraph = queryableGraph;
     this.eventHandler = eventHandler;
   }
@@ -75,7 +75,7 @@
   }
 
   @Override
-  public EventHandler getListener() {
+  public ExtendedEventHandler getListener() {
     return eventHandler;
   }
 
diff --git a/src/main/java/com/google/devtools/build/skyframe/SequentialBuildDriver.java b/src/main/java/com/google/devtools/build/skyframe/SequentialBuildDriver.java
index f28a800..7f4c9fe 100644
--- a/src/main/java/com/google/devtools/build/skyframe/SequentialBuildDriver.java
+++ b/src/main/java/com/google/devtools/build/skyframe/SequentialBuildDriver.java
@@ -13,7 +13,7 @@
 // limitations under the License.
 package com.google.devtools.build.skyframe;
 
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.util.Preconditions;
 import com.google.devtools.common.options.OptionsClassProvider;
 import javax.annotation.Nullable;
@@ -32,7 +32,7 @@
 
   @Override
   public <T extends SkyValue> EvaluationResult<T> evaluate(
-      Iterable<SkyKey> roots, boolean keepGoing, int numThreads, EventHandler reporter)
+      Iterable<SkyKey> roots, boolean keepGoing, int numThreads, ExtendedEventHandler reporter)
       throws InterruptedException {
     try {
       return memoizingEvaluator.evaluate(roots, curVersion, keepGoing, numThreads, reporter);
diff --git a/src/main/java/com/google/devtools/build/skyframe/SkyFunction.java b/src/main/java/com/google/devtools/build/skyframe/SkyFunction.java
index 6bd52c6..ee1d93c 100644
--- a/src/main/java/com/google/devtools/build/skyframe/SkyFunction.java
+++ b/src/main/java/com/google/devtools/build/skyframe/SkyFunction.java
@@ -15,7 +15,7 @@
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import java.util.Map;
 import javax.annotation.Nullable;
 
@@ -267,10 +267,10 @@
     boolean valuesMissing();
 
     /**
-     * Returns the {@link EventHandler} that a SkyFunction should use to print any errors,
-     * warnings, or progress messages during execution of {@link SkyFunction#compute}.
+     * Returns the {@link EventHandler} that a SkyFunction should use to print any errors, warnings,
+     * or progress messages during execution of {@link SkyFunction#compute}.
      */
-    EventHandler getListener();
+    ExtendedEventHandler getListener();
 
     /** Returns whether we are currently in error bubbling. */
     @VisibleForTesting
diff --git a/src/main/java/com/google/devtools/build/skyframe/SkyFunctionEnvironment.java b/src/main/java/com/google/devtools/build/skyframe/SkyFunctionEnvironment.java
index 28fb512..93e90cd 100644
--- a/src/main/java/com/google/devtools/build/skyframe/SkyFunctionEnvironment.java
+++ b/src/main/java/com/google/devtools/build/skyframe/SkyFunctionEnvironment.java
@@ -27,7 +27,7 @@
 import com.google.devtools.build.lib.collect.nestedset.NestedSet;
 import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
 import com.google.devtools.build.lib.events.Event;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.events.StoredEventHandler;
 import com.google.devtools.build.lib.util.GroupedList;
 import com.google.devtools.build.lib.util.GroupedList.GroupedListHelper;
@@ -479,7 +479,7 @@
   }
 
   @Override
-  public EventHandler getListener() {
+  public ExtendedEventHandler getListener() {
     checkActive();
     return eventHandler;
   }
diff --git a/src/main/java/com/google/devtools/build/skyframe/WalkableGraph.java b/src/main/java/com/google/devtools/build/skyframe/WalkableGraph.java
index 8f3dd04..5b98079 100644
--- a/src/main/java/com/google/devtools/build/skyframe/WalkableGraph.java
+++ b/src/main/java/com/google/devtools/build/skyframe/WalkableGraph.java
@@ -14,7 +14,7 @@
 package com.google.devtools.build.skyframe;
 
 import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.skyframe.QueryableGraph.Reason;
 import java.util.Collection;
 import java.util.Map;
@@ -99,7 +99,8 @@
   /** Provides a WalkableGraph on demand after preparing it. */
   interface WalkableGraphFactory {
     EvaluationResult<SkyValue> prepareAndGet(
-        SkyKey universeKey, int numThreads, EventHandler eventHandler) throws InterruptedException;
+        SkyKey universeKey, int numThreads, ExtendedEventHandler eventHandler)
+        throws InterruptedException;
 
     /**
      * Returns true if this instance has already been used to {@link #prepareAndGet} {@code
diff --git a/src/test/java/com/google/devtools/build/lib/actions/util/ActionsTestUtil.java b/src/test/java/com/google/devtools/build/lib/actions/util/ActionsTestUtil.java
index d11392e..92eeedf 100644
--- a/src/test/java/com/google/devtools/build/lib/actions/util/ActionsTestUtil.java
+++ b/src/test/java/com/google/devtools/build/lib/actions/util/ActionsTestUtil.java
@@ -23,6 +23,7 @@
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
+import com.google.common.eventbus.EventBus;
 import com.google.devtools.build.lib.actions.AbstractAction;
 import com.google.devtools.build.lib.actions.Action;
 import com.google.devtools.build.lib.actions.ActionAnalysisMetadata;
@@ -45,6 +46,8 @@
 import com.google.devtools.build.lib.analysis.actions.SpawnActionTemplate.OutputPathMapper;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
+import com.google.devtools.build.lib.events.Reporter;
 import com.google.devtools.build.lib.exec.SingleBuildFileCache;
 import com.google.devtools.build.lib.packages.AspectDescriptor;
 import com.google.devtools.build.lib.util.FileType;
@@ -149,8 +152,12 @@
       EvaluationResult<SkyValue> evaluationResult;
       Map<SkyKey, ValueOrUntypedException> result = new HashMap<>();
       try {
-        evaluationResult = driver.evaluate(depKeys, /*keepGoing=*/false,
-            ResourceUsage.getAvailableProcessors(), eventHandler);
+        evaluationResult =
+            driver.evaluate(
+                depKeys, /*keepGoing=*/
+                false,
+                ResourceUsage.getAvailableProcessors(),
+                new Reporter(new EventBus(), eventHandler));
       } catch (InterruptedException e) {
         Thread.currentThread().interrupt();
         for (SkyKey key : depKeys) {
@@ -175,7 +182,7 @@
     }
 
     @Override
-    public EventHandler getListener() {
+    public ExtendedEventHandler getListener() {
       return null;
     }
 
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/util/AnalysisTestCase.java b/src/test/java/com/google/devtools/build/lib/analysis/util/AnalysisTestCase.java
index 0312811..98a91b8 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/util/AnalysisTestCase.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/util/AnalysisTestCase.java
@@ -280,8 +280,8 @@
     BuildConfiguration targetConfig =
         Iterables.getOnlyElement(masterConfig.getTargetConfigurations());
     if (useDynamicVersionIfEnabled && targetConfig.useDynamicConfigurations()) {
-      return skyframeExecutor.getConfigurationForTesting(eventCollector,
-          targetConfig.fragmentClasses(), targetConfig.getOptions());
+      return skyframeExecutor.getConfigurationForTesting(
+          reporter, targetConfig.fragmentClasses(), targetConfig.getOptions());
     } else {
       return targetConfig;
     }
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/util/AnalysisTestUtil.java b/src/test/java/com/google/devtools/build/lib/analysis/util/AnalysisTestUtil.java
index 50e591b..8291d8e 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/util/AnalysisTestUtil.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/util/AnalysisTestUtil.java
@@ -47,7 +47,7 @@
 import com.google.devtools.build.lib.analysis.config.BuildConfigurationCollection;
 import com.google.devtools.build.lib.cmdline.RepositoryName;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.testutil.TestConstants;
 import com.google.devtools.build.lib.vfs.FileSystemUtils;
 import com.google.devtools.build.lib.vfs.PathFragment;
@@ -109,7 +109,7 @@
     }
 
     @Override
-    public EventHandler getEventHandler() {
+    public ExtendedEventHandler getEventHandler() {
       return original.getEventHandler();
     }
 
@@ -321,7 +321,7 @@
     }
 
     @Override
-    public EventHandler getEventHandler() {
+    public ExtendedEventHandler getEventHandler() {
       return null;
     }
 
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/util/BuildViewTestCase.java b/src/test/java/com/google/devtools/build/lib/analysis/util/BuildViewTestCase.java
index 0e68cfa..5d475a2 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/util/BuildViewTestCase.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/util/BuildViewTestCase.java
@@ -89,7 +89,7 @@
 import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
 import com.google.devtools.build.lib.collect.nestedset.Order;
 import com.google.devtools.build.lib.events.Event;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.events.StoredEventHandler;
 import com.google.devtools.build.lib.exec.ExecutionOptions;
 import com.google.devtools.build.lib.flags.InvocationPolicyEnforcer;
@@ -1640,7 +1640,7 @@
     }
 
     @Override
-    public EventHandler getEventHandler() {
+    public ExtendedEventHandler getEventHandler() {
       return reporter;
     }
 
diff --git a/src/test/java/com/google/devtools/build/lib/events/EventSensorTest.java b/src/test/java/com/google/devtools/build/lib/events/EventSensorTest.java
index ff19a68..d765f23 100644
--- a/src/test/java/com/google/devtools/build/lib/events/EventSensorTest.java
+++ b/src/test/java/com/google/devtools/build/lib/events/EventSensorTest.java
@@ -17,6 +17,7 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
+import com.google.common.eventbus.EventBus;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
@@ -37,7 +38,7 @@
   @Test
   public void sensorNoticesEventsInItsMask() {
     EventSensor sensor = new EventSensor(EventKind.ERRORS);
-    Reporter reporter = new Reporter(sensor);
+    Reporter reporter = new Reporter(new EventBus(), sensor);
     reporter.handle(Event.error(location, "An ERROR event."));
     assertTrue(sensor.wasTriggered());
   }
@@ -45,7 +46,7 @@
   @Test
   public void sensorNoticesEventsInItsMask2() {
     EventSensor sensor = new EventSensor(EventKind.ALL_EVENTS);
-    Reporter reporter = new Reporter(sensor);
+    Reporter reporter = new Reporter(new EventBus(), sensor);
     reporter.handle(Event.error(location, "An ERROR event."));
     reporter.handle(Event.warn(location, "A warning event."));
     assertTrue(sensor.wasTriggered());
@@ -54,7 +55,7 @@
   @Test
   public void sensorIgnoresEventsNotInItsMask() {
     EventSensor sensor = new EventSensor(EventKind.ERRORS_AND_WARNINGS);
-    Reporter reporter = new Reporter(sensor);
+    Reporter reporter = new Reporter(new EventBus(), sensor);
     reporter.handle(Event.info(location, "An INFO event."));
     assertFalse(sensor.wasTriggered());
   }
@@ -62,7 +63,7 @@
   @Test
   public void sensorCanCount() {
     EventSensor sensor = new EventSensor(EventKind.ERRORS_AND_WARNINGS);
-    Reporter reporter = new Reporter(sensor);
+    Reporter reporter = new Reporter(new EventBus(), sensor);
     reporter.handle(Event.error(location, "An ERROR event."));
     reporter.handle(Event.error(location, "Another ERROR event."));
     reporter.handle(Event.warn(location, "A warning event."));
diff --git a/src/test/java/com/google/devtools/build/lib/events/ReporterStreamTest.java b/src/test/java/com/google/devtools/build/lib/events/ReporterStreamTest.java
index 786a4de..6c0777a 100644
--- a/src/test/java/com/google/devtools/build/lib/events/ReporterStreamTest.java
+++ b/src/test/java/com/google/devtools/build/lib/events/ReporterStreamTest.java
@@ -15,15 +15,14 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import com.google.common.eventbus.EventBus;
 import com.google.devtools.build.lib.testutil.MoreAsserts;
-
+import java.io.PrintWriter;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
-import java.io.PrintWriter;
-
 @RunWith(JUnit4.class)
 public class ReporterStreamTest {
 
@@ -33,7 +32,7 @@
 
   @Before
   public final void createOutputAppender() throws Exception  {
-    reporter = new Reporter();
+    reporter = new Reporter(new EventBus());
     out = new StringBuilder();
     outAppender = new EventHandler() {
       @Override
diff --git a/src/test/java/com/google/devtools/build/lib/events/ReporterTest.java b/src/test/java/com/google/devtools/build/lib/events/ReporterTest.java
index d385a5d..27617cb 100644
--- a/src/test/java/com/google/devtools/build/lib/events/ReporterTest.java
+++ b/src/test/java/com/google/devtools/build/lib/events/ReporterTest.java
@@ -17,7 +17,7 @@
 import static org.junit.Assert.assertEquals;
 
 import com.google.common.collect.ImmutableList;
-
+import com.google.common.eventbus.EventBus;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -35,7 +35,7 @@
 
   @Before
   public final void initializeOutput() throws Exception  {
-    reporter = new Reporter();
+    reporter = new Reporter(new EventBus());
     out = new StringBuilder();
     outAppender = new AbstractEventHandler(EventKind.ERRORS) {
       @Override
diff --git a/src/test/java/com/google/devtools/build/lib/events/SimpleReportersTest.java b/src/test/java/com/google/devtools/build/lib/events/SimpleReportersTest.java
index f7939ea..f99df10 100644
--- a/src/test/java/com/google/devtools/build/lib/events/SimpleReportersTest.java
+++ b/src/test/java/com/google/devtools/build/lib/events/SimpleReportersTest.java
@@ -15,6 +15,7 @@
 
 import static org.junit.Assert.assertEquals;
 
+import com.google.common.eventbus.EventBus;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
@@ -36,7 +37,7 @@
       }
     };
 
-    Reporter reporter = new Reporter(handler);
+    Reporter reporter = new Reporter(new EventBus(), handler);
     reporter.handle(Event.info(location, "Add to handlerCount."));
     reporter.handle(Event.info(location, "Add to handlerCount."));
     reporter.handle(Event.info(location, "Add to handlerCount."));
diff --git a/src/test/java/com/google/devtools/build/lib/events/util/EventCollectionApparatus.java b/src/test/java/com/google/devtools/build/lib/events/util/EventCollectionApparatus.java
index 05a5826..8d10452 100644
--- a/src/test/java/com/google/devtools/build/lib/events/util/EventCollectionApparatus.java
+++ b/src/test/java/com/google/devtools/build/lib/events/util/EventCollectionApparatus.java
@@ -13,6 +13,7 @@
 // limitations under the License.
 package com.google.devtools.build.lib.events.util;
 
+import com.google.common.eventbus.EventBus;
 import com.google.devtools.build.lib.events.Event;
 import com.google.devtools.build.lib.events.EventCollector;
 import com.google.devtools.build.lib.events.EventHandler;
@@ -22,7 +23,6 @@
 import com.google.devtools.build.lib.syntax.Environment;
 import com.google.devtools.build.lib.testutil.MoreAsserts;
 import com.google.devtools.build.lib.util.io.OutErr;
-
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
@@ -45,7 +45,7 @@
   public EventCollectionApparatus(Set<EventKind> mask) {
     eventCollector = new EventCollector(mask);
     printingEventHandler = new PrintingEventHandler(EventKind.ERRORS_AND_WARNINGS_AND_OUTPUT);
-    reporter = new Reporter(eventCollector, printingEventHandler);
+    reporter = new Reporter(new EventBus(), eventCollector, printingEventHandler);
     this.setFailFast(true);
   }
 
diff --git a/src/test/java/com/google/devtools/build/lib/exec/BlazeExecutorTest.java b/src/test/java/com/google/devtools/build/lib/exec/BlazeExecutorTest.java
index 105829a..05c65a7 100644
--- a/src/test/java/com/google/devtools/build/lib/exec/BlazeExecutorTest.java
+++ b/src/test/java/com/google/devtools/build/lib/exec/BlazeExecutorTest.java
@@ -17,6 +17,7 @@
 
 import com.google.common.base.Predicate;
 import com.google.common.collect.Iterables;
+import com.google.common.eventbus.EventBus;
 import com.google.devtools.build.lib.actions.SpawnActionContext;
 import com.google.devtools.build.lib.analysis.BlazeDirectories;
 import com.google.devtools.build.lib.analysis.config.BinTools;
@@ -60,7 +61,7 @@
     OptionsParser parser = OptionsParser.newOptionsParser(TestExecutorBuilder.DEFAULT_OPTIONS);
     parser.parse("--debug_print_action_contexts");
 
-    Reporter reporter = new Reporter();
+    Reporter reporter = new Reporter(new EventBus());
     StoredEventHandler storedEventHandler = new StoredEventHandler();
     reporter.addHandler(storedEventHandler);
 
diff --git a/src/test/java/com/google/devtools/build/lib/exec/util/TestExecutorBuilder.java b/src/test/java/com/google/devtools/build/lib/exec/util/TestExecutorBuilder.java
index 972fd9e..d18e004 100644
--- a/src/test/java/com/google/devtools/build/lib/exec/util/TestExecutorBuilder.java
+++ b/src/test/java/com/google/devtools/build/lib/exec/util/TestExecutorBuilder.java
@@ -45,8 +45,8 @@
   public static final List<Class<? extends OptionsBase>> DEFAULT_OPTIONS = ImmutableList.of(
       ExecutionOptions.class, CommonCommandOptions.class);
   private final BlazeDirectories directories;
-  private Reporter reporter = new Reporter();
   private EventBus bus = new EventBus();
+  private Reporter reporter = new Reporter(bus);
   private OptionsParser optionsParser = OptionsParser.newOptionsParser(DEFAULT_OPTIONS);
   private List<ActionContext> strategies = new ArrayList<>();
   private Map<String, SpawnActionContext> spawnStrategyMap =
diff --git a/src/test/java/com/google/devtools/build/lib/packages/PackageFactoryTest.java b/src/test/java/com/google/devtools/build/lib/packages/PackageFactoryTest.java
index 972b2fe..836ed6c 100644
--- a/src/test/java/com/google/devtools/build/lib/packages/PackageFactoryTest.java
+++ b/src/test/java/com/google/devtools/build/lib/packages/PackageFactoryTest.java
@@ -26,6 +26,7 @@
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
+import com.google.common.eventbus.EventBus;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.cmdline.PackageIdentifier;
 import com.google.devtools.build.lib.events.Reporter;
@@ -70,7 +71,7 @@
 
     final Semaphore beforeError = new Semaphore(0);
     final Semaphore afterError = new Semaphore(0);
-    Reporter reporter = new Reporter();
+    Reporter reporter = new Reporter(new EventBus());
     ParsingTracker parser = new ParsingTracker(beforeError, afterError, reporter);
     final Logger log = Logger.getLogger(PackageFactory.class.getName());
     log.addHandler(parser);
diff --git a/src/test/java/com/google/devtools/build/lib/packages/RuleFactoryTest.java b/src/test/java/com/google/devtools/build/lib/packages/RuleFactoryTest.java
index 95d3c45..a2d34f3 100644
--- a/src/test/java/com/google/devtools/build/lib/packages/RuleFactoryTest.java
+++ b/src/test/java/com/google/devtools/build/lib/packages/RuleFactoryTest.java
@@ -22,6 +22,7 @@
 
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
+import com.google.common.eventbus.EventBus;
 import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.cmdline.PackageIdentifier;
@@ -32,14 +33,12 @@
 import com.google.devtools.build.lib.syntax.Type;
 import com.google.devtools.build.lib.testutil.TestRuleClassProvider;
 import com.google.devtools.build.lib.vfs.Path;
-
+import java.util.HashMap;
+import java.util.Map;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
-import java.util.HashMap;
-import java.util.Map;
-
 @RunWith(JUnit4.class)
 public class RuleFactoryTest extends PackageLoadingTestCase {
 
@@ -67,7 +66,7 @@
             pkgBuilder,
             ruleClass,
             new BuildLangTypedAttributeValuesMap(attributeValues),
-            new Reporter(),
+            new Reporter(new EventBus()),
             /*ast=*/ null,
             LOCATION_42,
             /*env=*/ null,
@@ -128,7 +127,7 @@
             pkgBuilder,
             ruleClass,
             new BuildLangTypedAttributeValuesMap(attributeValues),
-            new Reporter(),
+            new Reporter(new EventBus()),
             /*ast=*/ null,
             Location.fromFileAndOffsets(myPkgPath.asFragment(), 42, 42),
             /*env=*/ null,
@@ -154,7 +153,7 @@
           pkgBuilder,
           ruleClass,
           new BuildLangTypedAttributeValuesMap(attributeValues),
-          new Reporter(),
+          new Reporter(new EventBus()),
           /*ast=*/ null,
           LOCATION_42,
           /*env=*/ null,
@@ -183,7 +182,7 @@
           pkgBuilder,
           ruleClass,
           new BuildLangTypedAttributeValuesMap(attributeValues),
-          new Reporter(),
+          new Reporter(new EventBus()),
           /*ast=*/ null,
           Location.fromFileAndOffsets(myPkgPath.asFragment(), 42, 42),
           /*env=*/ null,
@@ -223,7 +222,7 @@
           pkgBuilder,
           ruleClass,
           new BuildLangTypedAttributeValuesMap(attributeValues),
-          new Reporter(),
+          new Reporter(new EventBus()),
           /*ast=*/ null,
           Location.fromFileAndOffsets(myPkgPath.asFragment(), 42, 42),
           /*env=*/ null,
diff --git a/src/test/java/com/google/devtools/build/lib/packages/TestTargetUtilsTest.java b/src/test/java/com/google/devtools/build/lib/packages/TestTargetUtilsTest.java
index 53f21bb..0258d52 100644
--- a/src/test/java/com/google/devtools/build/lib/packages/TestTargetUtilsTest.java
+++ b/src/test/java/com/google/devtools/build/lib/packages/TestTargetUtilsTest.java
@@ -27,7 +27,7 @@
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.cmdline.ResolvedTargets;
 import com.google.devtools.build.lib.cmdline.TargetParsingException;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.packages.util.PackageLoadingTestCase;
 import com.google.devtools.build.lib.pkgcache.TargetProvider;
 import com.google.devtools.build.lib.skyframe.TestSuiteExpansionValue;
@@ -198,7 +198,7 @@
       TestTargetUtils.expandTestSuites(
           new TargetProvider() {
             @Override
-            public Target getTarget(EventHandler eventHandler, Label label)
+            public Target getTarget(ExtendedEventHandler eventHandler, Label label)
                 throws InterruptedException {
               throw new InterruptedException();
             }
diff --git a/src/test/java/com/google/devtools/build/lib/pkgcache/AbstractTargetPatternEvaluatorTest.java b/src/test/java/com/google/devtools/build/lib/pkgcache/AbstractTargetPatternEvaluatorTest.java
index 8464cef..904a97f 100644
--- a/src/test/java/com/google/devtools/build/lib/pkgcache/AbstractTargetPatternEvaluatorTest.java
+++ b/src/test/java/com/google/devtools/build/lib/pkgcache/AbstractTargetPatternEvaluatorTest.java
@@ -20,20 +20,18 @@
 import com.google.devtools.build.lib.cmdline.ResolvedTargets;
 import com.google.devtools.build.lib.cmdline.TargetParsingException;
 import com.google.devtools.build.lib.events.DelegatingEventHandler;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.packages.ConstantRuleVisibility;
 import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.lib.packages.util.PackageLoadingTestCase;
 import com.google.devtools.build.lib.util.Pair;
-
-import org.junit.Before;
-
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 import java.util.TreeSet;
+import org.junit.Before;
 
 /**
  * Abstract framework for target pattern evaluation tests. The {@link TargetPatternEvaluatorTest}
@@ -45,17 +43,22 @@
   protected RecordingParsingListener parsingListener;
 
   protected static ResolvedTargets<Target> parseTargetPatternList(
-      TargetPatternEvaluator parser, EventHandler eventHandler,
-      List<String> targetPatterns, boolean keepGoing)
-          throws TargetParsingException, InterruptedException {
+      TargetPatternEvaluator parser,
+      ExtendedEventHandler eventHandler,
+      List<String> targetPatterns,
+      boolean keepGoing)
+      throws TargetParsingException, InterruptedException {
     return parseTargetPatternList(
         parser, eventHandler, targetPatterns, FilteringPolicies.NO_FILTER, keepGoing);
   }
 
   protected static ResolvedTargets<Target> parseTargetPatternList(
-      TargetPatternEvaluator parser, EventHandler eventHandler,
-      List<String> targetPatterns, FilteringPolicy policy,
-      boolean keepGoing) throws TargetParsingException, InterruptedException {
+      TargetPatternEvaluator parser,
+      ExtendedEventHandler eventHandler,
+      List<String> targetPatterns,
+      FilteringPolicy policy,
+      boolean keepGoing)
+      throws TargetParsingException, InterruptedException {
     return parser.parseTargetPatternList(eventHandler, targetPatterns, policy, keepGoing);
   }
 
@@ -98,7 +101,7 @@
       implements ParseFailureListener {
     protected final List<Pair<String, String>> events = new ArrayList<>();
 
-    private RecordingParsingListener(EventHandler delegate) {
+    private RecordingParsingListener(ExtendedEventHandler delegate) {
       super(delegate);
     }
 
diff --git a/src/test/java/com/google/devtools/build/lib/pkgcache/IncrementalLoadingTest.java b/src/test/java/com/google/devtools/build/lib/pkgcache/IncrementalLoadingTest.java
index 7527f88..de78d51 100644
--- a/src/test/java/com/google/devtools/build/lib/pkgcache/IncrementalLoadingTest.java
+++ b/src/test/java/com/google/devtools/build/lib/pkgcache/IncrementalLoadingTest.java
@@ -23,6 +23,7 @@
 import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.eventbus.EventBus;
 import com.google.devtools.build.lib.analysis.BlazeDirectories;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.events.Reporter;
@@ -449,7 +450,7 @@
     private final ManualClock clock;
     private final Path workspace;
     private final Path outputBase;
-    private final Reporter reporter = new Reporter();
+    private final Reporter reporter = new Reporter(new EventBus());
     private final SkyframeExecutor skyframeExecutor;
     private final List<Path> changes = new ArrayList<>();
     private boolean everythingModified = false;
@@ -588,8 +589,8 @@
           ImmutableMap.<String, String>of(),
           new TimestampGranularityMonitor(BlazeClock.instance()));
       skyframeExecutor.invalidateFilesUnderPathForTesting(
-          new Reporter(), modifiedFileSet, workspace);
-      ((SequencedSkyframeExecutor) skyframeExecutor).handleDiffs(new Reporter());
+          new Reporter(new EventBus()), modifiedFileSet, workspace);
+      ((SequencedSkyframeExecutor) skyframeExecutor).handleDiffs(new Reporter(new EventBus()));
 
       changes.clear();
     }
diff --git a/src/test/java/com/google/devtools/build/lib/rules/cpp/CcCommonTest.java b/src/test/java/com/google/devtools/build/lib/rules/cpp/CcCommonTest.java
index 466e061..f25c425 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/cpp/CcCommonTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/cpp/CcCommonTest.java
@@ -547,7 +547,7 @@
         "    path = '/foo')");
     getSkyframeExecutor()
         .invalidateFilesUnderPathForTesting(
-            eventCollector,
+            reporter,
             new ModifiedFileSet.Builder().modify(new PathFragment("WORKSPACE")).build(),
             rootDirectory);
     FileSystemUtils.createDirectoryAndParents(scratch.resolve("/foo/bar"));
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/PrepareDepsOfPatternsFunctionSmartNegationTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/PrepareDepsOfPatternsFunctionSmartNegationTest.java
index dbbcf49..50c3a2c 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/PrepareDepsOfPatternsFunctionSmartNegationTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/PrepareDepsOfPatternsFunctionSmartNegationTest.java
@@ -19,9 +19,11 @@
 import static org.junit.Assert.assertTrue;
 
 import com.google.common.collect.ImmutableList;
+import com.google.common.eventbus.EventBus;
 import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.cmdline.PackageIdentifier;
+import com.google.devtools.build.lib.events.Reporter;
 import com.google.devtools.build.lib.util.Preconditions;
 import com.google.devtools.build.lib.vfs.PathFragment;
 import com.google.devtools.build.skyframe.EvaluationResult;
@@ -139,7 +141,11 @@
     EvaluationResult<SkyValue> evaluationResult =
         getSkyframeExecutor()
             .getDriverForTesting()
-            .evaluate(singletonTargetPattern, keepGoing, LOADING_PHASE_THREADS, eventCollector);
+            .evaluate(
+                singletonTargetPattern,
+                keepGoing,
+                LOADING_PHASE_THREADS,
+                new Reporter(new EventBus(), eventCollector));
     // The evaluation has no errors if success was expected.
     assertThat(evaluationResult.hasError()).isNotEqualTo(successExpected);
     return Preconditions.checkNotNull(evaluationResult.getWalkableGraph());
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/PrepareDepsOfPatternsFunctionTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/PrepareDepsOfPatternsFunctionTest.java
index cda7fbc..0afcbed 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/PrepareDepsOfPatternsFunctionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/PrepareDepsOfPatternsFunctionTest.java
@@ -22,8 +22,10 @@
 import static org.junit.Assert.assertTrue;
 
 import com.google.common.collect.ImmutableList;
+import com.google.common.eventbus.EventBus;
 import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
 import com.google.devtools.build.lib.cmdline.Label;
+import com.google.devtools.build.lib.events.Reporter;
 import com.google.devtools.build.lib.packages.NoSuchPackageException;
 import com.google.devtools.build.lib.packages.NoSuchTargetException;
 import com.google.devtools.build.lib.util.Preconditions;
@@ -208,7 +210,11 @@
     EvaluationResult<SkyValue> evaluationResult =
         getSkyframeExecutor()
             .getDriverForTesting()
-            .evaluate(singletonTargetPattern, keepGoing, LOADING_PHASE_THREADS, eventCollector);
+            .evaluate(
+                singletonTargetPattern,
+                keepGoing,
+                LOADING_PHASE_THREADS,
+                new Reporter(new EventBus(), eventCollector));
     // Currently all callers either expect success or pass keepGoing=true, which implies success,
     // since PrepareDepsOfPatternsFunction swallows all errors. Will need to be changed if a test
     // that evaluates with keepGoing=false and expects errors is added.
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/util/SkyframeExecutorTestUtils.java b/src/test/java/com/google/devtools/build/lib/skyframe/util/SkyframeExecutorTestUtils.java
index f0a81f1..21ba998 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/util/SkyframeExecutorTestUtils.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/util/SkyframeExecutorTestUtils.java
@@ -21,7 +21,7 @@
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
 import com.google.devtools.build.lib.cmdline.Label;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.packages.NoSuchTargetException;
 import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.lib.skyframe.ConfiguredTargetValue;
@@ -62,13 +62,13 @@
     return skyframeExecutor.getEvaluatorForTesting().getExistingErrorForTesting(key);
   }
 
-  /**
-   * Calls {@link MemoizingEvaluator#evaluate} on the given {@link SkyframeExecutor}'s
-   * graph.
-   */
+  /** Calls {@link MemoizingEvaluator#evaluate} on the given {@link SkyframeExecutor}'s graph. */
   public static <T extends SkyValue> EvaluationResult<T> evaluate(
-      SkyframeExecutor skyframeExecutor, SkyKey key, boolean keepGoing,
-      EventHandler errorEventListener) throws InterruptedException {
+      SkyframeExecutor skyframeExecutor,
+      SkyKey key,
+      boolean keepGoing,
+      ExtendedEventHandler errorEventListener)
+      throws InterruptedException {
     return skyframeExecutor.getDriverForTesting().evaluate(ImmutableList.of(key), keepGoing,
         SkyframeExecutor.DEFAULT_THREAD_COUNT, errorEventListener);
   }
diff --git a/src/test/java/com/google/devtools/build/lib/standalone/StandaloneSpawnStrategyTest.java b/src/test/java/com/google/devtools/build/lib/standalone/StandaloneSpawnStrategyTest.java
index d05a44e..c9578bf 100644
--- a/src/test/java/com/google/devtools/build/lib/standalone/StandaloneSpawnStrategyTest.java
+++ b/src/test/java/com/google/devtools/build/lib/standalone/StandaloneSpawnStrategyTest.java
@@ -60,7 +60,8 @@
 @RunWith(JUnit4.class)
 public class StandaloneSpawnStrategyTest {
 
-  private Reporter reporter = new Reporter(PrintingEventHandler.ERRORS_AND_WARNINGS_TO_STDERR);
+  private Reporter reporter =
+      new Reporter(new EventBus(), PrintingEventHandler.ERRORS_AND_WARNINGS_TO_STDERR);
   private BlazeExecutor executor;
   private FileSystem fileSystem;
 
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/LexerTest.java b/src/test/java/com/google/devtools/build/lib/syntax/LexerTest.java
index 311922e..10da1ad 100644
--- a/src/test/java/com/google/devtools/build/lib/syntax/LexerTest.java
+++ b/src/test/java/com/google/devtools/build/lib/syntax/LexerTest.java
@@ -17,13 +17,13 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
+import com.google.common.eventbus.EventBus;
 import com.google.devtools.build.lib.events.Event;
 import com.google.devtools.build.lib.events.EventHandler;
 import com.google.devtools.build.lib.events.EventKind;
 import com.google.devtools.build.lib.events.Location;
 import com.google.devtools.build.lib.events.Reporter;
 import com.google.devtools.build.lib.vfs.PathFragment;
-
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
@@ -43,7 +43,7 @@
   private Lexer createLexer(String input) {
     PathFragment somePath = new PathFragment("/some/path.txt");
     ParserInputSource inputSource = ParserInputSource.create(input, somePath);
-    Reporter reporter = new Reporter();
+    Reporter reporter = new Reporter(new EventBus());
     reporter.addHandler(new EventHandler() {
       @Override
       public void handle(Event event) {
diff --git a/src/test/java/com/google/devtools/build/lib/testutil/FoundationTestCase.java b/src/test/java/com/google/devtools/build/lib/testutil/FoundationTestCase.java
index 098a4dd..e333784 100644
--- a/src/test/java/com/google/devtools/build/lib/testutil/FoundationTestCase.java
+++ b/src/test/java/com/google/devtools/build/lib/testutil/FoundationTestCase.java
@@ -15,6 +15,7 @@
 
 import static org.junit.Assert.fail;
 
+import com.google.common.eventbus.EventBus;
 import com.google.devtools.build.lib.events.Event;
 import com.google.devtools.build.lib.events.EventCollector;
 import com.google.devtools.build.lib.events.EventHandler;
@@ -75,7 +76,7 @@
   @Before
   public final void initializeLogging() throws Exception {
     eventCollector = new EventCollector(EventKind.ERRORS_AND_WARNINGS);
-    reporter = new Reporter(eventCollector);
+    reporter = new Reporter(new EventBus(), eventCollector);
     reporter.addHandler(failFastHandler);
   }
 
diff --git a/src/test/java/com/google/devtools/build/skyframe/CyclesReporterTest.java b/src/test/java/com/google/devtools/build/skyframe/CyclesReporterTest.java
index ab17456..e009493 100644
--- a/src/test/java/com/google/devtools/build/skyframe/CyclesReporterTest.java
+++ b/src/test/java/com/google/devtools/build/skyframe/CyclesReporterTest.java
@@ -16,16 +16,14 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.collect.ImmutableList;
-import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.events.NullEventHandler;
 import com.google.devtools.build.skyframe.CyclesReporter.SingleCycleReporter;
-
+import java.util.concurrent.atomic.AtomicBoolean;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
-import java.util.concurrent.atomic.AtomicBoolean;
-
 @RunWith(JUnit4.class)
 public class CyclesReporterTest {
 
@@ -44,13 +42,17 @@
 
   @Test
   public void notReportedAssertion() {
-    SingleCycleReporter singleReporter = new SingleCycleReporter() {
-      @Override
-      public boolean maybeReportCycle(SkyKey topLevelKey, CycleInfo cycleInfo,
-          boolean alreadyReported, EventHandler eventHandler) {
-        return false;
-      }
-    };
+    SingleCycleReporter singleReporter =
+        new SingleCycleReporter() {
+          @Override
+          public boolean maybeReportCycle(
+              SkyKey topLevelKey,
+              CycleInfo cycleInfo,
+              boolean alreadyReported,
+              ExtendedEventHandler eventHandler) {
+            return false;
+          }
+        };
 
     CycleInfo cycleInfo = new CycleInfo(ImmutableList.of(DUMMY_KEY));
     CyclesReporter cyclesReporter = new CyclesReporter(singleReporter);
@@ -66,14 +68,18 @@
   @Test
   public void smoke() {
     final AtomicBoolean reported = new AtomicBoolean();
-    SingleCycleReporter singleReporter = new SingleCycleReporter() {
-      @Override
-      public boolean maybeReportCycle(SkyKey topLevelKey, CycleInfo cycleInfo,
-          boolean alreadyReported, EventHandler eventHandler) {
-        reported.set(true);
-        return true;
-      }
-    };
+    SingleCycleReporter singleReporter =
+        new SingleCycleReporter() {
+          @Override
+          public boolean maybeReportCycle(
+              SkyKey topLevelKey,
+              CycleInfo cycleInfo,
+              boolean alreadyReported,
+              ExtendedEventHandler eventHandler) {
+            reported.set(true);
+            return true;
+          }
+        };
 
     CycleInfo cycleInfo = new CycleInfo(ImmutableList.of(DUMMY_KEY));
     CyclesReporter cyclesReporter = new CyclesReporter(singleReporter);
diff --git a/src/test/java/com/google/devtools/build/skyframe/EagerInvalidatorTest.java b/src/test/java/com/google/devtools/build/skyframe/EagerInvalidatorTest.java
index 428bff5..cfb656b 100644
--- a/src/test/java/com/google/devtools/build/skyframe/EagerInvalidatorTest.java
+++ b/src/test/java/com/google/devtools/build/skyframe/EagerInvalidatorTest.java
@@ -27,6 +27,7 @@
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Sets;
+import com.google.common.eventbus.EventBus;
 import com.google.common.testing.GcFinalization;
 import com.google.devtools.build.lib.concurrent.AbstractQueueVisitor;
 import com.google.devtools.build.lib.events.Reporter;
@@ -137,7 +138,7 @@
 
   protected <T extends SkyValue> EvaluationResult<T> eval(boolean keepGoing, SkyKey... keys)
     throws InterruptedException {
-    Reporter reporter = new Reporter();
+    Reporter reporter = new Reporter(new EventBus());
     ParallelEvaluator evaluator =
         new ParallelEvaluator(
             graph,
diff --git a/src/test/java/com/google/devtools/build/skyframe/MemoizingEvaluatorTest.java b/src/test/java/com/google/devtools/build/skyframe/MemoizingEvaluatorTest.java
index 23200e2..461047d 100644
--- a/src/test/java/com/google/devtools/build/skyframe/MemoizingEvaluatorTest.java
+++ b/src/test/java/com/google/devtools/build/skyframe/MemoizingEvaluatorTest.java
@@ -38,13 +38,15 @@
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
+import com.google.common.eventbus.EventBus;
 import com.google.common.testing.GcFinalization;
 import com.google.common.util.concurrent.Uninterruptibles;
 import com.google.devtools.build.lib.events.DelegatingEventHandler;
 import com.google.devtools.build.lib.events.Event;
 import com.google.devtools.build.lib.events.EventCollector;
-import com.google.devtools.build.lib.events.EventHandler;
 import com.google.devtools.build.lib.events.EventKind;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
+import com.google.devtools.build.lib.events.Reporter;
 import com.google.devtools.build.lib.testutil.TestThread;
 import com.google.devtools.build.lib.testutil.TestUtils;
 import com.google.devtools.build.lib.util.Preconditions;
@@ -82,7 +84,7 @@
 
   protected MemoizingEvaluatorTester tester;
   private EventCollector eventCollector;
-  private EventHandler reporter;
+  private ExtendedEventHandler reporter;
   protected MemoizingEvaluator.EmittedEventState emittedEventState;
 
   // Knobs that control the size / duration of larger tests.
@@ -136,7 +138,7 @@
 
   private void initializeReporter() {
     eventCollector = new EventCollector();
-    reporter = eventCollector;
+    reporter = new Reporter(new EventBus(), eventCollector);
     tester.resetPlayedEvents();
   }
 
diff --git a/src/test/java/com/google/devtools/build/skyframe/ParallelEvaluatorTest.java b/src/test/java/com/google/devtools/build/skyframe/ParallelEvaluatorTest.java
index 0aeebc9..2097852 100644
--- a/src/test/java/com/google/devtools/build/skyframe/ParallelEvaluatorTest.java
+++ b/src/test/java/com/google/devtools/build/skyframe/ParallelEvaluatorTest.java
@@ -35,11 +35,14 @@
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
+import com.google.common.eventbus.EventBus;
 import com.google.common.util.concurrent.Uninterruptibles;
 import com.google.devtools.build.lib.events.Event;
 import com.google.devtools.build.lib.events.EventCollector;
 import com.google.devtools.build.lib.events.EventHandler;
 import com.google.devtools.build.lib.events.EventKind;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
+import com.google.devtools.build.lib.events.Reporter;
 import com.google.devtools.build.lib.testutil.TestThread;
 import com.google.devtools.build.lib.testutil.TestUtils;
 import com.google.devtools.build.skyframe.GraphTester.StringValue;
@@ -96,10 +99,11 @@
       EventFilter storedEventFilter) {
     Version oldGraphVersion = graphVersion;
     graphVersion = graphVersion.next();
-    return new ParallelEvaluator(graph,
+    return new ParallelEvaluator(
+        graph,
         oldGraphVersion,
         builders,
-        eventCollector,
+        new Reporter(new EventBus(), eventCollector),
         new MemoizingEvaluator.EmittedEventState(),
         storedEventFilter,
         keepGoing,
@@ -1838,12 +1842,15 @@
       }
     };
 
-    EventHandler reporter = new EventHandler() {
-      @Override
-      public void handle(Event e) {
-        throw new IllegalStateException();
-      }
-    };
+    ExtendedEventHandler reporter =
+        new Reporter(
+            new EventBus(),
+            new EventHandler() {
+              @Override
+              public void handle(Event e) {
+                throw new IllegalStateException();
+              }
+            });
 
     MemoizingEvaluator aug = new InMemoryMemoizingEvaluator(
         ImmutableMap.of(GraphTester.NODE_TYPE, tester.getFunction()), new RecordingDifferencer(),