Skywalking

来自ling
跳转至: 导航搜索

k8s环境下Skywalking容器化部署

https://www.jianshu.com/p/4f4c182bcbd8 Docker常用服务#skywalking

https://github.com/apache/skywalking-kubernetes

https://blog.csdn.net/dpnice/article/details/95499394

http://skywalking.apache.org/

https://www.elastic.co/guide/en/elasticsearch/reference/current/windows.html

https://codeload.github.com/mobz/elasticsearch-head/zip/master

http://127.0.0.1:8080/


https://skywalking.apache.org/downloads/

常用代码

-javaagent:C:/server/apache-skywalking-apm-bin/agent/skywalking-agent.jar -Dskywalking.agent.service_name=CodeGen -Dskywalking.collector.backend_service=127.0.0.1:11800,192.168.78.129:11801
java -javaagent:C:\server\apache-skywalking-apm-bin\agent\skywalking-agent.jar -Dskywalking.agent.service_name=gateway -Dskywalking.collector.backend_service=127.0.0.1:11800 -jar C:\workspace\source\ling-cloud\ling-cloud-nacos\target\ling-cloud-nacos.jar --MYSQL-HOST=127.0.0.1 --MYSQL-PORT=3306 --MYSQL-DB:base_nacos --MYSQL-PWD:Dtt!23456789
 java -javaagent:C:\server\apache-skywalking-apm-bin\agent\skywalking-agent.jar -Dskywalking.agent.service_name=gateway -Dskywalking.collector.backend_service=127.0.0.1:11800 -jar C:\workspace\source\ling-cloud\ling-cloud-admin\ling-cloud-admin-biz\target\ling-cloud-admin-biz.jar   --NACOS-HOST=127.0.0.1 --NACOS-PORT=8848 --server.ip=127.0.0.1

代码阅读

String str = new ByteBuddy() // 创建ByteBuddy对象
        .subclass(Object.class) // subclass增强方式
        .name("com.xxx.Type") // 新类型的类名
        // 拦截其中的toString()方法
        .method(ElementMatchers.named("toString")) 
        // 让toString()方法返回固定值
        .intercept(FixedValue.value("Hello World!")) 
        .make()
        // 加载新类型,默认WRAPPER策略
        .load(ByteBuddy.class.getClassLoader()) 
        .getLoaded()
        .newInstance() // 通过 Java反射创建 com.xxx.Type实例
        .toString(); // 调用 toString()方法
System.out.println(str);

class Foo { // Foo 中定义了三个方法
  public String bar() { return null; }
  public String foo() { return null; }
  public String foo(Object o) { return null; }
}

Foo dynamicFoo = new ByteBuddy()
  .subclass(Foo.class) 
  .method(isDeclaredBy(Foo.class)) // 匹配 Foo中所有的方法
  .intercept(FixedValue.value("One!")) 
  .method(named("foo")) // 匹配名为 foo的方法
  .intercept(FixedValue.value("Two!"))
  .method(named("foo").and(takesArguments(1))) // 匹配名为foo且只有一个
                                               // 参数的方法
  .intercept(FixedValue.value("Three!"))
  .make()
  .load(getClass().getClassLoader(), INJECTION)
  .getLoaded()
  .newInstance();
System.out.println(dynamicFoo.bar());
System.out.println(dynamicFoo.foo());
System.out.println(dynamicFoo.foo(null));

class DB {
    public String hello(String name) {
        System.out.println("DB:" + name);
        return null;
    }
}

String helloWorld = new ByteBuddy()
         .subclass(DB.class)
         .method(named("hello"))
         // 拦截DB.hello()方法,并委托给 Interceptor中的静态方法处理
         .intercept(MethodDelegation.to(Interceptor.class))
         .make()
         .load(ClassLoader.getSystemClassLoader(), INJECTION)
         .getLoaded()
         .newInstance()
         .hello("World");
System.out.println(helloWorld);

class Interceptor {
    public static String intercept(String name) { return "String"; }
    public static String intercept(int i) { return "int"; }
    public static String intercept(Object o) { return "Object";}
}


class Interceptor {
    @RuntimeType
    public Object intercept(
      @This Object obj, // 目标对象
      @AllArguments Object[] allArguments, // 注入目标方法的全部参数
      @SuperCall Callable<?> zuper, // 调用目标方法,必不可少哦
      @Origin Method method, // 目标方法
      @Super DB db // 目标对象
    ) throws Exception {
        System.out.println(obj); 
        System.out.println(db);
        // 从上面两行输出可以看出,obj和db是一个对象
        try {
          return zuper.call(); // 调用目标方法
        } finally {
        }
}
// 输出:
// com.xxx.DB$ByteBuddy$8AV3B7GI@2d127a61
// com.xxx.DB$ByteBuddy$8AV3B7GI@2d127a61
// DB:World
// null

@RuntimeType 注解:告诉 Byte Buddy 不要进行严格的参数类型检测,在参数匹配失败时,尝试使用类型转换方式(runtime type casting)进行类型转换,匹配相应方法。

@This 注解:**注入被拦截的目标对象(即前面示例的 DB 对象)。

@AllArguments 注解:注入目标方法的全部参数,是不是感觉与 Java 反射的那套 API 有点类似了?

@Origin 注解:注入目标方法对应的 Method 对象。如果拦截的是字段的话,该注解应该标注到 Field 类型参数。

@Super 注解:注入目标对象。通过该对象可以调用目标对象的所有方法。

@SuperCall:这个注解比较特殊,我们要在 intercept() 方法中调用目标方法的话,需要通过这种方式注入,与 Spring AOP 中的 ProceedingJoinPoint.proceed() 方法有点类似,需要注意的是,这里不能修改调用参数,从上面的示例的调用也能看出来,参数不用单独传递,都包含在其中了。另外,@SuperCall 注解还可以修饰 Runnable 类型的参数,只不过目标方法的返回值就拿不到了。

前面示例中,使用 @SuperCall 注解注入的 Callable 参数来调用目标方法时,是无法动态修改参数的,如果想要动态修改参数,则需要用到 @Morph 注解以及一些绑定操作,示例如下:

复制代码
String hello = new ByteBuddy()
    .subclass(DB.class)
    .method(named("hello"))
    .intercept(MethodDelegation.withDefaultConfiguration()
        .withBinders( 
            // 要用@Morph注解之前,需要通过 Morph.Binder 告诉 Byte Buddy 
            // 要注入的参数是什么类型
            Morph.Binder.install(OverrideCallable.class)
        )
        .to(new Interceptor()))
    .make()
    .load(Main.class.getClassLoader(), INJECTION)
    .getLoaded()
    .newInstance()
    .hello("World");
这里的 Interceptor 会使用 @Morph 注解注入一个 OverrideCallable 对象作为参数,然后通过该 OverrideCallable 对象调用目标方法,如下所示:

复制代码
class Interceptor {
    @RuntimeType
    public Object intercept(@This Object obj,
          @AllArguments Object[] allArguments,// 注入目标方法的全部参数
          @Origin Method method,
          @Super DB db,
          @Morph OverrideCallable callable // 通过@Morph注解注入
    ) throws Throwable {
        try {
            System.out.println("before");
            // 通过 OverrideCallable.call()方法调用目标方法,此时需要传递参数
            Object result = callable.call(allArguments);
            System.out.println("after");
            return result;
        } catch (Throwable t) {
            throw t;
        } finally {
            System.out.println("finally");
        }
    }
}
最后,这里使用的 OverrideCallable 是一个自定义的接口,如下所示:

复制代码
public interface OverrideCallable {
    Object call(Object[] args);
}
除了拦截 static 方法和实例方法,Byte Buddy 还可以拦截构造方法,这里依然通过一个示例进行说明。首先修改 DB 这个类,为它添加一个构造方法,如下所示:

复制代码
class DB { // 只有一个有参数的构造方法
    public DB(String name) { System.out.println("DB:" + name); }
}
使用的 Interceptor 与前文使用的类似:

复制代码
class Interceptor { 
    @RuntimeType
    public void intercept(@This Object obj, 
                          @AllArguments Object[] allArguments) {
        System.out.println("after constructor!");
    }
}


defineMethod() 方法:新增方法。 defineField() 方法:新增字段。 Implement() 方法:实现一个接口。 示例如下:

interface DemoInterface{
    String get();
    void set(String name);
}
Class<? extends Foo> loaded = new ByteBuddy()
  .subclass(Foo.class)
  .defineMethod("moon", // 定义方法的名称
          String.class,  // 方法的返回值
          Modifier.PUBLIC) // public修饰
  .withParameter(String.class, "s") // 新增方法的参数参数
  .intercept(FixedValue.value("Zero!")) // 方法的具体实现,返回固定值
  // 新增一个字段,该字段名称成为"name",类型是 String,且public修饰
  .defineField("name", String.class, Modifier.PUBLIC)
  .implement(DemoInterface.class) // 实现DemoInterface接口
  // 实现 DemoInterface接口的方式是读写name字段
  .intercept(FieldAccessor.ofField("name")) 
  .make().load(Main.class.getClassLoader(),
   ClassLoadingStrategy.Default.INJECTION)
  .getLoaded(); // 获取加载后的Class
Foo dynamicFoo = loaded.newInstance(); // 反射
// 要调用新定义的doo()方法,只能通过反射方式
Method m = loaded.getDeclaredMethod("moon", String.class);
System.out.println(m.invoke(dynamicFoo, new Object[]{""}));
Field field = loaded.getField("name"); // 通过反射方式读写新增的name字段
field.set(dynamicFoo, "Zero-Name"); 
System.out.println(field.get(dynamicFoo));
// 通过反射调用 DemoInterface接口中定义的get()和set()方法,读取name字段的值
Method setNameMethod = loaded.getDeclaredMethod("set", String.class);
setNameMethod.invoke(dynamicFoo, new Object[]{"Zero-Name2"});
Method getNameMethod = loaded.getDeclaredMethod("get");
System.out.println(getNameMethod.invoke(dynamicFoo, new Object[]{}))
----------
输出如下:
Zero!
Zero-Name
Zero-Name