You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Bazel构建中获取各规则执行耗时并实现规则执行前扩展

好问题!确实Aspect本身是在规则执行完成后才触发的,没法直接拿到启动时间,但Bazel其实有几种实用的方式可以实现完整的规则执行耗时统计,下面给你详细拆解:

方法一:用Bazel内置Profile工具(零代码最省心)

这是官方提供的最简单方案,不需要写任何自定义代码就能拿到详细的时间统计:

  • 构建时加上--profile=build.profile参数,比如:
    bazel build //your:target --profile=build.profile
    
  • 构建完成后,运行bazel analyze-profile build.profile命令,就能看到每个规则(以及对应的底层Action)的开始时间、结束时间、耗时,甚至还有CPU、内存等资源使用情况。
  • 如果需要结构化数据做后续处理,可以加上--profile_format=json参数,生成JSON格式的profile文件,方便自己解析。
方法二:自定义Action Listener(灵活定制统计逻辑)

如果需要更定制化的统计(比如把数据输出到特定日志系统、自定义格式),可以用Bazel的Experimental Action Listener特性——它能监听每个Action的开始结束事件,而规则的执行本质上是由一个或多个Action组成的,我们可以通过Action关联到对应的规则信息。

具体步骤:

  1. 写一个Java类实现com.google.devtools.build.lib.actions.ActionListener接口,这个接口有两个核心方法:actionStarted(Action启动时触发)和actionCompleted(Action结束时触发)。示例代码大概是这样:
    import com.google.devtools.build.lib.actions.Action;
    import com.google.devtools.build.lib.actions.ActionExecutionContext;
    import com.google.devtools.build.lib.actions.ActionListener;
    import com.google.devtools.build.lib.actions.ActionResult;
    import java.util.HashMap;
    import java.util.Map;
    
    public class TimingActionListener implements ActionListener {
        private final Map<Action, Long> startTimestampMap = new HashMap<>();
    
        @Override
        public void actionStarted(Action action, ActionExecutionContext context) {
            long startTime = System.currentTimeMillis();
            startTimestampMap.put(action, startTime);
            // 通过action.getOwner()拿到对应的规则信息
            String ruleLabel = action.getOwner().getLabel().toString();
            System.out.printf("[START] Rule %s at %d%n", ruleLabel, startTime);
        }
    
        @Override
        public void actionCompleted(Action action, ActionResult result, ActionExecutionContext context) {
            long startTime = startTimestampMap.getOrDefault(action, 0L);
            long duration = System.currentTimeMillis() - startTime;
            String ruleLabel = action.getOwner().getLabel().toString();
            System.out.printf("[END] Rule %s completed in %d ms, status: %s%n", 
                ruleLabel, duration, result.getExitCode());
            startTimestampMap.remove(action);
        }
    }
    
  2. 把这个类打包成JAR文件,注意要依赖Bazel的核心库(可以从Bazel安装目录下的lib文件夹获取相关依赖)。
  3. 构建时通过--experimental_action_listener参数指定这个Listener,比如:
    bazel build //your:target --experimental_action_listener=//path/to:your_timing_listener_jar
    
    你需要在WORKSPACE文件里用java_import规则引入这个JAR,确保Bazel能找到它。
方法三:结合Aspect与Build Event Protocol(BEP)

如果还是想保留Aspect的自定义逻辑,同时获取规则的启动时间,可以结合Bazel的Build Event Protocol(BEP):

  • 构建时加上--build_event_json_file=build_events.json参数,把构建过程中的所有事件(包括规则启动的targetStarted事件、规则完成的targetCompleted事件)输出到JSON文件。
  • 同时用Aspect在规则结束时补充你需要的自定义信息,之后自己解析JSON文件,将targetStartedtargetCompleted事件通过规则标签关联起来,计算耗时。
    这种方法适合需要整合Aspect逻辑和时间统计的场景。

内容的提问来源于stack exchange,提问作者lzf

火山引擎 最新活动