skywalking python插件修改(flask\requests)

目录结构

  • 官方默认自带的插件所在位置为:skywalking/plugins目录内
  • 官方加载插件时会自动加载该目录内符合条件的全部模,详细加载判断逻辑可以查看plugins/init.py中的install方法

插件代码结构

  • 官方默认提供了很多插件,用于处理常见的第三方库,其实现方式主要是利用猴子补丁在启动时对原有的第三方库中方法/函数对象进行替换,在原本的方法前后包裹需要的定制代码,用于在方法执行前后获取参数和返回值,进行记录/发送等处理。从某种程度上可以看作是装饰器。
  • 插件模块的实现方式主要就是实现install方法,在后续加载时skywalking会自动运行插件模块中的install方法,实现对内容的替换,达到抓取数据的目的

修改抓取数据

  • 相关数据记录到skywalking中的方法为:
    • span.tag(TagHttpParams()) 用于记录该请求的参数,抓取到的数据会展示skywalking界面的http.params字段内
    • span.tag(TagHttpMethod()) 用于记录该请求的请求方法,抓取到的数据会展示skywalking界面的http.method字段内
    • span.tag(TagHttpURL()) 用于记录该请求的URL,抓取到的数据会展示skywalking界面的http.url字段内
    • span.tag(TagHttpStatusCode()) 用于记录该请求的返回状态码,抓取到的数据会展示skywalking界面的http.status_code字段内
    • span.tag(TagHttpStatusMsg()) 用于记录该请求的返回消息,抓取到的数据会展示skywalking界面的http.status_msg字段内

实现flask抓取json请求参数数据

  • 修改sw_flask.py文件
with span:  
  span.layer = Layer.Http  
  span.component = Component.Flask  
  if all(environ_key in req.environ for environ_key in ('REMOTE_ADDR', 'REMOTE_PORT')):  
    span.peer = f"{req.environ['REMOTE_ADDR']}:{req.environ['REMOTE_PORT']}"  
  span.tag(TagHttpMethod(method))  
  span.tag(TagHttpURL(req.url.split('?')[0]))  
  if config.flask_collect_http_params:  
    # 获取form或者args格式的参数数据  
    if req.values:  
      span.tag(TagHttpParams(params_tostring(req.values)[0:config.http_params_length_threshold]))  
    # 获取json格式的请求参数数据  
    elif req.is_json and req.json:  
      span.tag(TagHttpParams(json.dumps(req.json, ensure_ascii=False, indent=2)[0:config.http_params_length_threshold]))  
  
  resp = _full_dispatch_request(this)
  • 额外添加获取json格式数据的逻辑,当请求数据为json时将数据记录到params中,解决无法获取到json数据的问题

实现requests请求抓取请求参数

  • 修改sw_requests.py文件
span.tag(TagHttpMethod(method.upper()))  
span.tag(TagHttpURL(url_param.geturl()))  
  
res = _request(this, method, url, params, data, headers, cookies, files, auth, timeout,allow_redirects,proxies, hooks, stream, verify, cert, json)  
# 获取get方法的请求参数  
if method.upper() == 'GET':  
    params_string = dict_params_tostring(params)[0:config.http_params_length_threshold]  
# 获取其它方法的请求参数(byte类型)  
else:  
    params_string = res.request.body[0:config.http_params_length_threshold]  
span.tag(TagHttpParams(params_string))  
span.tag(TagHttpStatusCode(res.status_code))  
if res.status_code >= 400:  
    span.error_occurred = True
  • 通过添加requests的参数获取逻辑,并将获取到的参数通过TagHttpParams方法保存到参数中,体现在skywalking内

skywalking python打包的坑

  • 由于项目中使用了子模块protocol,并且子模块本身的位置并不在项目实际目录中,无法直接通过pip安装git仓库的方式进行项目的安装,改版的项目也需要打包成whl包,才能用来给环境安装。
  • 首先保证拉取的代码中protocol子模块内容完整,之后在项目根目录运行命令python3 tools/codegen.py 将protocol目录中的内容生成到skywalking目录下。
  • 再使用python3 setup.py bdist_wheel命令,将代码打包成whl包,用于后续环境安装使用。