zoukankan      html  css  js  c++  java
  • zorka源码解读之通过beanshell进行插桩的流程

    zorka中插桩流程概述

    1、在SpyDefinition中配置插桩属性,将SpyDefinition实例提交给插桩引擎。
    2、SpyDefinition实例中包含了插桩探针probes,probe插入到方法中,对方法的执行进行监控。
    方法的插入阶段主要包括三个:开始阶段(entry),返回阶段(return),异常阶段(error)。
    每个probe会根据其指定的阶段对方法插桩,捕获其中的数据,比如当前时间、方法参数、方法内部的变量等。
    probe捕获的数据会封装为SpyRecord实例(SymbolicRecord),为一条记录record。
    3、根据probe中定义的阶段,record将提交给不同的processor链进行处理。
    一个方法的所有探针的记录将组合在一起并提交给submit链进行处理。
    以上过程都属于某个方法调用的线程独有(要保证线程安全)
    4、最后record被提交给collect链(单线程),collector会更新统计信息并将record写到相应的流。
    我们要自定义插桩,主要是通过编写beanshell来定义插桩探针probe、定义插桩记录处理器processor、指定插桩的方法以及位置。

    Demo

    例子1:记录tomcat的request的URL。
    (监控org.apache.catalina.core.StandardEngineValve方法,获取request中的URI,并记录到日志)
    1、直接在catalina.bsh里面加上如下代码,保存。(注:把原有的对org.apache.catalina.core.StandardEngineValve方法的插桩代码注释掉,只能定义一次)

    spy.add(spy.instance("CATALINA_LOG_REQUESTS")
    .onEnter(spy.fetchArg("REQ", 1), spy.zorkaLog("INFO", "HTTPzsy", "${REQ.request.requestURI}"))
    .include(spy.byMethod("org.apache.catalina.core.StandardEngineValve", "invoke")));

    说明
    1)、spy是在zorka启动的时候已经注册到beanshell中的对象,在beanshell中可以直接使用。
    spy的作用是配置插桩引擎。
    2)、add方法往spy中添加一个SpyDefinition的实例。
    spy.instance("CATALINA_LOG_REQUESTS")是实例化一个零配置的SpyDefinition对象,CATALINA_LOG_REQUESTS是指定名字。
    3)、调用onEnter方法往SpyDefinition实例中添加enter阶段的配置信息。
    配置信息包括SpyProbe实例-探针,SpyProcessor实例-记录处理器
    spy.fetchArg("REQ", 1):定义一个探针,用于获取方法的第一个参数,并放入REQ的变量中。
    spy.zorkaLog("INFO", "HTTPzsy", "${REQ.request.requestURI}")定义一个记录处理器,这里定义的是日志收集器。第一个参数是日志级别,第二个是tag,第三个是日志信息(这里是从REQ变量中获取request的URI)
    4)、include方法用于往SpyDefinition实例中添加插桩位置信息。
    插桩时机被封装在SpyMatcher中。这里表示调用org.apache.catalina.core.StandardEngineValve方法的时候进行插桩。
    综上就是,在调用org.apache.catalina.core.StandardEngineValve方法的时候,获取第一个参数,并提取参数中的URI信息写入到zorka日志中。
    2、重启tomcat,或者在jconsole里面如下图位置点击reload重新加载zorka的配置。

    3、访问本地tomcat下的web,比如http://localhost:8080/
    4、打开zorka下的日志,比如D:apache-tomcat-7.0.62-windows-x64apache-tomcat-7.0.62zorkalogzorka.log

    例子2:监控http请求、返回、执行时间等信息,根据配置文件选择是否执行相应的监控跟踪。
    我们来分析下catalina.bsh中自带的HTTP监控。以下如此复杂的监控,主要是加入了根据配置文件zorka.properties的配置项来添加监控和记录追踪。
    1、代码分析

    spy.add(spy.instrument("CATALINA_HTTP")//该方法也是调用SpyDefinition.instance实例化一个SpyDefinition实例,并添加时间监控的probe和计算运行时长的processor。
    .onEnter(//添加方法进入阶段的probe
    spy.fetchArg("REQ", 1), //获取第一个参数放入REQ中,即获取request对象
    spy.fetchArg("RESP", 2),//获取第二个参数放入RESP中,即获取response对象
    spy.format("URI", "${REQ.request.requestURI}"),//获取URI
    http._trace ? spy.subchain(//如果http.trace=yes(默认是打开http跟踪),则添加LogicalFilterProcessor处理器(包含一串子processor,遍历处理record,若处理结果为空则返回原始record)
        http._uriQualifier,//URI匹配处理器,用于根据http.trace.exclude和http.trace.include配置项过滤URL
        tracer.begin("HTTP", zorka.longCfg("http.trace.time")),//添加一个TraceBeginProcessor,用于开始一个新trace(调用traceBuilder.traceBegin)。这里表示开始一个名字为HTTP的trace,最小追踪时间为配置项所指定。
        tracer.attr("URI", "URI")//返回TraceAttrProcessor,用于将属性添加到record。这里用于将源字段中的URI放到URI变量中。
    ) : null,
    http._congestion ? spy.zorkaStats("java", http._mbean, "stats", "ALL", "T", null, spy.ACTION_ENTER) : null//若http.stats.congestion配置为true,则添加方法调用统计处理器
    )
    .onReturn(spy.put("ERR", ""))//方法返回时,给ERR变量放入空值
    .onError(
    spy.fetchError("EX"), //添加异常捕获的probe,方法抛出异常时,则probe捕获该异常对象
    spy.format("ERR", "${EX}"),//将异常格式化并放入ERR变量
    http._trace ? spy.subchain(//http跟踪打开,则添加如下processor
    http._uriQualifier,//URL过滤处理器
    http._error_chain,//若http.error = yes,则添加相应的trapperCollector,即将错误记录发送给记录收集器
    tracer.flags(tracer.SUBMIT_TRACE),
    tracer.attr("ERR", "ERR")
    ) : null
    )
    .onSubmit(//提交阶段
    spy.strTime("TIME"),//获取方法执行时间
    spy.format("STATUS", "${RESP.status}"),//获取请求状态
    spy.get("USER", "REQ", "remoteUser"),//获取远程用户地址
    http._trace ? spy.subchain(
    http._uriQualifier,
    tracer.attr("STATUS", "STATUS"),
    tracer.filterBy("STATUS", null, http._errors, null, null),
    tracer.attr("USER", "USER"),
    http._cookies ? http.cookies_processor(true, true) : spy.put("COOKIES", ""),
    http._headers ? headers_processor() : null,
    http._params ? http.param_processor() : spy.put("PARAMS", "")
    ) : null,
    http._slow_chain,
    spy.subchain(
    spy.valSetFilter("STATUS", http._errors),
    spy.markError(),
    tracer.markError(),
    http._error_chain
    ),
    http._redirQualifier,
    http._stats ? spy.zorkaStats("java", http._mbean, "stats", "ALL", "T", null, http._action) : null,
    http._tags_chain
    )
    .include(spy.byMethod("org.apache.catalina.core.StandardEngineValve", "invoke")));//在调用org.apache.catalina.core.StandardEngineValve方法时执行插桩。

    2、监控结果
    我们用zico查看监控结果,可以看到上面bsh脚本中指定监控的时长、调用次数、错误信息、URL、请求状态等都有记录。

  • 相关阅读:
    js中split字符串分割
    获取日期,实时显示当前时间,时间相减
    5.5.4 函数内部属性
    单选按钮radio和下拉选择select,ajax返回数据回显对应值
    如何在HTML不同的页面中,共用头部与尾部?
    android-Activity(四大组件之一)
    android-ImageView及其子类
    android-ActionBar
    android- 菜单
    android-Fragment
  • 原文地址:https://www.cnblogs.com/peterpanzsy/p/4594944.html
Copyright © 2011-2022 走看看