要为 JProfiler 开发自定义探针,您需要了解一些基本概念和术语。JProfiler 所有探针的共同基础是它们拦截特定方法,并使用拦截的方法参数和其他数据源构建一个包含您希望在 JProfiler UI 中查看的有趣信息的字符串。
定义探针时的初始问题是如何指定拦截的方法并获得一个可以使用方法参数和其他相关对象来构建字符串的环境。在 JProfiler 中,有三种不同的方法可以做到这一点:
- 脚本探针 完全在 JProfiler UI 中定义。您可以右键单击调用树中的方法,选择脚本探针操作,并在内置代码编辑器中输入字符串表达式。这对于实验探针非常有用,但仅暴露了自定义探针功能的一个非常有限的部分。
- 嵌入探针 API 可以从您自己的代码中调用。如果您编写一个库、数据库驱动程序或服务器,您可以随产品一起提供探针。任何使用 JProfiler 分析您的产品的人,都会自动将您的探针添加到 JProfiler UI 中。
- 使用 注入探针 API,您可以在 IDE 中为第三方软件编写探针,使用 JProfiler 探针系统的全部功能。该 API 使用注解来定义拦截并注入方法参数和其他有用的对象。
下一个问题是:JProfiler 应该如何处理您创建的字符串?有两种不同的策略可用:有效负载创建或调用树拆分。
有效负载创建
探针构建的字符串可用于创建一个 探针事件。事件的描述设置为该字符串,持续时间等于拦截方法的调用时间,并且有一个关联的调用栈。在它们相应的调用栈中,探针描述和时间被累积并作为 有效负载 保存到调用树中。当事件在达到某个最大数量后被合并时,调用树中累积的有效负载显示整个记录期间的总数。如果同时记录 CPU 数据和您的探针,探针调用树视图将显示合并的调用栈,其中有效负载字符串作为叶节点,CPU 调用树视图将包含到探针调用树视图的 注释链接。
就像 CPU 数据一样,有效负载可以在调用树或热点视图中显示。热点显示哪些有效负载对大部分消耗时间负责,回溯显示代码的哪些部分负责创建这些有效负载。为了获得良好的热点列表,有效负载字符串不应包含任何唯一 ID 或时间戳,因为如果每个有效负载字符串都不同,将不会有累积,也没有明确的热点分布。例如,在准备好的 JDBC 语句的情况下,参数不应包含在有效负载字符串中。
脚本探针会自动从配置的脚本的返回值中创建有效负载。注入探针类似,它们从带有 PayloadInterception
注解的拦截处理方法中返回有效负载描述,作为字符串或
Payload
对象以实现高级功能。另一方面,嵌入探针通过调用 Payload.exit
并将有效负载描述作为参数来创建有效负载,其中
Payload.enter
和 Payload.exit
之间的时间被记录为探针事件持续时间。
如果您正在记录在不同调用点发生的服务调用,有效负载创建最有用。一个典型的例子是数据库驱动程序,其中有效负载字符串是某种形式的查询字符串或命令。探针从调用点的角度出发,测量的工作由另一个软件组件执行。
调用树拆分
探针也可以从执行站点的角度出发。在这种情况下,拦截方法如何被调用并不重要,而是拦截方法之后执行了哪些方法调用。一个典型的例子是用于 servlet 容器的探针,其中提取的字符串是 URL。
比创建有效负载更重要的是能够为探针构建的每个不同字符串拆分调用树。对于每个这样的字符串,将在调用树中插入一个拆分节点,其中包含所有相应调用的累积调用树。否则将只有一个累积调用树,现在有一组拆分节点将调用树分割成不同的部分,可以分别进行分析。
多个探针可以产生嵌套拆分。默认情况下,单个探针仅产生一个拆分级别,除非它被配置为 可重入,这不支持脚本探针。
在 JProfiler UI 中,调用树拆分不与脚本探针功能捆绑在一起,而是一个 独立功能,称为“拆分方法”。它们只是拆分调用树而不创建有效负载,因此不需要带有名称和描述的探针视图。注入探针从带有
SplitInterception
注解的拦截处理方法中返回拆分字符串,而嵌入探针调用 Split.enter
并传入拆分字符串。
遥测
自定义探针有两个默认遥测:事件频率和平均事件持续时间。注入和嵌入探针支持通过探针配置类中的注解方法创建的附加遥测。在 JProfiler UI 中,脚本遥测独立于脚本探针功能,并在“遥测”部分中找到,位于工具栏中的 配置遥测 按钮下。
遥测方法每秒轮询一次。在 Telemetry
注解中,您可以配置单位和比例因子。使用 line
属性,可以将多个遥测组合成一个遥测视图。使用
TelemetryFormat
的 stacked
属性,您可以使线条累加并将其显示为堆叠线图。嵌入和注入探针中的与遥测相关的 API 是等效的,但仅适用于各自的探针类型。
控制对象
有时将探针事件与 JProfiler 中称为“控制对象”的关联长生命周期对象绑定在一起是很有趣的。例如,在数据库探针中,该角色由执行查询的物理连接承担。这样的控制对象可以通过嵌入 API 和注入探针 API 打开和关闭,这会在探针事件视图中生成相应的事件。当创建探针事件时,可以指定控制对象,以便探针事件贡献于探针的“控制对象”视图中显示的统计信息。
控制对象具有在打开时必须指定的显示名称。如果在创建探针事件时使用了新的控制对象,探针必须在其配置中提供名称解析器。
此外,探针可以通过枚举类定义自定义事件类型。当创建探针事件时,可以指定这些类型之一,并在事件视图中显示,您可以在其中筛选单个事件类型。更重要的是,显示控制对象作为时间轴上线条的探针时间线视图根据事件类型进行着色。对于没有自定义事件类型的探针,着色显示未记录事件的空闲状态和探针事件持续时间的默认事件状态。通过自定义类型,您可以区分状态,例如“读取”和“写入”。
记录
像所有探针一样,自定义探针默认不记录数据,但您必须根据需要启用和禁用记录。虽然您可以在探针视图中使用手动开始/停止操作,但通常需要在开始时打开探针记录。因为 JProfiler 事先不知道自定义探针,所以记录配置文件有一个 自定义探针 复选框,适用于所有自定义探针。
同样,您可以为开始和停止探针记录的触发器操作选择 所有自定义探针。
对于编程记录,您可以调用
Controller.startProbeRecording(Controller.PROBE_NAME_ALL_CUSTOM, ProbeRecordingOptions.EVENTS)
来记录所有自定义探针,或者传递探针的类名以更具体。