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-x64\apache-tomcat-7.0.62\zorka\log\zorka.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、请求状态等都有记录。

zorka源码解读之通过beanshell进行插桩的流程的更多相关文章

  1. zorka源码解读之Instrument实现原理

    主要用到三方面技术: beanshell来实现可扩展:告诉zorkaAgent插桩的具体需求,包括插桩的方法和值.插桩的时机.插桩追踪记录方式等. Instrument来通过代理的方式访问JVM,实现 ...

  2. zorka源码解读之tracer内部实现

    核心类: ZorkaAsyncThread.java protected BlockingQueue<T> submitQueue; /** * Processes single item ...

  3. zorka源码解读之Beanshell与zorka的交互实现

    一.beanshell基础知识从应用程序中调用BeanShell创建一个BeanShell的解释器(interpreter)用eval()和source()命令可以对一个字符串求值和运行一个脚本文件使 ...

  4. SDWebImage源码解读之SDWebImageDownloaderOperation

    第七篇 前言 本篇文章主要讲解下载操作的相关知识,SDWebImageDownloaderOperation的主要任务是把一张图片从服务器下载到内存中.下载数据并不难,如何对下载这一系列的任务进行设计 ...

  5. SDWebImage源码解读 之 NSData+ImageContentType

    第一篇 前言 从今天开始,我将开启一段源码解读的旅途了.在这里先暂时不透露具体解读的源码到底是哪些?因为也可能随着解读的进行会更改计划.但能够肯定的是,这一系列之中肯定会有Swift版本的代码. 说说 ...

  6. SDWebImage源码解读 之 UIImage+GIF

    第二篇 前言 本篇是和GIF相关的一个UIImage的分类.主要提供了三个方法: + (UIImage *)sd_animatedGIFNamed:(NSString *)name ----- 根据名 ...

  7. SDWebImage源码解读 之 SDWebImageCompat

    第三篇 前言 本篇主要解读SDWebImage的配置文件.正如compat的定义,该配置文件主要是兼容Apple的其他设备.也许我们真实的开发平台只有一个,但考虑各个平台的兼容性,对于框架有着很重要的 ...

  8. SDWebImage源码解读_之SDWebImageDecoder

    第四篇 前言 首先,我们要弄明白一个问题? 为什么要对UIImage进行解码呢?难道不能直接使用吗? 其实不解码也是可以使用的,假如说我们通过imageNamed:来加载image,系统默认会在主线程 ...

  9. SDWebImage源码解读之SDWebImageCache(上)

    第五篇 前言 本篇主要讲解图片缓存类的知识,虽然只涉及了图片方面的缓存的设计,但思想同样适用于别的方面的设计.在架构上来说,缓存算是存储设计的一部分.我们把各种不同的存储内容按照功能进行切割后,图片缓 ...

随机推荐

  1. Logstash-5.0同步.json文件到ElasticSearch-5.0配置文件

    logstash/conf/input-file.conf内容如下: input { file { #监听文件的路径. path => ["E:/data_json/*.json&qu ...

  2. Python之路【第二十一篇】Django ORM详解

    ORM回顾 关系对象映射(Object Relational Mapping,简称ORM). django中遵循 Code Frist 的原则,即:根据代码中定义的类来自动生成数据库表. 对于ORM框 ...

  3. oracle中时间处理

    --查看当前日期.时间SQL> select sysdate from dual; SQL> select to_char(sysdate,'yyyy-mm-dd hh24:mi:ss') ...

  4. jvm

    -Xms128m表示JVM Heap(堆内存)最小尺寸128MB,初始分配-Xmx512m表示JVM Heap(堆内存)最大允许的尺寸256MB,按需分配. 说明:如果-Xmx不指定或者指定偏小,应用 ...

  5. javascript数据结构与算法--散列

    一:javascript数据结构与算法--散列  一:什么是哈希表? 哈希表也叫散列表,是根据关键码值(key,value)而直接进行访问的数据结构,它是通过键码值映射到表中一个位置来访问记录的,散列 ...

  6. Windows7 + Ubuntu双系统安装过程记录

    本文为在已安装Windows7系统的前提下安装Ubuntu Kylin 14.10系统的过程以及期间出现的各种问题的记录. Ubuntu系统下载 Ubuntu Kylin中文官方网站:http://w ...

  7. Eclipse安装Freemarker插件

    方法一:手动安装 手动安装没有成功 步骤: 1. 下载freemarker-ide : http://sourceforge.net/projects/freemarker-ide/files/ 2. ...

  8. BZOJ 1131: [POI2008]Sta

    Description 一棵树,问以那个节点为根时根的总和最大. Sol DFS+树形DP. 第一遍统计一下 size 和 d. 第二遍转移根,统计答案就行了. Code /************* ...

  9. 利用Mongoose来结构化模式与验证

    Mongoose是一个文档对象模型(ODM)库,为MongoDB Node.js原生驱动程序提供更多的功能. 把结构化的模式应用到一个MongoDB集合,提供了验证和类型转换的好处 Mongoose通 ...

  10. Python自动化之django URL

    URL url(r'^detail-(?P<nid>\d+)-(?P<uid>\d+).html', views.detail) 会把(?P\d+)和(?P\d+)传到后台 需 ...