Skip to content

Commit 4535088

Browse files
committed
introduce kamon-spring module
1 parent e7bbe7b commit 4535088

File tree

12 files changed

+224
-156
lines changed

12 files changed

+224
-156
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ language: scala
33
script:
44
- sbt +test
55
scala:
6-
- 2.12.5
6+
- 2.12.6
77
jdk:
88
- oraclejdk8
99
before_script:

build.sbt

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ val kamonTestkit = "io.kamon" %% "kamon-testkit"
2323
val springBootStarterWeb = "org.springframework.boot" % "spring-boot-starter-web" % "2.0.0.RELEASE" exclude("org.springframework.boot", "spring-boot-starter-tomcat")
2424
val springBootStarterTest = "org.springframework.boot" % "spring-boot-starter-test" % "2.0.0.RELEASE"
2525
val springStarterJetty = "org.springframework.boot" % "spring-boot-starter-jetty" % "2.0.0.RELEASE"
26-
val kamonServlet3 = "io.kamon" %% "kamon-servlet-3.x.x" % "0.1-e3428b1c8ba6f301749f955b5feb7126ac79bb1e"
26+
val kamonServlet3 = "io.kamon" %% "kamon-servlet-3.x.x" % "0.1-0c8024964581daaf872876044f8ec7c06b55159e"
2727
val servletApiV3 = "javax.servlet" % "javax.servlet-api" % "3.0.1"
2828

2929
val httpClient = "org.apache.httpcomponents" % "httpclient" % "4.5.5"
@@ -36,11 +36,10 @@ lazy val root = (project in file("."))
3636
.aggregate(kamonSpring, kamonSpringBench)
3737

3838
val commonSettings = Seq(
39-
scalaVersion := "2.12.5",
39+
scalaVersion := "2.12.6",
4040
resolvers += Resolver.mavenLocal,
41-
crossScalaVersions := Seq("2.12.5", "2.11.12", "2.10.7"),
41+
crossScalaVersions := Seq("2.12.6", "2.11.12", "2.10.7"),
4242
scalacOptions ++= Seq(
43-
// "-Ypartial-unification",
4443
"-language:higherKinds",
4544
"-language:postfixOps") ++ (CrossVersion.partialVersion(scalaVersion.value) match {
4645
case Some((2,10)) => Seq("-Yno-generic-signatures", "-target:jvm-1.7")

kamon-spring/src/main/resources/reference.conf

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,6 @@ kamon {
1616
enabled = true
1717
}
1818
}
19+
20+
servlet.tags.server-component = "spring-server"
1921
}

kamon-spring/src/main/scala/kamon/spring/Spring.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ object Spring {
2020
}
2121

2222
private def addHttpStatusCodeAsMetricTagFromConfig(config: Config): Boolean =
23-
Kamon.config.getBoolean("kamon.spring.add-http-status-code-as-metric-tag")
23+
config.getBoolean("kamon.spring.add-http-status-code-as-metric-tag")
2424

2525

2626
Kamon.onReconfigure(new OnReconfigureHook {

kamon-spring/src/test/scala/kamon/spring/AsyncHttpMetricsSpec.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ class AsyncHttpMetricsSpec extends WordSpec
8383

8484
"track the response time with status code 5xx" in {
8585
for(_ <- 1 to 100) yield get("/async/tracing/error")
86-
ResponseTimeMetrics().forStatusCode("5xx").distribution().max should be >= 10000000L
86+
ResponseTimeMetrics().forStatusCode("5xx").distribution().max should be >= 1000000L // 1 ms expressed in nanos
8787
}
8888
}
8989
}

kamon-spring/src/test/scala/kamon/spring/AsyncServerInstrumentationSpec.scala

Lines changed: 48 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,10 @@ package kamon.spring
1818

1919
import com.typesafe.config.ConfigFactory
2020
import kamon.Kamon
21+
import kamon.spring.client.HttpClientSupport
2122
import kamon.spring.webapp.AppSupport
2223
import kamon.trace.Span
2324
import kamon.trace.Span.TagValue
24-
import org.apache.http.client.methods.{CloseableHttpResponse, HttpGet}
25-
import org.apache.http.impl.client.HttpClients
2625
import org.scalatest.concurrent.Eventually
2726
import org.scalatest.{BeforeAndAfterAll, Matchers, OptionValues, WordSpec}
2827

@@ -34,7 +33,8 @@ class AsyncServerInstrumentationSpec extends WordSpec
3433
with Eventually
3534
with OptionValues
3635
with SpanReporter
37-
with AppSupport {
36+
with AppSupport
37+
with HttpClientSupport {
3838

3939
override protected def beforeAll(): Unit = {
4040
Kamon.reconfigure(ConfigFactory.load())
@@ -47,33 +47,21 @@ class AsyncServerInstrumentationSpec extends WordSpec
4747
stopApp()
4848
}
4949

50-
private val httpClient = HttpClients.createDefault()
51-
52-
private def get(path: String, headers: Seq[(String, String)] = Seq()): CloseableHttpResponse = {
53-
val request = new HttpGet(s"http://127.0.0.1:$port$path")
54-
headers.foreach { case (name, v) => request.addHeader(name, v) }
55-
httpClient.execute(request)
56-
}
57-
5850
"The Server instrumentation on Spring Boot with Async Servlet" should {
5951
"propagate the current context and respond to the ok action" in {
6052

6153
get("/async/tracing/ok").getStatusLine.getStatusCode shouldBe 200
6254

6355
eventually(timeout(3 seconds)) {
64-
6556
val span = reporter.nextSpan().value
6657
val spanTags = stringTag(span) _
6758

6859
span.operationName shouldBe "async.tracing.ok.get"
6960
spanTags("span.kind") shouldBe "server"
70-
spanTags("component") shouldBe "servlet.server"
61+
spanTags("component") shouldBe "spring-server"
7162
spanTags("http.method") shouldBe "GET"
7263
spanTags("http.url") shouldBe "/async/tracing/ok"
7364
span.tags("http.status_code") shouldBe TagValue.Number(200)
74-
75-
// span.from.until(span.to, ChronoUnit.MILLIS) shouldBe >= (servlet.durationOk.toLong)
76-
7765
}
7866
}
7967

@@ -87,12 +75,10 @@ class AsyncServerInstrumentationSpec extends WordSpec
8775

8876
span.operationName shouldBe "not-found"
8977
spanTags("span.kind") shouldBe "server"
90-
spanTags("component") shouldBe "servlet.server"
78+
spanTags("component") shouldBe "spring-server"
9179
spanTags("http.method") shouldBe "GET"
9280
spanTags("http.url") shouldBe "/async/tracing/not-found"
9381
span.tags("http.status_code") shouldBe TagValue.Number(404)
94-
95-
// span.from.until(span.to, ChronoUnit.MILLIS) shouldBe >= (servlet.durationNotFound.toLong)
9682
}
9783
}
9884

@@ -105,37 +91,72 @@ class AsyncServerInstrumentationSpec extends WordSpec
10591

10692
span.operationName shouldBe "async.tracing.error.get"
10793
spanTags("span.kind") shouldBe "server"
108-
spanTags("component") shouldBe "servlet.server"
94+
spanTags("component") shouldBe "spring-server"
10995
spanTags("http.method") shouldBe "GET"
11096
spanTags("http.url") shouldBe "/async/tracing/error"
11197
span.tags("error") shouldBe TagValue.True
11298
span.tags("http.status_code") shouldBe TagValue.Number(500)
113-
114-
// span.from.until(span.to, ChronoUnit.MILLIS) shouldBe >= (servlet.durationError.toLong)
11599
}
116100
}
117101

118102
"propagate the current context and respond to the error action produced with an internal exception" in {
119-
get("/async/tracing/unhandled-error").getStatusLine.getStatusCode shouldBe 500
103+
get("/async/tracing/exception").getStatusLine.getStatusCode shouldBe 500
120104

121105
eventually(timeout(3 seconds)) {
122106
val span = reporter.nextSpan().value
123107
val spanTags = stringTag(span) _
124108

125-
span.operationName shouldBe "async.tracing.unhandled-error.get"
109+
span.operationName shouldBe "async.tracing.exception.get"
126110
spanTags("span.kind") shouldBe "server"
127-
spanTags("component") shouldBe "servlet.server"
111+
spanTags("component") shouldBe "spring-server"
128112
spanTags("http.method") shouldBe "GET"
129-
spanTags("http.url") shouldBe "/async/tracing/unhandled-error"
113+
spanTags("http.url") shouldBe "/async/tracing/exception"
130114
span.tags("error") shouldBe TagValue.True
131115
span.tags("http.status_code") shouldBe TagValue.Number(500)
116+
}
117+
}
118+
119+
"resume the incoming context and respond to the ok endpoint" in {
120+
get("/async/tracing/ok", IncomingContext.headersB3).getStatusLine.getStatusCode shouldBe 200
121+
122+
eventually(timeout(3 seconds)) {
123+
124+
val span = reporter.nextSpan().value
125+
val spanTags = stringTag(span) _
126+
127+
span.operationName shouldBe "async.tracing.ok.get"
128+
spanTags("span.kind") shouldBe "server"
129+
spanTags("component") shouldBe "spring-server"
130+
spanTags("http.method") shouldBe "GET"
131+
spanTags("http.url") shouldBe "/async/tracing/ok"
132+
span.tags("http.status_code") shouldBe TagValue.Number(200)
132133

133-
// span.from.until(span.to, ChronoUnit.MILLIS) shouldBe >= (servlet.durationError.toLong)
134+
span.context.parentID.string shouldBe IncomingContext.SpanId
135+
span.context.traceID.string shouldBe IncomingContext.TraceId
134136
}
135137
}
136138
}
137139

138140
def stringTag(span: Span.FinishedSpan)(tag: String): String = {
139141
span.tags(tag).asInstanceOf[TagValue.String].string
140142
}
143+
144+
private object IncomingContext {
145+
import kamon.trace.SpanCodec.B3.{Headers => B3Headers}
146+
147+
val TraceId = "1234"
148+
val ParentSpanId = "2222"
149+
val SpanId = "4321"
150+
val Sampled = "1"
151+
val Flags = "some=baggage;more=baggage;other=baggage2"
152+
153+
154+
val headersB3 = Seq(
155+
(B3Headers.TraceIdentifier, TraceId),
156+
(B3Headers.ParentSpanIdentifier, ParentSpanId),
157+
(B3Headers.SpanIdentifier, SpanId),
158+
(B3Headers.Sampled, Sampled),
159+
(B3Headers.Flags, Flags))
160+
161+
}
141162
}

kamon-spring/src/test/scala/kamon/spring/ServerInstrumentationSpec.scala

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,13 @@
1616

1717
package kamon.spring
1818

19+
import java.time.temporal.ChronoUnit
20+
1921
import com.typesafe.config.ConfigFactory
2022
import kamon.Kamon
2123
import kamon.spring.client.HttpClientSupport
2224
import kamon.spring.webapp.AppSupport
25+
import kamon.spring.webapp.controller.SyncTracingController
2326
import kamon.trace.Span
2427
import kamon.trace.Span.TagValue
2528
import org.scalatest.concurrent.Eventually
@@ -48,7 +51,7 @@ class ServerInstrumentationSpec extends WordSpec
4851
}
4952

5053
"The Server instrumentation on Sync Spring Boot" should {
51-
"propagate the current context and respond to the ok action" in {
54+
"propagate the current context and respond to the ok endpoint" in {
5255

5356
get("/sync/tracing/ok").getStatusLine.getStatusCode shouldBe 200
5457

@@ -59,7 +62,7 @@ class ServerInstrumentationSpec extends WordSpec
5962

6063
span.operationName shouldBe "sync.tracing.ok.get"
6164
spanTags("span.kind") shouldBe "server"
62-
spanTags("component") shouldBe "servlet.server"
65+
spanTags("component") shouldBe "spring-server"
6366
spanTags("http.method") shouldBe "GET"
6467
spanTags("http.url") shouldBe "/sync/tracing/ok"
6568
span.tags("http.status_code") shouldBe TagValue.Number(200)
@@ -68,7 +71,7 @@ class ServerInstrumentationSpec extends WordSpec
6871
}
6972
}
7073

71-
"propagate the current context and respond to the not-found action" in {
74+
"propagate the current context and respond to the not-found endpoint" in {
7275

7376
get("/sync/tracing/not-found").getStatusLine.getStatusCode shouldBe 404
7477

@@ -78,7 +81,7 @@ class ServerInstrumentationSpec extends WordSpec
7881

7982
span.operationName shouldBe "not-found"
8083
spanTags("span.kind") shouldBe "server"
81-
spanTags("component") shouldBe "servlet.server"
84+
spanTags("component") shouldBe "spring-server"
8285
spanTags("http.method") shouldBe "GET"
8386
spanTags("http.url") shouldBe "/sync/tracing/not-found"
8487
span.tags("http.status_code") shouldBe TagValue.Number(404)
@@ -87,7 +90,7 @@ class ServerInstrumentationSpec extends WordSpec
8790
}
8891
}
8992

90-
"propagate the current context and respond to the error action" in {
93+
"propagate the current context and respond to the error endpoint" in {
9194
get("/sync/tracing/error").getStatusLine.getStatusCode shouldBe 500
9295

9396
eventually(timeout(3 seconds)) {
@@ -96,7 +99,7 @@ class ServerInstrumentationSpec extends WordSpec
9699

97100
span.operationName shouldBe "sync.tracing.error.get"
98101
spanTags("span.kind") shouldBe "server"
99-
spanTags("component") shouldBe "servlet.server"
102+
spanTags("component") shouldBe "spring-server"
100103
spanTags("http.method") shouldBe "GET"
101104
spanTags("http.url") shouldBe "/sync/tracing/error"
102105
span.tags("error") shouldBe TagValue.True
@@ -106,26 +109,45 @@ class ServerInstrumentationSpec extends WordSpec
106109
}
107110
}
108111

109-
"propagate the current context and respond to the error action produced with an internal exception" in {
110-
get("/sync/tracing/unhandled-error").getStatusLine.getStatusCode shouldBe 500
112+
"propagate the current context and respond to the exception endpoint produced with abnormal termination" in {
113+
get("/sync/tracing/exception").getStatusLine.getStatusCode shouldBe 200
111114

112115
eventually(timeout(3 seconds)) {
113116
val span = reporter.nextSpan().value
114117
val spanTags = stringTag(span) _
115118

116-
span.operationName shouldBe "sync.tracing.unhandled-error.get"
119+
span.operationName shouldBe "sync.tracing.exception.get"
117120
spanTags("span.kind") shouldBe "server"
118-
spanTags("component") shouldBe "servlet.server"
121+
spanTags("component") shouldBe "spring-server"
119122
spanTags("http.method") shouldBe "GET"
120-
spanTags("http.url") shouldBe "/sync/tracing/unhandled-error"
123+
spanTags("http.url") shouldBe "/sync/tracing/exception"
121124
span.tags("error") shouldBe TagValue.True
122125
span.tags("http.status_code") shouldBe TagValue.Number(500)
126+
}
127+
}
128+
"propagate the current context and respond to the slowly endpoint" in {
129+
130+
get("/sync/tracing/slowly").getStatusLine.getStatusCode shouldBe 200
131+
132+
eventually(timeout(3 seconds)) {
133+
134+
val span = reporter.nextSpan().value
135+
val spanTags = stringTag(span) _
136+
137+
span.operationName shouldBe "sync.tracing.slowly.get"
138+
spanTags("span.kind") shouldBe "server"
139+
spanTags("component") shouldBe "spring-server"
140+
spanTags("http.method") shouldBe "GET"
141+
spanTags("http.url") shouldBe "/sync/tracing/slowly"
142+
span.tags("http.status_code") shouldBe TagValue.Number(200)
143+
144+
span.context.parentID.string shouldBe ""
123145

124-
// span.from.until(span.to, ChronoUnit.MILLIS) shouldBe >= (servlet.durationError.toLong)
146+
span.from.until(span.to, ChronoUnit.MILLIS) shouldBe >= (SyncTracingController.slowlyServiceDuration.toMillis)
125147
}
126148
}
127149

128-
"resume the incoming context and respond to the ok action" in {
150+
"resume the incoming context and respond to the ok endpoint" in {
129151
get("/sync/tracing/ok", IncomingContext.headersB3).getStatusLine.getStatusCode shouldBe 200
130152

131153
eventually(timeout(3 seconds)) {
@@ -135,7 +157,7 @@ class ServerInstrumentationSpec extends WordSpec
135157

136158
span.operationName shouldBe "sync.tracing.ok.get"
137159
spanTags("span.kind") shouldBe "server"
138-
spanTags("component") shouldBe "servlet.server"
160+
spanTags("component") shouldBe "spring-server"
139161
spanTags("http.method") shouldBe "GET"
140162
spanTags("http.url") shouldBe "/sync/tracing/ok"
141163
span.tags("http.status_code") shouldBe TagValue.Number(200)
@@ -150,7 +172,7 @@ class ServerInstrumentationSpec extends WordSpec
150172
span.tags(tag).asInstanceOf[TagValue.String].string
151173
}
152174

153-
object IncomingContext {
175+
private object IncomingContext {
154176
import kamon.trace.SpanCodec.B3.{Headers => B3Headers}
155177

156178
val TraceId = "1234"

0 commit comments

Comments
 (0)