春节快乐,干货来袭。虽然QAPM业务压力巨大,但是我们依旧希望自己是有技术追求的。哪怕你不是APM的用户,也可以使用我们共享出来的小而美的组件和服务。例如TPS提供的登录和告警服务,已经有上百个项目接入;基于k8s的大数据框架也在内部开源。而最近,我们为了大家都能共享到我们自动提单中的处理人自动分析能力,我们从QAPM里面提炼出来的智能缺陷分配服务WhosBug。比起推广,今天我们不妨先来谈谈技术他的技术内核。业务痛点,茫茫人海中无法相遇的缺陷与解决者
如果缺陷没有分配给正确的人,会导致重要缺陷不断流转,很慢才能解决;而在流转的过程中会增加大量的交接成本——我们观察到一个简单的缺陷在流转中会浪费超过5天(见下图)。而且把缺陷分配给错误的人还可能导致被分配人不知道此缺陷的前因后果,修改缺陷时容易犯错,引发新的问题。
而将bug提单给正确的人,以减少缺陷流转时间和节省开发人员交接成本,就是WhosBug致力于解决的问题。下面来看看,我们是如何提炼并升级我们的智能缺陷分配服务。
提炼,仅需做好告诉责任人一件事
从我们打算把它从QAPM提炼出来开始,就想着要严格定义他的责任。我们设定好他应该仅专注在通过堆栈来分析责任人,不与任何系统绑定,通过restful api调用。这样的设计可以让它不仅仅我们自己的NewMonkey可以用,QAPM提单可以用,告警可以用,一切需要通过堆栈找责任人的服务,都可以通过API方便调用。下面是我们的设计,我们主要基于 Git, Antlr4, Django 实现插件以及后台的WebService
升级,从更“理解代码”开发
在QAPM里面的版本,已经运作了许多年了。实话说,当时的方案是我们当年平衡实现难度和时间的最终结果。利用git diff中提供的owner、文件名、变化代码行位置的初略计算,在不用理解代码的基础上,实现与问题堆栈的匹配,进而得出问题的owner。这种方法的问题,逻辑上的缺陷还是很明显的,如全局变量的变化间接的影响就无法分析了。
因此我们就开始从“理解代码”开始,让我们的分析引擎起码要知道什么是全局变量,什么是函数。经过调研,我们决定引入这个强大的工具Antlr4。
Antlr是什么
In a word, 多源语言多目标语言的一个语法分析框架
以下是官方文档的解释:
ANTLR(ANother Tool for Language Recognition)是一个功能强大的解析器生成器,用于读取,处理,执行或翻译结构化文本或二进制文件。它被广泛用于构建语言,工具和框架。ANTLR从语法上生成一个解析器,该解析器可以构建解析树,还可以生成一个侦听器接口(或访问者),从而可以轻松地对所关注短语的识别做出响应。
ANTLR (ANother Tool for Language Recognition) is a powerful parser generator for reading, processing, executing, or translating structured text or binary files. It's widely used to build languages, tools, and frameworks. From a grammar, ANTLR generates a parser that can build parse trees and also generates a listener interface (or visitor) that makes it easy to respond to the recognition of phrases of interest.
Github项目地址
与传统源码分析不同,antlr提供Listener这一API供用户自定义自己的分析器,这种方式可以很大程度上使语法更易于阅读(按每位用户自己的设计),同时使得它们能避免与特定的应用程序耦合在一起,以下是官方的解释(官方文档):
Because we specify phrase structure with a set of rules, parse tree subtree roots correspond to grammar rule names. ANTLR has a ParseTreeWalker that knows how to walk these parse trees and trigger events in listener implementation objects that you can create. The ANTLR tool generates listener interfaces for you also, unless you turn that off with a commandline option. You can also have it generate visitors. For example from a Java.g4 grammar, ANTLR generates:
public interface JavaListener extends ParseTreeListener<Token> { void enterClassDeclaration(JavaParser.ClassDeclarationContext ctx); void exitClassDeclaration(JavaParser.ClassDeclarationContext ctx); void enterMethodDeclaration(JavaParser.MethodDeclarationContext ctx); ... }
where there is an enter and exit method for each rule in the parser grammar. ANTLR also generates a base listener with the fall empty implementations of all listener interface methods, in this case called JavaBaseListener. You can build your listener by subclassing this base and overriding the methods of interest.
Listeners and visitors are great because they keep application-specific code out of grammars, making grammars easier to read and preventing them from getting entangled with a particular application.
其低耦合性也保证了Whosbug可以根据实际需求自由地拓展和更新语法分析模块
基于Antlr4完整分析代码结构,并基于Git精确绑定责任人;下图为对AllInOne7.java(包含java所有语法结构的示例代码)的语法分析测试:
紧接着,我们重新设计了基于“理解代码”的归属算法,设计如下:
如何用起来?
本工具呈现形式为蓝盾 / Coding 流水线插件
- Whosbug 蓝盾插件
- Whosbug Coding插件
插件基于python3开发,下面是蓝盾及Coding的流水线配置流程
蓝盾流水线配置
新建蓝盾流水线(项目release触发),新建Linux环境Job
添加拉取Git插件,拉取项目源码:
添加Bash插件,确保pip指向python3(因为蓝盾流水线python插件是基于setuptools打包的,pip的指向决定了插件的运行命令对应的python版本):
添加Whosbug-智能分派助手插件:
- 其中项目ID和项目发布版本从拉取Git插件的输出中自动获取,无特殊需要不需要改动
- 项目路径和拉取Git中的代码保存路径保持相同(一般都不填,默认为工作空间目录)
- NewMonkey任务名填写新创建的NewMonkey任务名,以绑定任务(若接入NewMonkey服务)
最终流水线全览如下:
Coding流水线配置
与蓝盾流水线类似,但因为Coding流水线集成了拉取Git的步骤(源码会在工作目录中),并且Coding插件可以通过配置entry字段解决python的版本兼容性问题,所以省去了拉取Git步骤和环境配置步骤,whosbug插件配置和蓝盾流水线中基本一致(省去了项目路径选项)
使用效果
目前NewMonkey已接入Whosbug微服务,以满足NewMonkey测试流程中提单的责任人归属需求
下图为一次测试流程中产生的自动提单,调用了Whosbug API获取到了对应的责任人
后续规划
- 优化反馈模块,给用户一个优质方便的反馈入口
- 加速开发对其它主流语言的支持,增强 Whosbug 的泛用性
- 针对反馈内容优化责任人归属算法以及插件功能等
Whosbug 接口文档