Restlet 2.0 instrumentation (#4535)
* add restlet 2.0 instrumentation * add restlet 2.0 instrumentation * revies: testLibrary, create RestletInstrumenterFactory
This commit is contained in:
parent
21d6648c95
commit
8b7c097912
|
@ -0,0 +1,42 @@
|
||||||
|
plugins {
|
||||||
|
id("otel.javaagent-instrumentation")
|
||||||
|
}
|
||||||
|
|
||||||
|
muzzle {
|
||||||
|
pass {
|
||||||
|
group.set("org.restlet")
|
||||||
|
module.set("org.restlet.jse")
|
||||||
|
versions.set("[2.0.0,)")
|
||||||
|
assertInverse.set(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
maven("https://maven.restlet.talend.com/")
|
||||||
|
mavenLocal()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
api(project(":instrumentation:restlet:restlet-2.0:library"))
|
||||||
|
|
||||||
|
library("org.restlet.jse:org.restlet:2.0.2")
|
||||||
|
|
||||||
|
implementation(project(":instrumentation:restlet:restlet-2.0:library"))
|
||||||
|
|
||||||
|
testImplementation(project(":instrumentation:restlet:restlet-2.0:testing"))
|
||||||
|
testLibrary("org.restlet.jse:org.restlet.ext.jetty:2.0.2")
|
||||||
|
}
|
||||||
|
|
||||||
|
// restlet registers the first engine that is present on classpath, so we need to enforce the appropriate version
|
||||||
|
if (findProperty("testLatestDeps") as Boolean) {
|
||||||
|
configurations.configureEach {
|
||||||
|
resolutionStrategy {
|
||||||
|
eachDependency {
|
||||||
|
if (requested.group == "org.restlet.jse") {
|
||||||
|
useVersion("2.+")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.javaagent.instrumentation.restlet.v2_0;
|
||||||
|
|
||||||
|
import com.google.auto.service.AutoService;
|
||||||
|
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
||||||
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@AutoService(InstrumentationModule.class)
|
||||||
|
public class RestletInstrumentationModule extends InstrumentationModule {
|
||||||
|
|
||||||
|
public RestletInstrumentationModule() {
|
||||||
|
super("restlet", "restlet-2.0");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<TypeInstrumentation> typeInstrumentations() {
|
||||||
|
return Arrays.asList(new ServerInstrumentation(), new RouteInstrumentation());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.javaagent.instrumentation.restlet.v2_0;
|
||||||
|
|
||||||
|
import io.opentelemetry.api.GlobalOpenTelemetry;
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||||
|
import io.opentelemetry.instrumentation.restlet.v2_0.internal.RestletInstrumenterFactory;
|
||||||
|
import org.restlet.Request;
|
||||||
|
import org.restlet.Response;
|
||||||
|
|
||||||
|
public final class RestletSingletons {
|
||||||
|
|
||||||
|
private static final Instrumenter<Request, Response> INSTRUMENTER =
|
||||||
|
RestletInstrumenterFactory.newServerInstrumenter(GlobalOpenTelemetry.get());
|
||||||
|
|
||||||
|
public static Instrumenter<Request, Response> instrumenter() {
|
||||||
|
return INSTRUMENTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
private RestletSingletons() {}
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.javaagent.instrumentation.restlet.v2_0;
|
||||||
|
|
||||||
|
import static io.opentelemetry.instrumentation.api.servlet.ServerSpanNaming.Source.CONTROLLER;
|
||||||
|
import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext;
|
||||||
|
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
|
||||||
|
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||||
|
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
||||||
|
|
||||||
|
import io.opentelemetry.instrumentation.api.servlet.ServerSpanNaming;
|
||||||
|
import io.opentelemetry.instrumentation.restlet.v2_0.internal.RestletServerSpanNaming;
|
||||||
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||||
|
import net.bytebuddy.asm.Advice;
|
||||||
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
|
import net.bytebuddy.matcher.ElementMatcher;
|
||||||
|
import org.restlet.Request;
|
||||||
|
import org.restlet.routing.TemplateRoute;
|
||||||
|
|
||||||
|
public class RouteInstrumentation implements TypeInstrumentation {
|
||||||
|
@Override
|
||||||
|
public ElementMatcher<TypeDescription> typeMatcher() {
|
||||||
|
return named("org.restlet.routing.TemplateRoute").or(named("org.restlet.routing.Route"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void transform(TypeTransformer transformer) {
|
||||||
|
transformer.applyAdviceToMethod(
|
||||||
|
isMethod()
|
||||||
|
.and(named("beforeHandle"))
|
||||||
|
.and(takesArgument(0, named("org.restlet.Request")))
|
||||||
|
.and(takesArgument(1, named("org.restlet.Response"))),
|
||||||
|
this.getClass().getName() + "$RouteBeforeHandleAdvice");
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public static class RouteBeforeHandleAdvice {
|
||||||
|
|
||||||
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
|
public static void getRouteInfo(
|
||||||
|
@Advice.This TemplateRoute route, @Advice.Argument(0) Request request) {
|
||||||
|
String pattern = route.getTemplate().getPattern();
|
||||||
|
|
||||||
|
ServerSpanNaming.updateServerSpanName(
|
||||||
|
currentContext(), CONTROLLER, RestletServerSpanNaming.SERVER_SPAN_NAME, pattern);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,94 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.javaagent.instrumentation.restlet.v2_0;
|
||||||
|
|
||||||
|
import static io.opentelemetry.instrumentation.api.servlet.ServerSpanNaming.Source.CONTROLLER;
|
||||||
|
import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext;
|
||||||
|
import static io.opentelemetry.javaagent.instrumentation.restlet.v2_0.RestletSingletons.instrumenter;
|
||||||
|
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
|
||||||
|
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||||
|
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
||||||
|
|
||||||
|
import io.opentelemetry.context.Context;
|
||||||
|
import io.opentelemetry.context.Scope;
|
||||||
|
import io.opentelemetry.instrumentation.api.servlet.ServerSpanNaming;
|
||||||
|
import io.opentelemetry.instrumentation.restlet.v2_0.internal.RestletServerSpanNaming;
|
||||||
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||||
|
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||||
|
import net.bytebuddy.asm.Advice;
|
||||||
|
import net.bytebuddy.description.type.TypeDescription;
|
||||||
|
import net.bytebuddy.matcher.ElementMatcher;
|
||||||
|
import org.restlet.Request;
|
||||||
|
import org.restlet.Response;
|
||||||
|
import org.restlet.data.Status;
|
||||||
|
|
||||||
|
public class ServerInstrumentation implements TypeInstrumentation {
|
||||||
|
@Override
|
||||||
|
public ElementMatcher<TypeDescription> typeMatcher() {
|
||||||
|
return named("org.restlet.Server");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void transform(TypeTransformer transformer) {
|
||||||
|
transformer.applyAdviceToMethod(
|
||||||
|
isMethod()
|
||||||
|
.and(named("handle"))
|
||||||
|
.and(takesArgument(0, named("org.restlet.Request")))
|
||||||
|
.and(takesArgument(1, named("org.restlet.Response"))),
|
||||||
|
this.getClass().getName() + "$ServerHandleAdvice");
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public static class ServerHandleAdvice {
|
||||||
|
|
||||||
|
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||||
|
public static void beginRequest(
|
||||||
|
@Advice.Argument(0) Request request,
|
||||||
|
@Advice.Argument(1) Response response,
|
||||||
|
@Advice.Local("otelContext") Context context,
|
||||||
|
@Advice.Local("otelScope") Scope scope) {
|
||||||
|
|
||||||
|
Context parentContext = currentContext();
|
||||||
|
|
||||||
|
if (!instrumenter().shouldStart(parentContext, request)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
context = instrumenter().start(parentContext, request);
|
||||||
|
scope = context.makeCurrent();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||||
|
public static void finishRequest(
|
||||||
|
@Advice.Argument(0) Request request,
|
||||||
|
@Advice.Argument(1) Response response,
|
||||||
|
@Advice.Thrown Throwable exception,
|
||||||
|
@Advice.Local("otelContext") Context context,
|
||||||
|
@Advice.Local("otelScope") Scope scope) {
|
||||||
|
|
||||||
|
if (scope == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
scope.close();
|
||||||
|
|
||||||
|
if (Status.CLIENT_ERROR_NOT_FOUND.equals(response.getStatus())) {
|
||||||
|
ServerSpanNaming.updateServerSpanName(
|
||||||
|
context, CONTROLLER, RestletServerSpanNaming.SERVER_SPAN_NAME, "/*");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exception != null) {
|
||||||
|
instrumenter().end(context, request, response, exception);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restlet suppresses exceptions and sets the throwable in status
|
||||||
|
Throwable statusThrowable = response.getStatus().getThrowable();
|
||||||
|
|
||||||
|
instrumenter().end(context, request, response, statusThrowable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.javaagent.instrumentation.restlet.v2_0
|
||||||
|
|
||||||
|
import io.opentelemetry.instrumentation.restlet.v2_0.AbstractRestletServerTest
|
||||||
|
import io.opentelemetry.instrumentation.test.AgentTestTrait
|
||||||
|
|
||||||
|
class RestletServerTest extends AbstractRestletServerTest implements AgentTestTrait {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
plugins {
|
||||||
|
id("otel.library-instrumentation")
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
maven("https://maven.restlet.talend.com/")
|
||||||
|
mavenLocal()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
|
||||||
|
library("org.restlet.jse:org.restlet:2.0.2")
|
||||||
|
|
||||||
|
testImplementation(project(":instrumentation:restlet:restlet-2.0:testing"))
|
||||||
|
testLibrary("org.restlet.jse:org.restlet.ext.jetty:2.0.2")
|
||||||
|
}
|
||||||
|
// restlet registers the first engine that is present on classpath, so we need to enforce the appropriate version
|
||||||
|
if (findProperty("testLatestDeps") as Boolean) {
|
||||||
|
configurations.configureEach {
|
||||||
|
resolutionStrategy {
|
||||||
|
eachDependency {
|
||||||
|
if (requested.group == "org.restlet.jse") {
|
||||||
|
useVersion("2.+")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.restlet.v2_0;
|
||||||
|
|
||||||
|
import io.opentelemetry.api.OpenTelemetry;
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||||
|
import org.restlet.Request;
|
||||||
|
import org.restlet.Response;
|
||||||
|
import org.restlet.routing.Filter;
|
||||||
|
|
||||||
|
/** Entrypoint for tracing Restlet servers. */
|
||||||
|
public final class RestletTracing {
|
||||||
|
|
||||||
|
/** Returns a new {@link RestletTracing} configured with the given {@link OpenTelemetry}. */
|
||||||
|
public static RestletTracing create(OpenTelemetry openTelemetry) {
|
||||||
|
return builder(openTelemetry).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new {@link RestletTracingBuilder} configured with the given {@link OpenTelemetry}.
|
||||||
|
*/
|
||||||
|
public static RestletTracingBuilder builder(OpenTelemetry openTelemetry) {
|
||||||
|
return new RestletTracingBuilder(openTelemetry);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Instrumenter<Request, Response> serverInstrumenter;
|
||||||
|
|
||||||
|
RestletTracing(Instrumenter<Request, Response> serverInstrumenter) {
|
||||||
|
this.serverInstrumenter = serverInstrumenter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new {@link Filter} which can be used to wrap {@link org.restlet.Restlet}
|
||||||
|
* implementations.
|
||||||
|
*/
|
||||||
|
public Filter newFilter(String path) {
|
||||||
|
return new TracingFilter(serverInstrumenter, path);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.restlet.v2_0;
|
||||||
|
|
||||||
|
import io.opentelemetry.api.OpenTelemetry;
|
||||||
|
import io.opentelemetry.instrumentation.api.config.Config;
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor;
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.http.CapturedHttpHeaders;
|
||||||
|
import io.opentelemetry.instrumentation.restlet.v2_0.internal.RestletInstrumenterFactory;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import org.restlet.Request;
|
||||||
|
import org.restlet.Response;
|
||||||
|
|
||||||
|
/** A builder of {@link RestletTracing}. */
|
||||||
|
public final class RestletTracingBuilder {
|
||||||
|
|
||||||
|
private final OpenTelemetry openTelemetry;
|
||||||
|
private final List<AttributesExtractor<Request, Response>> additionalExtractors =
|
||||||
|
new ArrayList<>();
|
||||||
|
private CapturedHttpHeaders capturedHttpHeaders = CapturedHttpHeaders.server(Config.get());
|
||||||
|
|
||||||
|
RestletTracingBuilder(OpenTelemetry openTelemetry) {
|
||||||
|
this.openTelemetry = openTelemetry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an additional {@link AttributesExtractor} to invoke to set attributes to instrumented
|
||||||
|
* items.
|
||||||
|
*/
|
||||||
|
public RestletTracingBuilder addAttributesExtractor(
|
||||||
|
AttributesExtractor<Request, Response> attributesExtractor) {
|
||||||
|
additionalExtractors.add(attributesExtractor);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure the instrumentation to capture chosen HTTP request and response headers as span
|
||||||
|
* attributes.
|
||||||
|
*
|
||||||
|
* @param capturedHttpHeaders An instance of {@link CapturedHttpHeaders} containing the configured
|
||||||
|
* HTTP request and response names.
|
||||||
|
*/
|
||||||
|
public RestletTracingBuilder captureHttpHeaders(CapturedHttpHeaders capturedHttpHeaders) {
|
||||||
|
this.capturedHttpHeaders = capturedHttpHeaders;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new {@link RestletTracing} with the settings of this {@link RestletTracingBuilder}.
|
||||||
|
*/
|
||||||
|
public RestletTracing build() {
|
||||||
|
|
||||||
|
Instrumenter<Request, Response> serverInstrumenter =
|
||||||
|
RestletInstrumenterFactory.newServerInstrumenter(
|
||||||
|
openTelemetry, capturedHttpHeaders, additionalExtractors);
|
||||||
|
|
||||||
|
return new RestletTracing(serverInstrumenter);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.restlet.v2_0;
|
||||||
|
|
||||||
|
import static io.opentelemetry.instrumentation.api.servlet.ServerSpanNaming.Source.CONTROLLER;
|
||||||
|
|
||||||
|
import io.opentelemetry.context.Context;
|
||||||
|
import io.opentelemetry.context.Scope;
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||||
|
import io.opentelemetry.instrumentation.api.servlet.ServerSpanNaming;
|
||||||
|
import io.opentelemetry.instrumentation.restlet.v2_0.internal.RestletServerSpanNaming;
|
||||||
|
import org.restlet.Request;
|
||||||
|
import org.restlet.Response;
|
||||||
|
import org.restlet.resource.ResourceException;
|
||||||
|
import org.restlet.routing.Filter;
|
||||||
|
|
||||||
|
final class TracingFilter extends Filter {
|
||||||
|
|
||||||
|
private final Instrumenter<Request, Response> instrumenter;
|
||||||
|
private final String path;
|
||||||
|
|
||||||
|
public TracingFilter(Instrumenter<Request, Response> instrumenter, String path) {
|
||||||
|
this.instrumenter = instrumenter;
|
||||||
|
this.path = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int doHandle(Request request, Response response) {
|
||||||
|
|
||||||
|
Context parentContext = Context.current();
|
||||||
|
Context context = parentContext;
|
||||||
|
|
||||||
|
Scope scope = null;
|
||||||
|
|
||||||
|
if (instrumenter.shouldStart(parentContext, request)) {
|
||||||
|
context = instrumenter.start(parentContext, request);
|
||||||
|
scope = context.makeCurrent();
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerSpanNaming.updateServerSpanName(
|
||||||
|
context, CONTROLLER, RestletServerSpanNaming.SERVER_SPAN_NAME, path);
|
||||||
|
|
||||||
|
Throwable statusThrowable = null;
|
||||||
|
try {
|
||||||
|
super.doHandle(request, response);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
|
||||||
|
statusThrowable = t;
|
||||||
|
|
||||||
|
if (t instanceof Error || t instanceof RuntimeException) {
|
||||||
|
throw t;
|
||||||
|
} else {
|
||||||
|
throw new ResourceException(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
|
||||||
|
if (scope != null) {
|
||||||
|
|
||||||
|
scope.close();
|
||||||
|
if (response.getStatus() != null && response.getStatus().isError()) {
|
||||||
|
statusThrowable = response.getStatus().getThrowable();
|
||||||
|
}
|
||||||
|
instrumenter.end(context, request, response, statusThrowable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return CONTINUE;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.restlet.v2_0.internal;
|
||||||
|
|
||||||
|
import io.opentelemetry.context.propagation.TextMapGetter;
|
||||||
|
import org.restlet.Message;
|
||||||
|
import org.restlet.Request;
|
||||||
|
import org.restlet.util.Series;
|
||||||
|
|
||||||
|
final class RestletHeadersGetter implements TextMapGetter<Request> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterable<String> keys(Request carrier) {
|
||||||
|
return getHeaders(carrier).getNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String get(Request carrier, String key) {
|
||||||
|
Series<?> headers = getHeaders(carrier);
|
||||||
|
return headers.getFirstValue(key, /* ignoreCase = */ true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Series<?> getHeaders(Message carrier) {
|
||||||
|
return (Series<?>) carrier.getAttributes().get("org.restlet.http.headers");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,122 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.restlet.v2_0.internal;
|
||||||
|
|
||||||
|
import static io.opentelemetry.instrumentation.restlet.v2_0.internal.RestletHeadersGetter.getHeaders;
|
||||||
|
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.http.CapturedHttpHeaders;
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerAttributesExtractor;
|
||||||
|
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import org.restlet.Request;
|
||||||
|
import org.restlet.Response;
|
||||||
|
import org.restlet.data.Reference;
|
||||||
|
import org.restlet.util.Series;
|
||||||
|
|
||||||
|
final class RestletHttpAttributesExtractor
|
||||||
|
extends HttpServerAttributesExtractor<Request, Response> {
|
||||||
|
|
||||||
|
RestletHttpAttributesExtractor(CapturedHttpHeaders capturedHttpHeaders) {
|
||||||
|
super(capturedHttpHeaders);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String method(Request request) {
|
||||||
|
return request.getMethod().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
protected String target(Request request) {
|
||||||
|
Reference ref = request.getOriginalRef();
|
||||||
|
String path = ref.getPath();
|
||||||
|
return ref.hasQuery() ? path + "?" + ref.getQuery() : path;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
protected String route(Request request) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
protected String scheme(Request request) {
|
||||||
|
return request.getOriginalRef().getScheme();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<String> requestHeader(Request request, String name) {
|
||||||
|
Series<?> headers = getHeaders(request);
|
||||||
|
if (headers == null) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
return Arrays.asList(headers.getValuesArray(name, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
protected Long requestContentLength(Request request, @Nullable Response response) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
protected Long requestContentLengthUncompressed(Request request, @Nullable Response response) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
protected String flavor(Request request) {
|
||||||
|
switch (request.getProtocol().toString()) {
|
||||||
|
case "HTTP/1.0":
|
||||||
|
return SemanticAttributes.HttpFlavorValues.HTTP_1_0;
|
||||||
|
case "HTTP/1.1":
|
||||||
|
return SemanticAttributes.HttpFlavorValues.HTTP_1_1;
|
||||||
|
case "HTTP/2.0":
|
||||||
|
return SemanticAttributes.HttpFlavorValues.HTTP_2_0;
|
||||||
|
default:
|
||||||
|
// fall through
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
protected String serverName(Request request, @Nullable Response response) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Integer statusCode(Request request, Response response) {
|
||||||
|
return response.getStatus().getCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
protected Long responseContentLength(Request request, Response response) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
protected Long responseContentLengthUncompressed(Request request, Response response) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<String> responseHeader(Request request, Response response, String name) {
|
||||||
|
Series<?> headers = getHeaders(response);
|
||||||
|
if (headers == null) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
return Arrays.asList(headers.getValuesArray(name, true));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.restlet.v2_0.internal;
|
||||||
|
|
||||||
|
import io.opentelemetry.api.OpenTelemetry;
|
||||||
|
import io.opentelemetry.instrumentation.api.config.Config;
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor;
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor;
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor;
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.http.CapturedHttpHeaders;
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerAttributesExtractor;
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpServerMetrics;
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.net.NetServerAttributesExtractor;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import org.restlet.Request;
|
||||||
|
import org.restlet.Response;
|
||||||
|
|
||||||
|
public class RestletInstrumenterFactory {
|
||||||
|
|
||||||
|
private static final String INSTRUMENTATION_NAME = "io.opentelemetry.restlet-2.0";
|
||||||
|
|
||||||
|
public static Instrumenter<Request, Response> newServerInstrumenter(OpenTelemetry openTelemetry) {
|
||||||
|
return newServerInstrumenter(
|
||||||
|
openTelemetry, CapturedHttpHeaders.server(Config.get()), Collections.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Instrumenter<Request, Response> newServerInstrumenter(
|
||||||
|
OpenTelemetry openTelemetry,
|
||||||
|
CapturedHttpHeaders capturedHttpHeaders,
|
||||||
|
List<AttributesExtractor<Request, Response>> additionalExtractors) {
|
||||||
|
|
||||||
|
HttpServerAttributesExtractor<Request, Response> httpAttributesExtractor =
|
||||||
|
new RestletHttpAttributesExtractor(capturedHttpHeaders);
|
||||||
|
SpanNameExtractor<Request> spanNameExtractor =
|
||||||
|
HttpSpanNameExtractor.create(httpAttributesExtractor);
|
||||||
|
SpanStatusExtractor<Request, Response> spanStatusExtractor =
|
||||||
|
HttpSpanStatusExtractor.create(httpAttributesExtractor);
|
||||||
|
NetServerAttributesExtractor<Request, Response> netAttributesExtractor =
|
||||||
|
new RestletNetAttributesExtractor();
|
||||||
|
|
||||||
|
return Instrumenter.<Request, Response>builder(
|
||||||
|
openTelemetry, INSTRUMENTATION_NAME, spanNameExtractor)
|
||||||
|
.setSpanStatusExtractor(spanStatusExtractor)
|
||||||
|
.addAttributesExtractor(httpAttributesExtractor)
|
||||||
|
.addAttributesExtractor(netAttributesExtractor)
|
||||||
|
.addAttributesExtractors(additionalExtractors)
|
||||||
|
.addRequestMetrics(HttpServerMetrics.get())
|
||||||
|
.newServerInstrumenter(new RestletHeadersGetter());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.restlet.v2_0.internal;
|
||||||
|
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.net.NetServerAttributesExtractor;
|
||||||
|
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import org.restlet.Request;
|
||||||
|
import org.restlet.Response;
|
||||||
|
|
||||||
|
final class RestletNetAttributesExtractor extends NetServerAttributesExtractor<Request, Response> {
|
||||||
|
@Override
|
||||||
|
public String transport(Request request) {
|
||||||
|
return SemanticAttributes.NetTransportValues.IP_TCP;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public String peerName(Request request) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer peerPort(Request request) {
|
||||||
|
return request.getClientInfo().getPort();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public String peerIp(Request request) {
|
||||||
|
return request.getClientInfo().getAddress();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.restlet.v2_0.internal;
|
||||||
|
|
||||||
|
import io.opentelemetry.instrumentation.api.servlet.ServerSpanNameSupplier;
|
||||||
|
import io.opentelemetry.instrumentation.api.servlet.ServletContextPath;
|
||||||
|
|
||||||
|
public final class RestletServerSpanNaming {
|
||||||
|
|
||||||
|
public static final ServerSpanNameSupplier<String> SERVER_SPAN_NAME =
|
||||||
|
(context, pattern) -> {
|
||||||
|
if (pattern == null || pattern.equals("")) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ServletContextPath.prepend(context, pattern);
|
||||||
|
};
|
||||||
|
|
||||||
|
private RestletServerSpanNaming() {}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.restlet.v2_0
|
||||||
|
|
||||||
|
import io.opentelemetry.instrumentation.test.LibraryTestTrait
|
||||||
|
import org.restlet.Restlet
|
||||||
|
import org.restlet.engine.application.StatusFilter
|
||||||
|
import org.restlet.service.StatusService
|
||||||
|
|
||||||
|
class RestletServerTest extends AbstractRestletServerTest implements LibraryTestTrait {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Restlet wrapRestlet(Restlet restlet, String path) {
|
||||||
|
|
||||||
|
RestletTracing tracing = RestletTracing.builder(openTelemetry)
|
||||||
|
.captureHttpHeaders(capturedHttpHeadersForTesting())
|
||||||
|
.build()
|
||||||
|
|
||||||
|
def tracingFilter = tracing.newFilter(path)
|
||||||
|
def statusFilter = new StatusFilter(component.getContext(), new StatusService())
|
||||||
|
|
||||||
|
tracingFilter.setNext(statusFilter)
|
||||||
|
statusFilter.setNext(restlet)
|
||||||
|
|
||||||
|
return tracingFilter
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
plugins {
|
||||||
|
id("otel.java-conventions")
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
maven("https://maven.restlet.talend.com/")
|
||||||
|
mavenLocal()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
api(project(":testing-common"))
|
||||||
|
|
||||||
|
implementation("org.restlet.jse:org.restlet:2.0.2")
|
||||||
|
|
||||||
|
implementation("org.codehaus.groovy:groovy-all")
|
||||||
|
implementation("io.opentelemetry:opentelemetry-api")
|
||||||
|
implementation("org.spockframework:spock-core")
|
||||||
|
}
|
|
@ -0,0 +1,195 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.restlet.v2_0
|
||||||
|
|
||||||
|
import io.opentelemetry.api.common.AttributeKey
|
||||||
|
import io.opentelemetry.instrumentation.test.base.HttpServerTest
|
||||||
|
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
|
||||||
|
import org.restlet.Component
|
||||||
|
import org.restlet.Context
|
||||||
|
import org.restlet.Request
|
||||||
|
import org.restlet.Response
|
||||||
|
import org.restlet.Restlet
|
||||||
|
import org.restlet.Server
|
||||||
|
import org.restlet.data.Form
|
||||||
|
import org.restlet.data.MediaType
|
||||||
|
import org.restlet.data.Protocol
|
||||||
|
import org.restlet.data.Status
|
||||||
|
import org.restlet.routing.Redirector
|
||||||
|
import org.restlet.routing.Router
|
||||||
|
import org.restlet.routing.Template
|
||||||
|
import org.restlet.routing.VirtualHost
|
||||||
|
|
||||||
|
import static io.opentelemetry.instrumentation.test.base.HttpServerTest.ServerEndpoint.CAPTURE_HEADERS
|
||||||
|
import static io.opentelemetry.instrumentation.test.base.HttpServerTest.ServerEndpoint.ERROR
|
||||||
|
import static io.opentelemetry.instrumentation.test.base.HttpServerTest.ServerEndpoint.EXCEPTION
|
||||||
|
import static io.opentelemetry.instrumentation.test.base.HttpServerTest.ServerEndpoint.INDEXED_CHILD
|
||||||
|
import static io.opentelemetry.instrumentation.test.base.HttpServerTest.ServerEndpoint.NOT_FOUND
|
||||||
|
import static io.opentelemetry.instrumentation.test.base.HttpServerTest.ServerEndpoint.PATH_PARAM
|
||||||
|
import static io.opentelemetry.instrumentation.test.base.HttpServerTest.ServerEndpoint.QUERY_PARAM
|
||||||
|
import static io.opentelemetry.instrumentation.test.base.HttpServerTest.ServerEndpoint.REDIRECT
|
||||||
|
import static io.opentelemetry.instrumentation.test.base.HttpServerTest.ServerEndpoint.SUCCESS
|
||||||
|
|
||||||
|
abstract class AbstractRestletServerTest extends HttpServerTest<Server> {
|
||||||
|
|
||||||
|
Component component
|
||||||
|
VirtualHost host
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Server startServer(int port) {
|
||||||
|
|
||||||
|
component = new Component()
|
||||||
|
host = component.getDefaultHost()
|
||||||
|
def server = setupServer(component)
|
||||||
|
setupRouting()
|
||||||
|
|
||||||
|
component.start()
|
||||||
|
|
||||||
|
return server
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void stopServer(Server server) {
|
||||||
|
component.stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
def attachAndWrap(path, restlet) {
|
||||||
|
host.attach(path, wrapRestlet(restlet, path))
|
||||||
|
}
|
||||||
|
|
||||||
|
Server setupServer(Component component) {
|
||||||
|
return component.getServers().add(Protocol.HTTP, port)
|
||||||
|
}
|
||||||
|
|
||||||
|
void setupRouting() {
|
||||||
|
|
||||||
|
def defaultRouter = wrapRestlet(new Router(host.getContext()), "/*")
|
||||||
|
host.attach("/", defaultRouter).setMatchingMode(Template.MODE_STARTS_WITH)
|
||||||
|
|
||||||
|
attachAndWrap(SUCCESS.path, new Restlet() {
|
||||||
|
@Override
|
||||||
|
void handle(Request request, Response response) {
|
||||||
|
controller(SUCCESS) {
|
||||||
|
response.setEntity(SUCCESS.body, MediaType.TEXT_PLAIN)
|
||||||
|
response.setStatus(Status.valueOf(SUCCESS.status), SUCCESS.body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
attachAndWrap(REDIRECT.path, new Redirector(Context.getCurrent(), REDIRECT.body, Redirector.MODE_CLIENT_FOUND) {
|
||||||
|
@Override
|
||||||
|
void handle(Request request, Response response) {
|
||||||
|
super.handle(request, response)
|
||||||
|
controller(REDIRECT) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
attachAndWrap(ERROR.path, new Restlet() {
|
||||||
|
@Override
|
||||||
|
void handle(Request request, Response response) {
|
||||||
|
controller(ERROR) {
|
||||||
|
response.setStatus(Status.valueOf(ERROR.getStatus()), ERROR.getBody())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
attachAndWrap(EXCEPTION.path, new Restlet() {
|
||||||
|
@Override
|
||||||
|
void handle(Request request, Response response) {
|
||||||
|
controller(EXCEPTION) {
|
||||||
|
throw new Exception(EXCEPTION.getBody())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
attachAndWrap(QUERY_PARAM.path, new Restlet() {
|
||||||
|
@Override
|
||||||
|
void handle(Request request, Response response) {
|
||||||
|
controller(QUERY_PARAM) {
|
||||||
|
response.setEntity(QUERY_PARAM.getBody(), MediaType.TEXT_PLAIN)
|
||||||
|
response.setStatus(Status.valueOf(QUERY_PARAM.getStatus()), QUERY_PARAM.getBody())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
attachAndWrap("/path/{id}/param", new Restlet() {
|
||||||
|
@Override
|
||||||
|
void handle(Request request, Response response) {
|
||||||
|
controller(PATH_PARAM) {
|
||||||
|
response.setEntity(PATH_PARAM.getBody(), MediaType.TEXT_PLAIN)
|
||||||
|
response.setStatus(Status.valueOf(PATH_PARAM.getStatus()), PATH_PARAM.getBody())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
attachAndWrap("/captureHeaders", new Restlet() {
|
||||||
|
@Override
|
||||||
|
void handle(Request request, Response response) {
|
||||||
|
controller(CAPTURE_HEADERS) {
|
||||||
|
|
||||||
|
def requestHeaders = request.getAttributes().get("org.restlet.http.headers")
|
||||||
|
def responseHeaders
|
||||||
|
|
||||||
|
try {
|
||||||
|
def headerClass = Class.forName("org.restlet.data.Header")
|
||||||
|
def seriesClass = Class.forName("org.restlet.util.Series")
|
||||||
|
//to avoid constructor error (Series is abstract in 2.0.x)
|
||||||
|
responseHeaders = response.getAttributes().computeIfAbsent("org.restlet.http.headers", { seriesClass.newInstance(headerClass) })
|
||||||
|
|
||||||
|
} catch (ClassNotFoundException | NoClassDefFoundError e) {
|
||||||
|
|
||||||
|
responseHeaders = response.getAttributes().computeIfAbsent("org.restlet.http.headers", { new Form() })
|
||||||
|
}
|
||||||
|
|
||||||
|
responseHeaders.add("X-Test-Response", requestHeaders.getValues("X-Test-Request"))
|
||||||
|
|
||||||
|
response.setEntity(CAPTURE_HEADERS.getBody(), MediaType.TEXT_PLAIN)
|
||||||
|
response.setStatus(Status.valueOf(CAPTURE_HEADERS.getStatus()), CAPTURE_HEADERS.getBody())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
attachAndWrap(INDEXED_CHILD.path, new Restlet() {
|
||||||
|
@Override
|
||||||
|
void handle(Request request, Response response) {
|
||||||
|
controller(INDEXED_CHILD) {
|
||||||
|
INDEXED_CHILD.collectSpanAttributes { request.getOriginalRef().getQueryAsForm().getFirst(it).getValue() }
|
||||||
|
response.setStatus(Status.valueOf(INDEXED_CHILD.status))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
List<AttributeKey<?>> extraAttributes() {
|
||||||
|
[
|
||||||
|
SemanticAttributes.NET_TRANSPORT
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean testPathParam() {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
String expectedServerSpanName(ServerEndpoint endpoint) {
|
||||||
|
switch (endpoint) {
|
||||||
|
case PATH_PARAM:
|
||||||
|
return getContextPath() + "/path/{id}/param"
|
||||||
|
case NOT_FOUND:
|
||||||
|
return getContextPath() + "/*"
|
||||||
|
default:
|
||||||
|
return endpoint.resolvePath(address).path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Restlet wrapRestlet(Restlet restlet, String path) {
|
||||||
|
return restlet
|
||||||
|
}
|
||||||
|
}
|
|
@ -294,6 +294,9 @@ include(":instrumentation:redisson-3.0:javaagent")
|
||||||
include(":instrumentation:restlet:restlet-1.0:javaagent")
|
include(":instrumentation:restlet:restlet-1.0:javaagent")
|
||||||
include(":instrumentation:restlet:restlet-1.0:library")
|
include(":instrumentation:restlet:restlet-1.0:library")
|
||||||
include(":instrumentation:restlet:restlet-1.0:testing")
|
include(":instrumentation:restlet:restlet-1.0:testing")
|
||||||
|
include(":instrumentation:restlet:restlet-2.0:javaagent")
|
||||||
|
include(":instrumentation:restlet:restlet-2.0:library")
|
||||||
|
include(":instrumentation:restlet:restlet-2.0:testing")
|
||||||
include(":instrumentation:rmi:bootstrap")
|
include(":instrumentation:rmi:bootstrap")
|
||||||
include(":instrumentation:rmi:javaagent")
|
include(":instrumentation:rmi:javaagent")
|
||||||
include(":instrumentation:rocketmq-client-4.8:javaagent")
|
include(":instrumentation:rocketmq-client-4.8:javaagent")
|
||||||
|
|
Loading…
Reference in New Issue