Skip to content

Commit

Permalink
Add support for apache shenyu (open-telemetry#5629)
Browse files Browse the repository at this point in the history
  • Loading branch information
HessTina-YuI committed Mar 21, 2022
1 parent 32fc378 commit 1d2ede1
Show file tree
Hide file tree
Showing 10 changed files with 330 additions and 0 deletions.
20 changes: 20 additions & 0 deletions instrumentation/shenyu/javaagent/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
plugins {
id("otel.javaagent-instrumentation")
}

muzzle {
pass {
group.set("org.apache.shenyu")
module.set("shenyu")
versions.set("[2.4.3,)")
assertInverse.set(true)
}
}

dependencies {
compileOnly("org.springframework:spring-webflux:5.0.0.RELEASE")
}

tasks.withType<Test>().configureEach {
jvmArgs("-Dotel.instrumentation.shenyu.experimental-span-attributes=true")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.shenyu;

import static io.opentelemetry.javaagent.instrumentation.shenyu.ShenYuPluginUtils.end;
import static io.opentelemetry.javaagent.instrumentation.shenyu.ShenYuPluginUtils.registerSpan;
import static io.opentelemetry.javaagent.instrumentation.shenyu.ShenYuSingletons.httpRouteGetter;
import static io.opentelemetry.javaagent.instrumentation.shenyu.ShenYuSingletons.instrumenter;

import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpRouteHolder;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpRouteSource;
import net.bytebuddy.asm.Advice;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

public class ShenYuCommonPluginAdvice {

@Advice.OnMethodEnter(suppress = Throwable.class)
public static void onEnter(@Advice.Argument(0) ServerWebExchange exchange,
@Advice.This Object self,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
Context parentContext = Context.current();

HttpRouteHolder.updateHttpRoute(
parentContext, HttpRouteSource.CONTROLLER, httpRouteGetter(), exchange);

if (!instrumenter().shouldStart(parentContext, self)) {
return;
}

context = instrumenter().start(parentContext, self);
scope = context.makeCurrent();

registerSpan(exchange, context, self);
}

@Advice.OnMethodExit(suppress = Throwable.class, onThrowable = Throwable.class)
public static void onExit(@Advice.Argument(0) ServerWebExchange exchange,
@Advice.Return(readOnly = false) Mono<Void> mono,
@Advice.Thrown Throwable exception,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {

if (scope != null) {
scope.close();
}

if (mono != null) {
mono = end(mono, exchange);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.shenyu;

import static net.bytebuddy.matcher.ElementMatchers.hasSuperClass;
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
import static net.bytebuddy.matcher.ElementMatchers.named;

import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;

public class ShenYuDoDubboInvokerInstrumentation implements TypeInstrumentation {

@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return hasSuperClass(named("org.apache.shenyu.plugin.dubbo.common.AbstractDubboPlugin"));
}

@Override
public void transform(TypeTransformer transformer) {
transformer.applyAdviceToMethod(
isMethod().and(named("doDubboInvoker")),
ShenYuCommonPluginAdvice.class.getName());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.shenyu;

import static net.bytebuddy.matcher.ElementMatchers.hasSuperClass;
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
import static net.bytebuddy.matcher.ElementMatchers.named;

import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;

public class ShenYuDoExecuteInstrumentation implements TypeInstrumentation {

@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return hasSuperClass(named("org.apache.shenyu.plugin.base.AbstractShenyuPlugin"));
}

@Override
public void transform(TypeTransformer transformer) {
transformer.applyAdviceToMethod(
isMethod().and(named("doExecute")),
ShenYuCommonPluginAdvice.class.getName());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.shenyu;

import static net.bytebuddy.matcher.ElementMatchers.isMethod;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.namedOneOf;

import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;

public class ShenYuExecuteInstrumentation implements TypeInstrumentation {

@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return namedOneOf("org.apache.shenyu.plugin.global.GlobalPlugin",
"org.apache.shenyu.plugin.response.ResponsePlugin");
}

@Override
public void transform(TypeTransformer transformer) {
transformer.applyAdviceToMethod(
isMethod().and(named("execute")),
ShenYuCommonPluginAdvice.class.getName());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.shenyu;

import static java.util.Arrays.asList;

import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import java.util.List;

@AutoService(InstrumentationModule.class)
public class ShenYuInstrumentationModule extends InstrumentationModule {

public ShenYuInstrumentationModule() {
super("shenyu");
}

@Override
public List<TypeInstrumentation> typeInstrumentations() {
return asList(new ShenYuExecuteInstrumentation(), new ShenYuDoExecuteInstrumentation());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.shenyu;

import static io.opentelemetry.javaagent.instrumentation.shenyu.ShenYuSingletons.instrumenter;

import io.opentelemetry.context.Context;
import java.util.Deque;
import java.util.LinkedList;
import javax.annotation.Nullable;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

public class ShenYuPluginUtils {

public static final String ON_SPAN_END = ShenYuPluginUtils.class.getName() + ".Context";

public static void registerSpan(ServerWebExchange exchange, Context context, Object plugin) {
ShenYuPlugin shenYuPlugin = (ShenYuPlugin) exchange.getAttributes()
.getOrDefault(ON_SPAN_END, new ShenYuPlugin());

shenYuPlugin.getOnSpanEndDeque().addLast(t -> instrumenter().end(context, plugin, null, t));

exchange.getAttributes()
.put(ON_SPAN_END, shenYuPlugin);
}

public static <T> Mono<T> end(Mono<T> mono, ServerWebExchange exchange) {
return mono.doOnError(throwable -> end(exchange, throwable))
.doOnSuccess(t -> end(exchange, null))
.doOnCancel(() -> end(exchange, null));
}

private static void end(ServerWebExchange exchange, @Nullable Throwable throwable) {
ShenYuPlugin shenYuPlugin = (ShenYuPlugin) exchange.getAttributes().get(ON_SPAN_END);
Deque<OnSpanEnd> onSpanEndDeque = shenYuPlugin.getOnSpanEndDeque();

OnSpanEnd onSpanEnd = onSpanEndDeque.pollLast();
if (onSpanEnd != null) {
onSpanEnd.end(throwable);
}

}

@FunctionalInterface
interface OnSpanEnd {
void end(Throwable throwable);
}

/**
* Many Plugins in ShenYu, so record these in Deque
*/
protected static class ShenYuPlugin {
private final Deque<OnSpanEnd> onSpanEndDeque;

public ShenYuPlugin() {
onSpanEndDeque = new LinkedList<>();
}

public Deque<OnSpanEnd> getOnSpanEndDeque() {
return onSpanEndDeque;
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.shenyu;

import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpRouteGetter;
import org.springframework.web.reactive.HandlerMapping;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.pattern.PathPattern;

public class ShenYuSingletons {

private static final String INSTRUMENTATION_NAME = "org.apache.shenyu";

private static final Instrumenter<Object, Void> INSTRUMENTER;

static {
InstrumenterBuilder<Object, Void> builder =
Instrumenter.builder(
GlobalOpenTelemetry.get(), INSTRUMENTATION_NAME, new ShenYuSpanNameExtractor());

INSTRUMENTER = builder.newInstrumenter();
}

public static Instrumenter<Object, Void> instrumenter() {
return INSTRUMENTER;
}

public static HttpRouteGetter<ServerWebExchange> httpRouteGetter() {
return (context, exchange) -> {
PathPattern bestPattern =
exchange.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
return bestPattern == null ? null : bestPattern.getPatternString();
};
}

private ShenYuSingletons() {}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.shenyu;

import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor;

public class ShenYuSpanNameExtractor implements SpanNameExtractor<Object> {

@Override
public String extract(Object plugin) {
return plugin.getClass().getSimpleName();
}

}
1 change: 1 addition & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,7 @@ include(":instrumentation:servlet:servlet-javax-common:javaagent")
include(":instrumentation:servlet:servlet-2.2:javaagent")
include(":instrumentation:servlet:servlet-3.0:javaagent")
include(":instrumentation:servlet:servlet-5.0:javaagent")
include(":instrumentation:shenyu:javaagent")
include(":instrumentation:spark-2.3:javaagent")
include(":instrumentation:spring:spring-batch-3.0:javaagent")
include(":instrumentation:spring:spring-core-2.0:javaagent")
Expand Down

0 comments on commit 1d2ede1

Please sign in to comment.