-
Notifications
You must be signed in to change notification settings - Fork 893
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Capture http.route for pekko-http (#10799)
Co-authored-by: Lauri Tulmin <[email protected]>
- Loading branch information
Showing
12 changed files
with
486 additions
and
44 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
43 changes: 43 additions & 0 deletions
43
...vaagent/instrumentation/pekkohttp/v1_0/server/route/PathConcatenationInstrumentation.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.javaagent.instrumentation.pekkohttp.v1_0.server.route; | ||
|
||
import static net.bytebuddy.matcher.ElementMatchers.namedOneOf; | ||
|
||
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; | ||
|
||
public class PathConcatenationInstrumentation implements TypeInstrumentation { | ||
@Override | ||
public ElementMatcher<TypeDescription> typeMatcher() { | ||
return namedOneOf( | ||
"org.apache.pekko.http.scaladsl.server.PathMatcher$$anonfun$$tilde$1", | ||
"org.apache.pekko.http.scaladsl.server.PathMatcher"); | ||
} | ||
|
||
@Override | ||
public void transform(TypeTransformer transformer) { | ||
transformer.applyAdviceToMethod( | ||
namedOneOf("apply", "$anonfun$append$1"), this.getClass().getName() + "$ApplyAdvice"); | ||
} | ||
|
||
@SuppressWarnings("unused") | ||
public static class ApplyAdvice { | ||
|
||
@Advice.OnMethodEnter(suppress = Throwable.class) | ||
public static void onEnter() { | ||
// https://github.com/apache/incubator-pekko-http/blob/bea7d2b5c21e23d55556409226d136c282da27a3/http/src/main/scala/org/apache/pekko/http/scaladsl/server/PathMatcher.scala#L53 | ||
// https://github.com/apache/incubator-pekko-http/blob/bea7d2b5c21e23d55556409226d136c282da27a3/http/src/main/scala/org/apache/pekko/http/scaladsl/server/PathMatcher.scala#L57 | ||
// when routing dsl uses path("path1" / "path2") we are concatenating 3 segments "path1" and / | ||
// and "path2" we need to notify the matcher that a new segment has started, so it could be | ||
// captured in the route | ||
PekkoRouteHolder.startSegment(); | ||
} | ||
} | ||
} |
47 changes: 47 additions & 0 deletions
47
...try/javaagent/instrumentation/pekkohttp/v1_0/server/route/PathMatcherInstrumentation.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.javaagent.instrumentation.pekkohttp.v1_0.server.route; | ||
|
||
import static net.bytebuddy.matcher.ElementMatchers.named; | ||
import static net.bytebuddy.matcher.ElementMatchers.returns; | ||
import static net.bytebuddy.matcher.ElementMatchers.takesArgument; | ||
|
||
import io.opentelemetry.instrumentation.api.util.VirtualField; | ||
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.apache.pekko.http.scaladsl.model.Uri; | ||
import org.apache.pekko.http.scaladsl.server.PathMatcher; | ||
|
||
public class PathMatcherInstrumentation implements TypeInstrumentation { | ||
@Override | ||
public ElementMatcher<TypeDescription> typeMatcher() { | ||
return named("org.apache.pekko.http.scaladsl.server.PathMatcher$"); | ||
} | ||
|
||
@Override | ||
public void transform(TypeTransformer transformer) { | ||
transformer.applyAdviceToMethod( | ||
named("apply") | ||
.and(takesArgument(0, named("org.apache.pekko.http.scaladsl.model.Uri$Path"))) | ||
.and(returns(named("org.apache.pekko.http.scaladsl.server.PathMatcher"))), | ||
this.getClass().getName() + "$ApplyAdvice"); | ||
} | ||
|
||
@SuppressWarnings("unused") | ||
public static class ApplyAdvice { | ||
|
||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) | ||
public static void onEnter( | ||
@Advice.Argument(0) Uri.Path prefix, @Advice.Return PathMatcher<?> result) { | ||
// store the path being matched inside a VirtualField on the given matcher, so it can be used | ||
// for constructing the route | ||
VirtualField.find(PathMatcher.class, String.class).set(result, prefix.toString()); | ||
} | ||
} | ||
} |
67 changes: 67 additions & 0 deletions
67
...vaagent/instrumentation/pekkohttp/v1_0/server/route/PathMatcherStaticInstrumentation.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.javaagent.instrumentation.pekkohttp.v1_0.server.route; | ||
|
||
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.extendsClass; | ||
import static net.bytebuddy.matcher.ElementMatchers.named; | ||
import static net.bytebuddy.matcher.ElementMatchers.takesArgument; | ||
|
||
import io.opentelemetry.instrumentation.api.util.VirtualField; | ||
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.apache.pekko.http.scaladsl.model.Uri; | ||
import org.apache.pekko.http.scaladsl.server.PathMatcher; | ||
import org.apache.pekko.http.scaladsl.server.PathMatchers; | ||
import org.apache.pekko.http.scaladsl.server.PathMatchers$; | ||
|
||
public class PathMatcherStaticInstrumentation implements TypeInstrumentation { | ||
@Override | ||
public ElementMatcher<TypeDescription> typeMatcher() { | ||
return extendsClass(named("org.apache.pekko.http.scaladsl.server.PathMatcher")); | ||
} | ||
|
||
@Override | ||
public void transform(TypeTransformer transformer) { | ||
transformer.applyAdviceToMethod( | ||
named("apply") | ||
.and(takesArgument(0, named("org.apache.pekko.http.scaladsl.model.Uri$Path"))), | ||
this.getClass().getName() + "$ApplyAdvice"); | ||
} | ||
|
||
@SuppressWarnings("unused") | ||
public static class ApplyAdvice { | ||
|
||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) | ||
public static void onExit( | ||
@Advice.This PathMatcher<?> pathMatcher, | ||
@Advice.Argument(0) Uri.Path path, | ||
@Advice.Return PathMatcher.Matching<?> result) { | ||
// result is either matched or unmatched, we only care about the matches | ||
if (result.getClass() == PathMatcher.Matched.class) { | ||
if (PathMatchers$.PathEnd$.class == pathMatcher.getClass()) { | ||
PekkoRouteHolder.endMatched(); | ||
return; | ||
} | ||
// if present use the matched path that was remembered in PathMatcherInstrumentation, | ||
// otherwise just use a * | ||
String prefix = VirtualField.find(PathMatcher.class, String.class).get(pathMatcher); | ||
if (prefix == null) { | ||
if (PathMatchers.Slash$.class == pathMatcher.getClass()) { | ||
prefix = "/"; | ||
} else { | ||
prefix = "*"; | ||
} | ||
} | ||
if (prefix != null) { | ||
PekkoRouteHolder.push(prefix); | ||
} | ||
} | ||
} | ||
} | ||
} |
40 changes: 40 additions & 0 deletions
40
...nstrumentation/pekkohttp/v1_0/server/route/PekkoHttpServerRouteInstrumentationModule.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.javaagent.instrumentation.pekkohttp.v1_0.server.route; | ||
|
||
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; | ||
|
||
/** | ||
* This instrumentation applies to classes in pekko-http.jar while | ||
* PekkoHttpServerInstrumentationModule applies to classes in pekko-http-core.jar | ||
*/ | ||
@AutoService(InstrumentationModule.class) | ||
public class PekkoHttpServerRouteInstrumentationModule extends InstrumentationModule { | ||
public PekkoHttpServerRouteInstrumentationModule() { | ||
super("pekko-http", "pekko-http-1.0", "pekko-http-server", "pekko-http-server-route"); | ||
} | ||
|
||
@Override | ||
public boolean isIndyModule() { | ||
// PekkoHttpServerInstrumentationModule and PekkoHttpServerRouteInstrumentationModule share | ||
// PekkoRouteHolder class | ||
return false; | ||
} | ||
|
||
@Override | ||
public List<TypeInstrumentation> typeInstrumentations() { | ||
return asList( | ||
new PathMatcherInstrumentation(), | ||
new PathMatcherStaticInstrumentation(), | ||
new RouteConcatenationInstrumentation(), | ||
new PathConcatenationInstrumentation()); | ||
} | ||
} |
79 changes: 79 additions & 0 deletions
79
...opentelemetry/javaagent/instrumentation/pekkohttp/v1_0/server/route/PekkoRouteHolder.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.javaagent.instrumentation.pekkohttp.v1_0.server.route; | ||
|
||
import static io.opentelemetry.context.ContextKey.named; | ||
|
||
import io.opentelemetry.context.Context; | ||
import io.opentelemetry.context.ContextKey; | ||
import io.opentelemetry.context.ImplicitContextKeyed; | ||
import io.opentelemetry.instrumentation.api.semconv.http.HttpServerRoute; | ||
import io.opentelemetry.instrumentation.api.semconv.http.HttpServerRouteSource; | ||
import java.util.ArrayDeque; | ||
import java.util.Deque; | ||
|
||
public class PekkoRouteHolder implements ImplicitContextKeyed { | ||
private static final ContextKey<PekkoRouteHolder> KEY = named("opentelemetry-pekko-route"); | ||
|
||
private String route = ""; | ||
private boolean newSegment; | ||
private boolean endMatched; | ||
private final Deque<String> stack = new ArrayDeque<>(); | ||
|
||
public static Context init(Context context) { | ||
if (context.get(KEY) != null) { | ||
return context; | ||
} | ||
return context.with(new PekkoRouteHolder()); | ||
} | ||
|
||
public static void push(String path) { | ||
PekkoRouteHolder holder = Context.current().get(KEY); | ||
if (holder != null && holder.newSegment && !holder.endMatched) { | ||
holder.route += path; | ||
holder.newSegment = false; | ||
} | ||
} | ||
|
||
public static void startSegment() { | ||
PekkoRouteHolder holder = Context.current().get(KEY); | ||
if (holder != null) { | ||
holder.newSegment = true; | ||
} | ||
} | ||
|
||
public static void endMatched() { | ||
Context context = Context.current(); | ||
PekkoRouteHolder holder = context.get(KEY); | ||
if (holder != null) { | ||
holder.endMatched = true; | ||
HttpServerRoute.update(context, HttpServerRouteSource.CONTROLLER, holder.route); | ||
} | ||
} | ||
|
||
public static void save() { | ||
PekkoRouteHolder holder = Context.current().get(KEY); | ||
if (holder != null) { | ||
holder.stack.push(holder.route); | ||
holder.newSegment = true; | ||
} | ||
} | ||
|
||
public static void restore() { | ||
PekkoRouteHolder holder = Context.current().get(KEY); | ||
if (holder != null) { | ||
holder.route = holder.stack.pop(); | ||
holder.newSegment = true; | ||
} | ||
} | ||
|
||
@Override | ||
public Context storeInContext(Context context) { | ||
return context.with(KEY, this); | ||
} | ||
|
||
private PekkoRouteHolder() {} | ||
} |
46 changes: 46 additions & 0 deletions
46
...aagent/instrumentation/pekkohttp/v1_0/server/route/RouteConcatenationInstrumentation.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.javaagent.instrumentation.pekkohttp.v1_0.server.route; | ||
|
||
import static net.bytebuddy.matcher.ElementMatchers.namedOneOf; | ||
|
||
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; | ||
|
||
public class RouteConcatenationInstrumentation implements TypeInstrumentation { | ||
@Override | ||
public ElementMatcher<TypeDescription> typeMatcher() { | ||
return namedOneOf( | ||
"org.apache.pekko.http.scaladsl.server.RouteConcatenation$RouteWithConcatenation$$anonfun$$tilde$1", | ||
"org.apache.pekko.http.scaladsl.server.RouteConcatenation$RouteWithConcatenation"); | ||
} | ||
|
||
@Override | ||
public void transform(TypeTransformer transformer) { | ||
transformer.applyAdviceToMethod( | ||
namedOneOf("apply", "$anonfun$$tilde$1"), this.getClass().getName() + "$ApplyAdvice"); | ||
} | ||
|
||
@SuppressWarnings("unused") | ||
public static class ApplyAdvice { | ||
|
||
@Advice.OnMethodEnter(suppress = Throwable.class) | ||
public static void onEnter() { | ||
// when routing dsl uses concat(path(...) {...}, path(...) {...}) we'll restore the currently | ||
// matched route after each matcher so that match attempts that failed wouldn't get recorded | ||
// in the route | ||
PekkoRouteHolder.save(); | ||
} | ||
|
||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) | ||
public static void onExit() { | ||
PekkoRouteHolder.restore(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.