-
Notifications
You must be signed in to change notification settings - Fork 144
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #271 from newrelic/akka-http-2.13_2.4.5
Add new akka-http-2.13_10.1.8 instrumentation module
- Loading branch information
Showing
59 changed files
with
3,889 additions
and
6 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
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
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,41 @@ | ||
apply plugin: 'scala' | ||
|
||
sourceSets.test.scala.srcDir "src/test/java" | ||
sourceSets.test.java.srcDirs = [] | ||
|
||
jar { | ||
manifest { attributes 'Implementation-Title': 'com.newrelic.instrumentation.akka-http-2.13_10.1.8' } | ||
} | ||
|
||
dependencies { | ||
implementation(project(":agent-bridge")) | ||
implementation("com.typesafe.akka:akka-http_2.13:10.1.8") | ||
implementation("com.typesafe.akka:akka-stream_2.13:2.5.23") | ||
implementation("com.typesafe.akka:akka-actor_2.13:2.5.23") | ||
|
||
testImplementation(project(":instrumentation:akka-2.2")) { transitive = false } | ||
testImplementation(project(":instrumentation:scala-2.13.0")) { transitive = false } | ||
testImplementation("com.jayway.restassured:rest-assured:2.7.0") | ||
testImplementation("javax.xml.bind:jaxb-api:2.3.0") | ||
} | ||
|
||
verifyInstrumentation { | ||
passesOnly('com.typesafe.akka:akka-http_2.13:[10.1.8,)') { | ||
compile("com.typesafe.akka:akka-stream_2.13:2.5.23") | ||
} | ||
excludeRegex 'com.typesafe.akka:akka-http_2.13:.*(RC|M)[0-9]*$' | ||
excludeRegex 'com.typesafe.akka:akka-http_2.13:.*-[0-9a-f]{8}$' | ||
} | ||
|
||
site { | ||
title 'Akka Http' | ||
type 'Framework' | ||
} | ||
|
||
test { | ||
// our dependency on rest-assured precludes running the tests on java 1.7 due to | ||
// akka http only being able to run on java 1.8 and above from this version onward | ||
onlyIf { | ||
!project.hasProperty("test7") | ||
} | ||
} |
29 changes: 29 additions & 0 deletions
29
.../akka-http-2.13_10.1.8/src/main/scala/akka/http/scaladsl/marshalling/AkkaHttpMarshal.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,29 @@ | ||
/* | ||
* | ||
* * Copyright 2020 New Relic Corporation. All rights reserved. | ||
* * SPDX-License-Identifier: Apache-2.0 | ||
* | ||
*/ | ||
|
||
package akka.http.scaladsl.marshalling; | ||
|
||
import akka.http.scaladsl.model.HttpRequest; | ||
import akka.http.scaladsl.model.HttpResponse; | ||
import com.agent.instrumentation.akka.http.PathMatcherUtils; | ||
import com.agent.instrumentation.akka.http.RequestWrapper; | ||
import com.newrelic.api.agent.NewRelic; | ||
import com.newrelic.api.agent.weaver.Weave; | ||
import com.newrelic.api.agent.weaver.Weaver; | ||
import scala.concurrent.ExecutionContext; | ||
import scala.concurrent.Future; | ||
|
||
@Weave(originalName = "akka.http.scaladsl.marshalling.Marshal") | ||
public class AkkaHttpMarshal<A> { | ||
|
||
public Future<HttpResponse> toResponseFor(HttpRequest request, Marshaller<A, HttpResponse> m, ExecutionContext ec) { | ||
NewRelic.getAgent().getTransaction().setWebRequest(new RequestWrapper(request)); | ||
PathMatcherUtils.reset(); | ||
return Weaver.callOriginal(); | ||
} | ||
|
||
} |
48 changes: 48 additions & 0 deletions
48
...p-2.13_10.1.8/src/main/scala/akka/http/scaladsl/marshalling/AkkaHttpMarshallerMapper.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,48 @@ | ||
/* | ||
* | ||
* * Copyright 2020 New Relic Corporation. All rights reserved. | ||
* * SPDX-License-Identifier: Apache-2.0 | ||
* | ||
*/ | ||
|
||
package akka.http.scaladsl.marshalling; | ||
|
||
import akka.http.scaladsl.model.HttpResponse; | ||
import com.agent.instrumentation.akka.http.ResponseWrapper; | ||
import com.newrelic.agent.bridge.AgentBridge; | ||
import com.newrelic.api.agent.NewRelic; | ||
import com.newrelic.api.agent.Token; | ||
import com.newrelic.api.agent.Trace; | ||
import com.newrelic.api.agent.Transaction; | ||
import com.newrelic.api.agent.weaver.Weaver; | ||
import scala.runtime.AbstractFunction1; | ||
|
||
public class AkkaHttpMarshallerMapper extends AbstractFunction1<HttpResponse, HttpResponse> { | ||
|
||
private final Token token; | ||
|
||
public AkkaHttpMarshallerMapper(Token token) { | ||
this.token = token; | ||
} | ||
|
||
@Override | ||
@Trace(async = true) | ||
public HttpResponse apply(HttpResponse httpResponse) { | ||
try { | ||
if (token != null) { | ||
token.linkAndExpire(); | ||
} | ||
ResponseWrapper responseWrapper = new ResponseWrapper(httpResponse); | ||
Transaction transaction = NewRelic.getAgent().getTransaction(); | ||
transaction.setWebResponse(responseWrapper); | ||
transaction.addOutboundResponseHeaders(); | ||
transaction.markResponseSent(); | ||
|
||
return responseWrapper.response(); | ||
} catch (Throwable t) { | ||
AgentBridge.instrumentation.noticeInstrumentationError(t, Weaver.getImplementationTitle()); | ||
return httpResponse; | ||
} | ||
} | ||
|
||
} |
29 changes: 29 additions & 0 deletions
29
..._10.1.8/src/main/scala/akka/http/scaladsl/marshalling/AkkaHttpToResponseMarshallable.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,29 @@ | ||
/* | ||
* | ||
* * Copyright 2020 New Relic Corporation. All rights reserved. | ||
* * SPDX-License-Identifier: Apache-2.0 | ||
* | ||
*/ | ||
|
||
package akka.http.scaladsl.marshalling; | ||
|
||
import akka.http.scaladsl.model.HttpResponse; | ||
import com.newrelic.api.agent.Token; | ||
import com.newrelic.api.agent.weaver.MatchType; | ||
import com.newrelic.api.agent.weaver.NewField; | ||
import com.newrelic.api.agent.weaver.Weave; | ||
import com.newrelic.api.agent.weaver.Weaver; | ||
|
||
@Weave(type = MatchType.Interface, originalName = "akka.http.scaladsl.marshalling.ToResponseMarshallable") | ||
public abstract class AkkaHttpToResponseMarshallable { | ||
|
||
@NewField | ||
public Token token; | ||
|
||
public Marshaller<Object, HttpResponse> marshaller() { | ||
Marshaller<Object, HttpResponse> marshaller = Weaver.callOriginal(); | ||
AkkaHttpMarshallerMapper akkaHttpMarshallerMapper = new AkkaHttpMarshallerMapper(token); | ||
return marshaller.map(akkaHttpMarshallerMapper); | ||
} | ||
|
||
} |
68 changes: 68 additions & 0 deletions
68
...a-http-2.13_10.1.8/src/main/scala/akka/http/scaladsl/server/AkkaHttpContextFunction.scala
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,68 @@ | ||
/* | ||
* | ||
* * Copyright 2020 New Relic Corporation. All rights reserved. | ||
* * SPDX-License-Identifier: Apache-2.0 | ||
* | ||
*/ | ||
|
||
package akka.http.scaladsl.server | ||
|
||
import com.agent.instrumentation.akka.http.PathMatcherUtils | ||
import com.newrelic.agent.bridge.AgentBridge | ||
import com.newrelic.api.agent.Trace | ||
|
||
import java.util.concurrent.LinkedBlockingDeque | ||
import java.util.concurrent.atomic.{AtomicBoolean, AtomicInteger} | ||
import java.util.logging.Level | ||
import scala.collection.mutable | ||
import scala.concurrent.Future | ||
import scala.runtime.AbstractFunction1 | ||
|
||
object AkkaHttpContextFunction { | ||
|
||
final val retransformed = new AtomicBoolean(false) | ||
|
||
def contextWrapper(original: Function1[RequestContext, Future[RouteResult]]): Function1[RequestContext, Future[RouteResult]] = { | ||
if (retransformed.compareAndSet(false, true)) { | ||
AgentBridge.getAgent.getLogger.log(Level.FINER, "Retransforming akka.http.scaladsl.server.AkkaHttpContextFunction") | ||
AgentBridge.instrumentation.retransformUninstrumentedClass(classOf[ContextWrapper]) | ||
AgentBridge.getAgent.getLogger.log(Level.FINER, "Retransformed akka.http.scaladsl.server.AkkaHttpContextFunction") | ||
} | ||
|
||
new ContextWrapper(original) | ||
} | ||
|
||
} | ||
|
||
class ContextWrapper(original: Function1[RequestContext, Future[RouteResult]]) extends AbstractFunction1[RequestContext, Future[RouteResult]] { | ||
|
||
@Trace(dispatcher = true) | ||
override def apply(ctx: RequestContext): Future[RouteResult] = { | ||
try { | ||
val tracedMethod = AgentBridge.getAgent.getTracedMethod | ||
tracedMethod.setMetricName("AkkaHttp") | ||
// Akka-http 10.1.5 uses CallbackRunnable and we lose transaction context between Directives | ||
AgentBridge.getAgent.getTracedMethod.setTrackCallbackRunnable(true); | ||
val token = AgentBridge.getAgent.getTransaction(false).getToken | ||
PathMatcherUtils.setHttpRequest(ctx.request) | ||
// We use this method to wire up our RequestContext wrapper and start our transaction | ||
val newCtx = new NewRelicRequestContextWrapper(ctx, ctx.asInstanceOf[RequestContextImpl], token, | ||
new LinkedBlockingDeque[String], new AtomicBoolean(false), new AtomicInteger(0), new AtomicInteger(0), | ||
new LinkedBlockingDeque[String], new mutable.HashSet[String], ctx.request, ctx.unmatchedPath, ctx.executionContext, ctx.materializer, | ||
ctx.log, ctx.settings, ctx.parserSettings) | ||
original.apply(newCtx) | ||
} catch { | ||
case t: Throwable => { | ||
AgentBridge.instrumentation.noticeInstrumentationError(t, "akka-http-2.4.5") | ||
original.apply(ctx) | ||
} | ||
} | ||
} | ||
|
||
override def compose[A](g: (A) => RequestContext): (A) => Future[RouteResult] = original.compose(g) | ||
|
||
override def andThen[A](g: (Future[RouteResult]) => A): (RequestContext) => A = original.andThen(g) | ||
|
||
override def toString(): String = original.toString() | ||
|
||
} |
74 changes: 74 additions & 0 deletions
74
.../akka-http-2.13_10.1.8/src/main/scala/akka/http/scaladsl/server/AkkaHttpPathMatchers.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,74 @@ | ||
/* | ||
* | ||
* * Copyright 2020 New Relic Corporation. All rights reserved. | ||
* * SPDX-License-Identifier: Apache-2.0 | ||
* | ||
*/ | ||
|
||
package akka.http.scaladsl.server; | ||
|
||
import akka.http.scaladsl.model.Uri; | ||
import com.agent.instrumentation.akka.http.PathMatcherUtils; | ||
import com.newrelic.api.agent.weaver.MatchType; | ||
import com.newrelic.api.agent.weaver.Weave; | ||
import com.newrelic.api.agent.weaver.Weaver; | ||
import scala.Tuple1; | ||
import scala.runtime.BoxedUnit; | ||
|
||
@Weave(type = MatchType.ExactClass, originalName = "akka.http.scaladsl.server.PathMatchers") | ||
public class AkkaHttpPathMatchers { | ||
|
||
@Weave(type = MatchType.ExactClass, originalName = "akka.http.scaladsl.server.PathMatchers$Slash$") | ||
public static class AkkaHttpSlash$ { | ||
|
||
public PathMatcher.Matching<BoxedUnit> apply(final Uri.Path path) { | ||
PathMatcher.Matching<BoxedUnit> matching = Weaver.callOriginal(); | ||
PathMatcherUtils.appendSlash(path, matching); | ||
return matching; | ||
} | ||
|
||
} | ||
|
||
@Weave(type = MatchType.ExactClass, originalName = "akka.http.scaladsl.server.PathMatchers$Remaining$") | ||
public static class AkkaHttpRemaining$ { | ||
|
||
public PathMatcher.Matched<Tuple1<String>> apply(final Uri.Path path) { | ||
PathMatcher.Matched<Tuple1<String>> matched = Weaver.callOriginal(); | ||
PathMatcherUtils.appendRemaining("Remaining", path, matched); | ||
return matched; | ||
} | ||
|
||
} | ||
|
||
@Weave(type = MatchType.ExactClass, originalName = "akka.http.scaladsl.server.PathMatchers$RemainingPath$") | ||
public static class AkkaHttpRemainingPath$ { | ||
|
||
public PathMatcher.Matched<Tuple1<String>> apply(final Uri.Path path) { | ||
PathMatcher.Matched<Tuple1<String>> matched = Weaver.callOriginal(); | ||
PathMatcherUtils.appendRemaining("RemainingPath", path, matched); | ||
return matched; | ||
} | ||
|
||
} | ||
|
||
@Weave(type = MatchType.BaseClass, originalName = "akka.http.scaladsl.server.PathMatchers$NumberMatcher") | ||
public static class AkkaHttpNumberMatcher<T> { | ||
|
||
public PathMatcher.Matching<Tuple1<T>> apply(final Uri.Path path) { | ||
PathMatcher.Matching<Tuple1<T>> matching = Weaver.callOriginal(); | ||
PathMatcherUtils.appendNumberMatch(getClass().getSimpleName().replaceAll("\\$", ""), path, matching); | ||
return matching; | ||
} | ||
|
||
} | ||
|
||
@Weave(type = MatchType.ExactClass, originalName = "akka.http.scaladsl.server.PathMatchers$Segment$") | ||
public static class AkkaHttpSegment$ { | ||
|
||
public PathMatcher.Matching<Tuple1<String>> apply(final Uri.Path path) { | ||
PathMatcher.Matching<Tuple1<String>> matching = Weaver.callOriginal(); | ||
PathMatcherUtils.appendSegment(path, matching); | ||
return matching; | ||
} | ||
} | ||
} |
55 changes: 55 additions & 0 deletions
55
...ka-http-2.13_10.1.8/src/main/scala/akka/http/scaladsl/server/AkkaHttpRequestContext.scala
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,55 @@ | ||
/* | ||
* | ||
* * Copyright 2020 New Relic Corporation. All rights reserved. | ||
* * SPDX-License-Identifier: Apache-2.0 | ||
* | ||
*/ | ||
|
||
package akka.http.scaladsl.server | ||
|
||
import akka.event.LoggingAdapter | ||
import akka.http.scaladsl.marshalling.AkkaHttpToResponseMarshallable | ||
import akka.http.scaladsl.model._ | ||
import akka.http.scaladsl.settings.{ParserSettings, RoutingSettings} | ||
import akka.stream.Materializer | ||
import com.agent.instrumentation.akka.http.PathMatcherUtils | ||
import com.newrelic.api.agent.weaver.{Weave, Weaver} | ||
|
||
import java.util.concurrent.LinkedBlockingDeque | ||
import java.util.concurrent.atomic.{AtomicBoolean, AtomicInteger} | ||
import scala.collection.mutable | ||
import scala.concurrent.{ExecutionContextExecutor, Future} | ||
|
||
@Weave(originalName = "akka.http.scaladsl.server.RequestContextImpl") | ||
abstract class AkkaHttpRequestContext(request: HttpRequest, | ||
unmatchedPath: Uri.Path, | ||
executionContext: ExecutionContextExecutor, | ||
materializer: Materializer, | ||
log: LoggingAdapter, | ||
settings: RoutingSettings, | ||
parserSettings: ParserSettings) { | ||
|
||
def complete(trm: AkkaHttpToResponseMarshallable): Future[RouteResult] = { | ||
val contextWrapper = PathMatcherUtils.nrRequestContext.get() | ||
if (trm != null && contextWrapper != null) { | ||
trm.token = contextWrapper.token | ||
} | ||
Weaver.callOriginal() // This ends up calling complete on our NewRelicRequestContextWrapper | ||
} | ||
|
||
def reconfigure(executionContext: ExecutionContextExecutor, materializer: Materializer, log: LoggingAdapter, settings: RoutingSettings): RequestContext = { | ||
Weaver.callOriginal() | ||
} | ||
|
||
private def copy(request: HttpRequest, | ||
unmatchedPath: Uri.Path, | ||
executionContext: ExecutionContextExecutor, | ||
materializer: Materializer, | ||
log: LoggingAdapter, | ||
settings: RoutingSettings, | ||
parserSettings: ParserSettings): RequestContextImpl = { | ||
return new NewRelicRequestContextWrapper(this, Weaver.callOriginal(), null, new LinkedBlockingDeque[String](), | ||
new AtomicBoolean(false), new AtomicInteger(0), new AtomicInteger(0), new LinkedBlockingDeque[String], new mutable.HashSet[String], request, | ||
unmatchedPath, executionContext, materializer, log, settings, parserSettings) | ||
} | ||
} |
Oops, something went wrong.