Skip to content

Commit d3473fd

Browse files
committed
+ kamon-armeria module [WIP]
1 parent e357bac commit d3473fd

19 files changed

+1487
-1
lines changed

build.sbt

+18-1
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ lazy val instrumentation = (project in file("instrumentation"))
129129
`kamon-akka-http`,
130130
`kamon-play`,
131131
`kamon-okhttp`,
132+
`kamon-armeria`
132133
)
133134

134135

@@ -423,6 +424,21 @@ lazy val `kamon-okhttp` = (project in file("instrumentation/kamon-okhttp"))
423424
).dependsOn(`kamon-core`, `kamon-executors`, `kamon-testkit` % "test")
424425

425426

427+
lazy val `kamon-armeria` = (project in file("instrumentation/kamon-armeria"))
428+
.disablePlugins(AssemblyPlugin)
429+
.enablePlugins(JavaAgent)
430+
.settings(instrumentationSettings)
431+
.settings(
432+
libraryDependencies ++= Seq(
433+
kanelaAgent % "provided",
434+
"com.linecorp.armeria" % "armeria" % "1.0.0" % "provided",
435+
436+
scalatest % "test",
437+
okHttp % "test",
438+
logbackClassic % "test"
439+
)
440+
).dependsOn(`kamon-instrumentation-common`, `kamon-testkit` % "test")
441+
426442
/**
427443
* Reporters
428444
*/
@@ -637,4 +653,5 @@ val `kamon-bundle` = (project in file("bundle/kamon-bundle"))
637653
`kamon-akka-http` % "shaded",
638654
`kamon-play` % "shaded",
639655
`kamon-okhttp` % "shaded",
640-
)
656+
`kamon-armeria` % "shaded"
657+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
# =================================== #
2+
# kamon-armeria reference configuration #
3+
# =================================== #
4+
5+
6+
kamon.instrumentation.armeria {
7+
8+
# Settings to control the HTTP Server instrumentation.
9+
#
10+
# IMPORTANT: Besides the "initial-operation-name" and "unhandled-operation-name" settings, the entire configuration of
11+
# the HTTP Server Instrumentation is based on the constructs provided by the Kamon Instrumentation Common library
12+
# which will always fallback to the settings found under the "kamon.instrumentation.http-server.default" path. The
13+
# default settings have been included here to make them easy to find and understand in the context of this project and
14+
# commented out so that any changes to the default settings will actually have effect.
15+
#
16+
http-server {
17+
18+
#
19+
# Configuration for HTTP context propagation.
20+
#
21+
propagation {
22+
23+
# Enables or disables HTTP context propagation on this HTTP server instrumentation. Please note that if
24+
# propagation is disabled then some distributed tracing features will not be work as expected (e.g. Spans can
25+
# be created and reported but will not be linked across boundaries nor take trace identifiers from tags).
26+
#enabled = yes
27+
28+
# HTTP propagation channel to b used by this instrumentation. Take a look at the kamon.propagation.http.default
29+
# configuration for more details on how to configure the detault HTTP context propagation.
30+
channel = "default"
31+
32+
33+
}
34+
35+
36+
#
37+
# Configuration for HTTP server metrics collection.
38+
#
39+
metrics {
40+
41+
# Enables collection of HTTP server metrics. When enabled the following metrics will be collected, assuming
42+
# that the instrumentation is fully compliant:
43+
#
44+
# - http.server.requets
45+
# - http.server.request.active
46+
# - http.server.request.size
47+
# - http.server.response.size
48+
# - http.server.connection.lifetime
49+
# - http.server.connection.usage
50+
# - http.server.connection.open
51+
#
52+
# All metrics have at least three tags: component, interface and port. Additionally, the http.server.requests
53+
# metric will also have a status_code tag with the status code group (1xx, 2xx and so on).
54+
#
55+
#enabled = yes
56+
}
57+
58+
59+
#
60+
# Configuration for HTTP request tracing.
61+
#
62+
tracing {
63+
64+
# Enables HTTP request tracing. When enabled the instrumentation will create Spans for incoming requests
65+
# and finish them when the response is sent back to the clients.
66+
#enabled = yes
67+
68+
# Select a context tag that provides a preferred trace identifier. The preferred trace identifier will be used
69+
# only if all these conditions are met:
70+
# - the context tag is present.
71+
# - there is no parent Span on the incoming context (i.e. this is the first service on the trace).
72+
# - the identifier is valid in accordance to the identity provider.
73+
#preferred-trace-id-tag = "none"
74+
75+
# Enables collection of span metrics using the `span.processing-time` metric.
76+
#span-metrics = on
77+
78+
# Select which tags should be included as span and span metric tags. The possible options are:
79+
# - span: the tag is added as a Span tag (i.e. using span.tag(...))
80+
# - metric: the tag is added a a Span metric tag (i.e. using span.tagMetric(...))
81+
# - off: the tag is not used.
82+
#
83+
tags {
84+
85+
# Use the http.url tag.
86+
#url = span
87+
88+
# Use the http.method tag.
89+
#method = metric
90+
91+
# Use the http.status_code tag.
92+
#status-code = metric
93+
94+
# Copy tags from the context into the Spans with the specified purpouse. For example, to copy a customer_type
95+
# tag from the context into the HTTP Server Span crekamon.trace.sampler = alwaysated by the instrumentation, the following configuration
96+
# should be added:
97+
#
98+
# from-context {
99+
# customer_type = span
100+
# }
101+
#
102+
from-context {
103+
104+
}
105+
}
106+
107+
# Controls writing trace and span identifiers to HTTP response headers sent by the instrumented servers. The
108+
# configuration can be set to either "none" to disable writing the identifiers on the response headers or to
109+
# the header name to be used when writing the identifiers.
110+
response-headers {
111+
112+
# HTTP response header name for the trace identifier, or "none" to disable it.
113+
#trace-id = "trace-id"
114+
115+
# HTTP response header name for the server span identifier, or "none" to disable it.
116+
#span-id = none
117+
}
118+
119+
# Custom mappings between routes and operation names.
120+
operations {
121+
122+
# The default operation name to be used when creating Spans to handle the HTTP server requests. In most
123+
# cases it is not possible to define an operation name right at the moment of starting the HTTP server Span
124+
# and in those cases, this operation name will be initially assigned to the Span. Instrumentation authors
125+
# should do their best effort to provide a suitable operation name or make use of the "mappings" facilities.
126+
default = "http.server.request"
127+
128+
# The operation name to be assigned when an application cannot find any route/endpoint/controller to handle
129+
# a given request. Depending on the instrumented framework, it might be possible to apply this operation
130+
# name automatically or not, check the frameworks' instrumentation docs for more details.
131+
unhandled = "unhandled"
132+
133+
# FQCN for a HttpOperationNameGenerator implementation, or ony of the following shorthand forms:
134+
# - default: Uses the set default operation name
135+
# - method: Uses the request HTTP method as the operation name.
136+
#
137+
name-generator = "kamon.armeria.instrumentation.server.KamonArmeriaOperationNameGenerator"
138+
139+
# Provides custom mappings from HTTP paths into operation names. Meant to be used in cases where the bytecode
140+
# instrumentation is not able to provide a sensible operation name that is free of high cardinality values.
141+
# For example, with the following configuration:
142+
# mappings {
143+
# "/organization/*/user/*/profile" = "/organization/:orgID/user/:userID/profile"
144+
# "/events/*/rsvps" = "EventRSVPs"
145+
# }
146+
#
147+
# Requests to "/organization/3651/user/39652/profile" and "/organization/22234/user/54543/profile" will have
148+
# the same operation name "/organization/:orgID/user/:userID/profile".
149+
#
150+
# Similarly, requests to "/events/aaa-bb-ccc/rsvps" and "/events/1234/rsvps" will have the same operation
151+
# name "EventRSVPs".
152+
#
153+
# The patterns are expressed as globs and the operation names are free form.
154+
#
155+
mappings {
156+
157+
}
158+
}
159+
}
160+
}
161+
162+
# Settings to control the HTTP Client instrumentation
163+
#
164+
# IMPORTANT: The entire configuration of the HTTP Client Instrumentation is based on the constructs provided by the
165+
# Kamon Instrumentation Common library which will always fallback to the settings found under the
166+
# "kamon.instrumentation.http-client.default" path. The default settings have been included here to make them easy to
167+
# find and understand in the context of this project and commented out so that any changes to the default settings
168+
# will actually have effect.
169+
#
170+
http-client {
171+
#
172+
# Configuration for HTTP context propagation.
173+
#
174+
propagation {
175+
176+
# Enables or disables HTTP context propagation on this HTTP server instrumentation. Please note that if
177+
# propagation is disabled then some distributed tracing features will not be work as expected (e.g. Spans can
178+
# be created and reported but will not be linked across boundaries nor take trace identifiers from tags).
179+
enabled = yes
180+
181+
# HTTP propagation channel to b used by this instrumentation. Take a look at the kamon.propagation.http.default
182+
# configuration for more details on how to configure the detault HTTP context propagation.
183+
channel = "default"
184+
}
185+
186+
tracing {
187+
188+
# Enables HTTP request tracing. When enabled the instrumentation will create Spans for outgoing requests
189+
# and finish them when the response is received from the server.
190+
enabled = yes
191+
192+
# Enables collection of span metrics using the `span.processing-time` metric.
193+
span-metrics = on
194+
195+
# Select which tags should be included as span and span metric tags. The possible options are:
196+
# - span: the tag is added as a Span tag (i.e. using span.tag(...))
197+
# - metric: the tag is added a a Span metric tag (i.e. using span.tagMetric(...))
198+
# - off: the tag is not used.
199+
#
200+
tags {
201+
202+
# Use the http.url tag.
203+
url = span
204+
205+
# Use the http.method tag.
206+
method = metric
207+
208+
# Use the http.status_code tag.
209+
status-code = metric
210+
211+
# Copy tags from the context into the Spans with the specified purpouse. For example, to copy a customer_type
212+
# tag from the context into the HTTP Server Span created by the instrumentation, the following configuration
213+
# should be added:
214+
#
215+
# from-context {
216+
# customer_type = span
217+
# }
218+
#
219+
from-context {
220+
221+
}
222+
}
223+
224+
operations {
225+
226+
# The default operation name to be used when creating Spans to handle the HTTP client requests. The HTTP
227+
# Client instrumentation will always try to use the HTTP Operation Name Generator configured bellow to get
228+
# a name, but if it fails to generate it then this name will be used.
229+
default = "http.client.request"
230+
231+
# FQCN for a HttpOperationNameGenerator implementation, or ony of the following shorthand forms:
232+
# - hostname: Uses the request Host as the operation name.
233+
# - method: Uses the request HTTP method as the operation name.
234+
#
235+
name-generator = "kamon.armeria.instrumentation.client.KamonArmeriaOperationNameGenerator"
236+
}
237+
}
238+
}
239+
}
240+
241+
kanela {
242+
show-banner = false
243+
modules {
244+
armeria-http-server {
245+
name = "Armeria http server Instrumentation"
246+
stoppable = true
247+
instrumentations = [
248+
"kamon.armeria.instrumentation.server.ArmeriaHttpServerInstrumentation"
249+
]
250+
within = [ "io.netty..*", "com.linecorp.armeria..*"]
251+
}
252+
armeria-http-client {
253+
name = "Armeria http client Instrumentation"
254+
stoppable = true
255+
instrumentations = [
256+
"kamon.armeria.instrumentation.client.ArmeriaHttpClientInstrumentation"
257+
]
258+
within = [ "com.linecorp.armeria.client..*"]
259+
}
260+
}
261+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/* =========================================================================================
2+
* Copyright © 2013-2020 the kamon project <http://kamon.io/>
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License") you may not use this file
5+
* except in compliance with the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the
10+
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
11+
* either express or implied. See the License for the specific language governing permissions
12+
* and limitations under the License.
13+
* =========================================================================================
14+
*/
15+
16+
package kamon.armeria.instrumentation
17+
18+
import kamon.instrumentation.http.HttpMessage.Request
19+
import kamon.instrumentation.http.HttpOperationNameGenerator
20+
21+
import scala.collection.concurrent.TrieMap
22+
23+
trait BaseKamonArmeriaOperationNameGenerator extends HttpOperationNameGenerator {
24+
25+
private val localCache = TrieMap.empty[String, String]
26+
private val normalizePattern = """\$([^<]+)<[^>]+>""".r
27+
28+
def name(request: Request): Option[String] =
29+
Some(
30+
localCache.getOrElseUpdate(key(request), {
31+
// Convert paths of form GET /foo/bar/$paramname<regexp>/blah to foo.bar.paramname.blah.get
32+
val normalisedPath = normalisePath(request.path)
33+
name(request, normalisedPath)
34+
})
35+
)
36+
37+
protected def name(request: Request, normalisedPath: String): String
38+
39+
protected def key(request: Request): String
40+
41+
private def normalisePath(path: String) = {
42+
val p = normalizePattern.replaceAllIn(path, "$1").replace('/', '.').dropWhile(_ == '.')
43+
val normalisedPath = {
44+
if (p.lastOption.exists(_ != '.')) s"$p."
45+
else p
46+
}
47+
normalisedPath
48+
}
49+
}

0 commit comments

Comments
 (0)