-
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 #362 from GDownes/sttp-client-instrumentation
STTP 2 & 3 Scala HTTP Client Instrumentation
- Loading branch information
Showing
82 changed files
with
2,788 additions
and
0 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
apply plugin: 'scala' | ||
|
||
dependencies { | ||
implementation(project(":newrelic-api")) | ||
implementation(project(":agent-bridge")) | ||
implementation(project(":newrelic-weaver-api")) | ||
implementation(project(":newrelic-weaver-scala-api")) | ||
implementation("org.scala-lang:scala-library:2.12.14") | ||
implementation("com.softwaremill.sttp.client:core_2.12:2.2.3") | ||
} | ||
|
||
jar { | ||
manifest { attributes 'Implementation-Title': 'com.newrelic.instrumentation.sttp-2.12_2.2.3', 'Implementation-Title-Alias': 'sttp_instrumentation' } | ||
} | ||
|
||
verifyInstrumentation { | ||
passes 'com.softwaremill.sttp.client:core_2.12:[2.2.3,)' | ||
excludeRegex ".*(RC|M)[0-9]*" | ||
} | ||
|
||
test { | ||
onlyIf { | ||
!project.hasProperty('test7') | ||
} | ||
} | ||
|
||
site { | ||
title 'Scala' | ||
type 'Other' | ||
} |
31 changes: 31 additions & 0 deletions
31
...n/sttp-2.12_2.2.3/src/main/scala/com/nr/agent/instrumentation/sttp/DelegateIdentity.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,31 @@ | ||
/* | ||
* | ||
* * Copyright 2020 New Relic Corporation. All rights reserved. | ||
* * SPDX-License-Identifier: Apache-2.0 | ||
* | ||
*/ | ||
|
||
package com.nr.agent.instrumentation.sttp | ||
|
||
import com.nr.agent.instrumentation.sttp.SttpUtils.{finishSegment, startSegment} | ||
import sttp.client.monad.MonadError | ||
import sttp.client.ws.WebSocketResponse | ||
import sttp.client.{FollowRedirectsBackend, Identity, NothingT, Request, Response, SttpBackend} | ||
|
||
class DelegateIdentity(delegate: FollowRedirectsBackend[Identity, Any, Any]) extends SttpBackend[Identity, Nothing, NothingT] { | ||
override def send[T](request: Request[T, Nothing]): Identity[Response[T]] = { | ||
val segment = startSegment(request) | ||
|
||
val response = delegate.send(request) | ||
|
||
finishSegment(request, segment, response) | ||
|
||
response | ||
} | ||
|
||
override def openWebsocket[T, WS_RESULT](request: Request[T, Nothing], handler: NothingT[WS_RESULT]): Identity[WebSocketResponse[WS_RESULT]] = delegate.openWebsocket(request, handler) | ||
|
||
override def close(): Identity[Unit] = delegate.close() | ||
|
||
override def responseMonad: MonadError[Identity] = delegate.responseMonad | ||
} |
22 changes: 22 additions & 0 deletions
22
...sttp-2.12_2.2.3/src/main/scala/com/nr/agent/instrumentation/sttp/InboundHttpHeaders.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,22 @@ | ||
/* | ||
* | ||
* * Copyright 2020 New Relic Corporation. All rights reserved. | ||
* * SPDX-License-Identifier: Apache-2.0 | ||
* | ||
*/ | ||
|
||
package com.nr.agent.instrumentation.sttp | ||
|
||
import com.newrelic.api.agent.{ExtendedInboundHeaders, HeaderType} | ||
import sttp.client.Response | ||
import collection.JavaConverters._ | ||
|
||
import java.util | ||
|
||
class InboundHttpHeaders[T](response: Response[T]) extends ExtendedInboundHeaders { | ||
override def getHeader(name: String): String = response.header(name).orNull | ||
|
||
override def getHeaders(name: String): util.List[String] = response.headers.map(x => x.name).toList.asJava | ||
|
||
override def getHeaderType: HeaderType = HeaderType.HTTP | ||
} |
21 changes: 21 additions & 0 deletions
21
...ttp-2.12_2.2.3/src/main/scala/com/nr/agent/instrumentation/sttp/OutboundHttpHeaders.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,21 @@ | ||
/* | ||
* | ||
* * Copyright 2020 New Relic Corporation. All rights reserved. | ||
* * SPDX-License-Identifier: Apache-2.0 | ||
* | ||
*/ | ||
|
||
package com.nr.agent.instrumentation.sttp | ||
|
||
import com.newrelic.api.agent.{HeaderType, OutboundHeaders} | ||
import sttp.client.Request | ||
|
||
class OutboundHttpHeaders[T, S](val request: Request[T, S]) extends OutboundHeaders { | ||
override def getHeaderType = HeaderType.HTTP | ||
|
||
/** | ||
* Sets a response header with the given name and value. | ||
* NO-OP Sttp Request Headers are immutable and so can't be set from here | ||
*/ | ||
override def setHeader(name: String, value: String): Unit = request.header(name, value) | ||
} |
32 changes: 32 additions & 0 deletions
32
...entation/sttp-2.12_2.2.3/src/main/scala/com/nr/agent/instrumentation/sttp/SttpUtils.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,32 @@ | ||
/* | ||
* | ||
* * Copyright 2020 New Relic Corporation. All rights reserved. | ||
* * SPDX-License-Identifier: Apache-2.0 | ||
* | ||
*/ | ||
|
||
package com.nr.agent.instrumentation.sttp | ||
|
||
import com.newrelic.api.agent.{HttpParameters, NewRelic, Segment, TransactionNamePriority} | ||
import sttp.client.{Request, Response} | ||
|
||
import java.net.URI | ||
|
||
object SttpUtils { | ||
|
||
def startSegment[R, T](request: Request[T, R]): Segment = { | ||
val segment = NewRelic.getAgent.getTransaction.startSegment("SttpBackend", "send") | ||
segment.addOutboundRequestHeaders(new OutboundHttpHeaders(request)) | ||
segment | ||
} | ||
|
||
def finishSegment[R, T](request: Request[T, R], segment: Segment, response: Response[T]): Unit = { | ||
segment.reportAsExternal(HttpParameters | ||
.library("Sttp") | ||
.uri(new URI(request.uri.toString())) | ||
.procedure(request.method.method) | ||
.inboundHeaders(new InboundHttpHeaders(response)) | ||
.build()) | ||
segment.end() | ||
} | ||
} |
26 changes: 26 additions & 0 deletions
26
...sttp-2.12_2.2.3/src/main/scala/sttp/client/HttpURLConnectionBackend_Instrumentation.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,26 @@ | ||
/* | ||
* | ||
* * Copyright 2020 New Relic Corporation. All rights reserved. | ||
* * SPDX-License-Identifier: Apache-2.0 | ||
* | ||
*/ | ||
|
||
package sttp.client | ||
|
||
import com.newrelic.api.agent.weaver.Weaver | ||
import com.newrelic.api.agent.weaver.scala.{ScalaMatchType, ScalaWeave} | ||
import com.nr.agent.instrumentation.sttp.DelegateIdentity | ||
import sttp.client.HttpURLConnectionBackend.EncodingHandler | ||
|
||
import java.net.{HttpURLConnection, URL, URLConnection} | ||
|
||
@ScalaWeave(`type` = ScalaMatchType.Object, `originalName` = "sttp.client.HttpURLConnectionBackend") | ||
class HttpURLConnectionBackend_Instrumentation { | ||
def apply( | ||
options: SttpBackendOptions, | ||
customizeConnection: HttpURLConnection => Unit, | ||
createURL: String => URL, | ||
openConnection: (URL, Option[java.net.Proxy]) => URLConnection, | ||
customEncodingHandler: EncodingHandler | ||
): SttpBackend[Identity, Nothing, NothingT] = new DelegateIdentity(Weaver.callOriginal()) | ||
} |
48 changes: 48 additions & 0 deletions
48
....3/src/test/scala/com/nr/agent/instrumentation/sttp/BackendRequestNoInstrumentation.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,48 @@ | ||
/* | ||
* | ||
* * Copyright 2021 New Relic Corporation. All rights reserved. | ||
* * SPDX-License-Identifier: Apache-2.0 | ||
* | ||
*/ | ||
|
||
package com.nr.agent.instrumentation.sttp | ||
|
||
import com.newrelic.agent.introspec.internal.HttpServerRule | ||
import com.newrelic.agent.introspec.{InstrumentationTestConfig, InstrumentationTestRunner, Introspector} | ||
import com.nr.agent.instrumentation.sttp.SttpTestUtils.{getSegments, getTraces, makeRequest} | ||
import org.junit.runner.RunWith | ||
import org.junit.{Assert, Rule, Test} | ||
import sttp.client.{HttpURLConnectionBackend, _} | ||
|
||
import java.util.concurrent.TimeUnit | ||
|
||
@RunWith(classOf[InstrumentationTestRunner]) | ||
@InstrumentationTestConfig(includePrefixes = Array("none")) | ||
class BackendRequestNoInstrumentation { | ||
|
||
val _server = new HttpServerRule() | ||
|
||
@Rule | ||
implicit def server: HttpServerRule = _server | ||
|
||
@Test | ||
def httpURLConnectionBackend(): Unit = { | ||
//Given | ||
implicit val introspector: Introspector = InstrumentationTestRunner.getIntrospector | ||
implicit val backend: SttpBackend[Identity, Nothing, NothingT] = HttpURLConnectionBackend() | ||
|
||
//When | ||
val response = makeRequest | ||
|
||
//Then | ||
introspector.getFinishedTransactionCount(TimeUnit.SECONDS.toMillis(10)) | ||
|
||
val traces = getTraces() | ||
val segments = getSegments(traces) | ||
|
||
Assert.assertTrue("Successful response", response.code.isSuccess) | ||
Assert.assertEquals("Transactions", 1, introspector.getTransactionNames.size) | ||
Assert.assertEquals("Traces", 1, traces.size) | ||
Assert.assertEquals("Segments", 1, segments.size) | ||
} | ||
} |
48 changes: 48 additions & 0 deletions
48
.../src/test/scala/com/nr/agent/instrumentation/sttp/BackendRequestSttpInstrumentation.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,48 @@ | ||
/* | ||
* | ||
* * Copyright 2021 New Relic Corporation. All rights reserved. | ||
* * SPDX-License-Identifier: Apache-2.0 | ||
* | ||
*/ | ||
|
||
package com.nr.agent.instrumentation.sttp | ||
|
||
import com.newrelic.agent.introspec.internal.HttpServerRule | ||
import com.newrelic.agent.introspec.{InstrumentationTestConfig, InstrumentationTestRunner, Introspector} | ||
import com.nr.agent.instrumentation.sttp.SttpTestUtils.{getSegments, getTraces, makeRequest} | ||
import org.junit.runner.RunWith | ||
import org.junit.{Assert, Rule, Test} | ||
import sttp.client.{HttpURLConnectionBackend, _} | ||
|
||
import java.util.concurrent.TimeUnit | ||
|
||
@RunWith(classOf[InstrumentationTestRunner]) | ||
@InstrumentationTestConfig(includePrefixes = Array("sttp")) | ||
class BackendRequestSttpInstrumentation { | ||
|
||
val _server = new HttpServerRule() | ||
|
||
@Rule | ||
implicit def server: HttpServerRule = _server | ||
|
||
@Test | ||
def httpURLConnectionBackend(): Unit = { | ||
//Given | ||
implicit val introspector: Introspector = InstrumentationTestRunner.getIntrospector | ||
implicit val backend: SttpBackend[Identity, Nothing, NothingT] = HttpURLConnectionBackend() | ||
|
||
//When | ||
val response = makeRequest | ||
|
||
//Then | ||
introspector.getFinishedTransactionCount(TimeUnit.SECONDS.toMillis(10)) | ||
|
||
val traces = getTraces() | ||
val segments = getSegments(traces) | ||
|
||
Assert.assertTrue("Successful response", response.code.isSuccess) | ||
Assert.assertEquals("Transactions", 1, introspector.getTransactionNames.size) | ||
Assert.assertEquals("Traces", 1, traces.size) | ||
Assert.assertEquals("Segments", 2, segments.size) | ||
} | ||
} |
35 changes: 35 additions & 0 deletions
35
...tion/sttp-2.12_2.2.3/src/test/scala/com/nr/agent/instrumentation/sttp/SttpTestUtils.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,35 @@ | ||
/* | ||
* | ||
* * Copyright 2020 New Relic Corporation. All rights reserved. | ||
* * SPDX-License-Identifier: Apache-2.0 | ||
* | ||
*/ | ||
|
||
package com.nr.agent.instrumentation.sttp | ||
|
||
import com.newrelic.agent.introspec.internal.HttpServerRule | ||
import com.newrelic.agent.introspec.{Introspector, TraceSegment, TransactionTrace} | ||
import com.newrelic.api.agent.Trace | ||
import sttp.client.{NothingT, Response, SttpBackend, UriContext, basicRequest} | ||
|
||
import collection.JavaConverters._ | ||
import scala.language.higherKinds | ||
|
||
object SttpTestUtils { | ||
|
||
@Trace(dispatcher = true) | ||
def makeRequest[F[_]](implicit backend: SttpBackend[F, Nothing, NothingT], server: HttpServerRule): F[Response[Either[String, String]]] = { | ||
basicRequest.get(uri"${server.getEndPoint}?no-transaction=1").send() | ||
} | ||
|
||
def getTraces()(implicit introspector: Introspector): Iterable[TransactionTrace] = | ||
introspector.getTransactionNames.asScala.flatMap(transactionName => introspector.getTransactionTracesForTransaction(transactionName).asScala) | ||
|
||
def getSegments(traces : Iterable[TransactionTrace]): Iterable[TraceSegment] = | ||
traces.flatMap(trace => this.getSegments(trace.getInitialTraceSegment)) | ||
|
||
private def getSegments(segment: TraceSegment): List[TraceSegment] = { | ||
val childSegments = segment.getChildren.asScala.flatMap(childSegment => getSegments(childSegment)).toList | ||
segment :: childSegments | ||
} | ||
} |
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,31 @@ | ||
apply plugin: 'scala' | ||
|
||
dependencies { | ||
implementation(project(":newrelic-api")) | ||
implementation(project(":agent-bridge")) | ||
implementation(project(":newrelic-weaver-api")) | ||
implementation(project(":newrelic-weaver-scala-api")) | ||
implementation("org.scala-lang:scala-library:2.13.5") | ||
implementation("com.softwaremill.sttp.client:core_2.13:2.2.3") | ||
} | ||
|
||
jar { | ||
manifest { attributes 'Implementation-Title': 'com.newrelic.instrumentation.sttp-2.13_2.2.3', 'Implementation-Title-Alias': 'sttp_instrumentation' } | ||
} | ||
|
||
verifyInstrumentation { | ||
passes 'com.softwaremill.sttp.client:core_2.13:[2.2.3,)' | ||
passes 'com.softwaremill.sttp.client:core_3:[2.2.3,)' | ||
excludeRegex ".*(RC|M)[0-9]*" | ||
} | ||
|
||
test { | ||
onlyIf { | ||
!project.hasProperty('test7') | ||
} | ||
} | ||
|
||
site { | ||
title 'Scala' | ||
type 'Other' | ||
} |
31 changes: 31 additions & 0 deletions
31
...n/sttp-2.13_2.2.3/src/main/scala/com/nr/agent/instrumentation/sttp/DelegateIdentity.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,31 @@ | ||
/* | ||
* | ||
* * Copyright 2020 New Relic Corporation. All rights reserved. | ||
* * SPDX-License-Identifier: Apache-2.0 | ||
* | ||
*/ | ||
|
||
package com.nr.agent.instrumentation.sttp | ||
|
||
import com.nr.agent.instrumentation.sttp.SttpUtils.{finishSegment, startSegment} | ||
import sttp.client.monad.MonadError | ||
import sttp.client.ws.WebSocketResponse | ||
import sttp.client.{FollowRedirectsBackend, Identity, NothingT, Request, Response, SttpBackend} | ||
|
||
class DelegateIdentity(delegate: FollowRedirectsBackend[Identity, Any, Any]) extends SttpBackend[Identity, Nothing, NothingT] { | ||
override def send[T](request: Request[T, Nothing]): Identity[Response[T]] = { | ||
val segment = startSegment(request) | ||
|
||
val response = delegate.send(request) | ||
|
||
finishSegment(request, segment, response) | ||
|
||
response | ||
} | ||
|
||
override def openWebsocket[T, WS_RESULT](request: Request[T, Nothing], handler: NothingT[WS_RESULT]): Identity[WebSocketResponse[WS_RESULT]] = delegate.openWebsocket(request, handler) | ||
|
||
override def close(): Identity[Unit] = delegate.close() | ||
|
||
override def responseMonad: MonadError[Identity] = delegate.responseMonad | ||
} |
22 changes: 22 additions & 0 deletions
22
...sttp-2.13_2.2.3/src/main/scala/com/nr/agent/instrumentation/sttp/InboundHttpHeaders.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,22 @@ | ||
/* | ||
* | ||
* * Copyright 2020 New Relic Corporation. All rights reserved. | ||
* * SPDX-License-Identifier: Apache-2.0 | ||
* | ||
*/ | ||
|
||
package com.nr.agent.instrumentation.sttp | ||
|
||
import com.newrelic.api.agent.{ExtendedInboundHeaders, HeaderType} | ||
import sttp.client.Response | ||
import collection.JavaConverters._ | ||
|
||
import java.util | ||
|
||
class InboundHttpHeaders[T](response: Response[T]) extends ExtendedInboundHeaders { | ||
override def getHeader(name: String): String = response.header(name).orNull | ||
|
||
override def getHeaders(name: String): util.List[String] = response.headers.map(x => x.name).toList.asJava | ||
|
||
override def getHeaderType: HeaderType = HeaderType.HTTP | ||
} |
Oops, something went wrong.