如何写一个Skywalking trace插件

javaagent 原理

美团技术团队-Java 动态调试技术原理及实践

类图

实现

ConsumeMessageConcurrentlyInstrumentation

public class ConsumeMessageConcurrentlyInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
// 需要增强的类
private static final String ENHANCE_CLASS = "com.aliyun.openservices.shade.com.alibaba.rocketmq.client.consumer.listener.MessageListenerConcurrently";
// 需要增强的方法
private static final String CONSUMER_MESSAGE_METHOD = "consumeMessage";
// 增加的方法对应的拦截器
private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.ons.v1.MessageConcurrentlyConsumeInterceptor"; // 构造器不需要拦截
@Override
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[0];
} @Override
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return new InstanceMethodsInterceptPoint[] {
// 新增一个拦截器
new InstanceMethodsInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getMethodsMatcher() {
// 方法匹配
return named(CONSUMER_MESSAGE_METHOD);
} @Override
public String getMethodsInterceptor() {
return INTERCEPTOR_CLASS;
} @Override
public boolean isOverrideArgs() {
return false;
}
}
};
} @Override
protected ClassMatch enhanceClass() {
// 需要增强的类
return HierarchyMatch.byHierarchyMatch(new String[] {ENHANCE_CLASS});
}
}

AbstractMessageConsumeInterceptor

public abstract class AbstractMessageConsumeInterceptor implements InstanceMethodsAroundInterceptor {

    public static final String CONSUMER_OPERATION_NAME_PREFIX = "OnsRocketMQ/";

    // 在方法前增强
@Override
public final void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments,
Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
// 拿到方法参数,转换成消息列表
List<MessageExt> msgs = (List<MessageExt>) allArguments[0]; // 从消息中中获取TraceId等Context信息
ContextCarrier contextCarrier = getContextCarrierFromMessage(msgs.get(0)); // 创建一个entry span
AbstractSpan span = ContextManager.createEntrySpan(CONSUMER_OPERATION_NAME_PREFIX + msgs.get(0)
.getTopic() + "/Consumer", contextCarrier);
span.setComponent(ComponentsDefine.ROCKET_MQ_CONSUMER);
SpanLayer.asMQ(span);
for (int i = 1; i < msgs.size(); i++) {
ContextManager.extract(getContextCarrierFromMessage(msgs.get(i)));
} } // 异常处理
@Override
public final void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
Class<?>[] argumentsTypes, Throwable t) {
ContextManager.activeSpan().log(t);
} private ContextCarrier getContextCarrierFromMessage(MessageExt message) {
ContextCarrier contextCarrier = new ContextCarrier(); CarrierItem next = contextCarrier.items();
while (next.hasNext()) {
next = next.next();
next.setHeadValue(message.getUserProperty(next.getHeadKey()));
} return contextCarrier;
}
}

MessageConcurrentlyConsumeInterceptor

public class MessageConcurrentlyConsumeInterceptor extends AbstractMessageConsumeInterceptor {
// 在方法后处理
@Override
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
Object ret) throws Throwable {
// 获取消费状态
ConsumeConcurrentlyStatus status = (ConsumeConcurrentlyStatus) ret;
if (status == ConsumeConcurrentlyStatus.RECONSUME_LATER) {
// 消费状态为重试,则设置span出现错误
AbstractSpan activeSpan = ContextManager.activeSpan();
activeSpan.errorOccurred();
Tags.MQ_STATUS.set(activeSpan, status.name());
}
// 停止span
ContextManager.stopSpan();
return ret;
}
}

项目:apm-ons-1.x-plugin

参考文档

  1. apm-ons-1.x-plugin
  2. 美团技术团队-Java 动态调试技术原理及实践

分享并记录所学所见

Skywalking-02:如何写一个Skywalking trace插件的更多相关文章

  1. 给Ionic写一个cordova(PhoneGap)插件

    给Ionic写一个cordova(PhoneGap)插件 之前由javaWeb转html5开发,由于面临新技术,遂在适应的过程中极为挣扎,不过还好~,这个过程也极为短暂:现如今面临一些较为复杂的需求还 ...

  2. 如何写一个Js上传图片插件。

    项目里面需要一个上传图片的插件,找了半天没有找到满意的,算了 不找了,自己写一个吧,顺便复习一下js方面的知识.完成之后效果还不错,当然还要继续优化,源码在最后. 介绍一种常见的js插件的写法 ; ( ...

  3. 用javascript写一个emoji表情插件

    概述 以我们写的这个emoji插件为例,网上已经有一些相关的插件了,但你总感觉有些部分的需求不能被满足(如:可以自行添加新的表情包而不用去改源代码等等) 详细 代码下载:http://www.demo ...

  4. 写一个Vue loading 插件

    什么是vue插件? 从功能上说,插件是为Vue添加全局功能的一种机制,比如给Vue添加一个全局组件,全局指令等: 从代码结构上说,插件就是一个必须拥有install方法的对象,这个方法的接收的第一个参 ...

  5. 改变滚动条的原始样式: chrome 可以改变, IE只能变相关颜色,firfox好像也不好改。最好是自己写一个或是用插件

    相关作者链接地址: https://www.lyblog.net/detail/314.html 问题: 1.我在项目中遇到的问题: 在设置了::-webkit-scrollbar 后,滚动条不见了! ...

  6. 用原生js来写一个swiper滑块插件

        是不是有点印象了,没错,他的最基本的用法就是左右滑动,插件使用者只需要写几行简单的html和js即可实现一个简单滑动效果,不过你完全可以组合各种元素来适应不同的场景. 当然插件我已经写好了,咱 ...

  7. 玉渊潭赏樱花有感:从无到有写一个jQuery开源插件

    “玉渊潭公园樱花节”是每年樱花绽放时,都会在玉渊潭公园樱举办樱花节,游客前往玉渊潭公园,可以欣赏到20个品种2000株樱花.2016玉渊潭樱花节时间:3月中旬-4月中旬观赏最佳,2016年3月23日开 ...

  8. 纯后端尝试写一个前端slide插件

    概述 由于项目组前端人员缺失,又赶上需要在手机端做一个slide效果的页面,所以只能自己硬着头皮上了,写的很简单,请大家不要笑话,只是拿出来分享下,大家先看下完成后的效果,如下: 过程 看了效果图是不 ...

  9. 怎么给Unity写一个原生的插件

    本文章由cartzhang编写,转载请注明出处. 所有权利保留. 文章链接:http://blog.csdn.net/cartzhang/article/details/50266889 作者:car ...

随机推荐

  1. PTA4题学习总结

    前言: 这是我20多年以来第一次写博客了,还是在学校里那可(牛)爱(逼)的Java老师的安(逼)慰(迫)下,含泪写下第一篇博客,大家应该都明白这种含泪写下的佳(废)作(品)是多么的动人的. 就不开玩笑 ...

  2. mybatis入“坑”第一步

    一.导入坐标 要想通过maven创建一个简单的mybatis项目,首先需要的是要导入相关的坐标.需要导入的坐标如下: <dependencies> <!--mysql驱动坐标--&g ...

  3. HashMap 中7种遍历方式的性能分析

    随着 JDK 1.8 Streams API 的发布,使得 HashMap 拥有了更多的遍历的方式,但应该选择那种遍历方式?反而成了一个问题. 本文先从 HashMap 的遍历方法讲起,然后再从性能. ...

  4. 学习Qt Charts - Qt Charts的坐标轴

    这次来学学Qt chart 的坐标轴 有这么一组数据: 这是深圳市2019年6月份的天气预报(来自中国天气网:深圳),里面有每天的最高温度,把这最高温度做成个数组,如下: int daily_temp ...

  5. Unity StateMachineBehaviour

    在unity animator中单个Animator Clip中点击Add Behaviour增加当执行该动画时的一些状态代码,请看如下 创建完之后基本代码结构如下:(如果想修改默认代码结构,请看示例 ...

  6. C#获取字符串字符的位数(区分中文和英文长度)

    请看以下代码 1 private static int GetStrLength(string str) 2 { 3 if (string.IsNullOrEmpty(str)) return 0; ...

  7. 多个异步ajax请求指定顺序执行

    1.比如2个ajax请求,把第二个ajax请求放在第一个ajax请求success方法里面. 2.ajax请求时添加 async: false,//使用同步的方式,true为异步方式.结果是只有等服务 ...

  8. Pygame 入门基本指南

    最近正在利用 Python 制作一个小游戏,但对于 Pygame 不熟悉,故在学习的过程记录相关知识点 Pygame 中文文档下载:Here Pygame第1-1课:入门 什么是Pygame? Pyg ...

  9. HTTP:Java实现HTTP请求的三种方式

    目前JAVA实现HTTP请求的方法用的最多的有两种: 一种是通过HTTPClient这种第三方的开源框架去实现.HTTPClient对HTTP的封装性比较不错,通过它基本上能够满足我们大部分的需求,H ...

  10. linux学习之路第七天(压缩和解压类指令详解)

    压缩和解压类 1.gzip/gunzip 指令 gzip 指令用于压缩文件, gunzip用于解压的 基本语法 gzip 文件 (功能描述:压缩文件,指令将文件压缩成*.gz文件) gunzip 文件 ...