Skip to content

Commit

Permalink
Implement M3TracingHttpInterceptor
Browse files Browse the repository at this point in the history
  • Loading branch information
saiya committed Apr 12, 2019
1 parent eac69da commit d8ce8dd
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 2 deletions.
1 change: 1 addition & 0 deletions .idea/gradle.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions jvm/apache-httpclient/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Apache HttpClient integration

## How to setup

Add `M3TracingHttpInterceptor` as request/response interceptor of HttpClient.

```java
// CAUTION: Must setup as BOTH interceptor otherwise it may cause memory leak.
httpclient.addRequestInterceptor(M3TracingHttpInterceptor.INSTANCE);
httpclient.addResponseInterceptor(M3TracingHttpInterceptor.INSTANCE);
```
9 changes: 9 additions & 0 deletions jvm/apache-httpclient/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
plugins {
kotlin("jvm")
}

dependencies {
api(project(":core"))

implementation("org.apache.httpcomponents:httpclient:${project.extra["apacheHttpClientVersion"]}")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package com.m3.tracing.apache.httpclient

import com.m3.tracing.M3Tracer
import com.m3.tracing.M3TracerFactory
import com.m3.tracing.TraceSpan
import org.apache.http.HttpRequest
import org.apache.http.HttpRequestInterceptor
import org.apache.http.HttpResponse
import org.apache.http.HttpResponseInterceptor
import org.apache.http.client.methods.HttpUriRequest
import org.apache.http.protocol.HttpContext
import org.slf4j.LoggerFactory

/**
* Interceptor for Apache HTTP Client.
*
*/
open class M3TracingHttpInterceptor(
protected val tracer: M3Tracer
) : HttpRequestInterceptor, HttpResponseInterceptor {
companion object {
@JvmStatic
public val INSTANCE = M3TracingHttpInterceptor()

private val currentSpan = ThreadLocal<TraceSpan>()
private val logger = LoggerFactory.getLogger(M3TracingHttpInterceptor::class.java)
}

constructor(): this(M3TracerFactory.get())

override fun process(request: HttpRequest, context: HttpContext) {
val span = tracer.startSpan(createSpanName(request))
currentSpan.set(span) // Set to ThreadLocal ASAP to prevent leak

doQuietly {
span["method"] = request.requestLine.method
span["uri"] = request.requestLine.uri
}
}

override fun process(response: HttpResponse, context: HttpContext) {
val span = currentSpan.get() ?: return
currentSpan.set(null) // Prevent ClassLoader leak

// Must continue to span.close() statement to prevent memory leak
doQuietly {
span["status"] = response.statusLine.statusCode
}
span.close()
}


private fun createSpanName(request: HttpRequest): String {
// Intentionally excluded queryString because it might contain dynamic string
// Dynamic span name makes runningSpan table so huge
return if (request is HttpUriRequest) {
"HTTP ${request.method} ${request.uri.host}"
} else {
"HTTP ${request.requestLine.method}"
}
}

/**
* `On Error Resume Next` in 21st century.
*/
protected fun doQuietly(action: () -> Unit) {
try {
action()
} catch (e: Throwable) {
logger.error("Failed to update Span.", e)
}
}
}
2 changes: 2 additions & 0 deletions jvm/apache-httpclient/src/test/resources/logging.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
handlers = org.slf4j.bridge.SLF4JBridgeHandler
.level=INFO
8 changes: 7 additions & 1 deletion jvm/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,15 @@ subprojects {
apply(plugin = "maven-publish")

val opencensusVersion by extra { "0.20.0" }

//Intentionally support Servlet API 3.0
//Intentionally support Servlet API 3.0
val servletApiVersion by extra { "3.0.1" }

// Following versions are based on spring-boot
val springBootVersion by extra { "2.1.4.RELEASE" }
val springWebVersion by extra { "5.1.6.RELEASE" }
val springBootVersion by extra { "2.1.4.RELEASE" } // spring-boot 2.1.4 -> spring-web 5.1.6
val apacheHttpClientVersion by extra { "4.5.8" }

dependencies {
compile(kotlin("stdlib-jdk8"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ open class M3TracingJdbcEventListener: SimpleJdbcEventListener() {

override fun onAfterAnyExecute(statementInformation: StatementInformation, timeElapsedNanos: Long, e: SQLException?) {
val span = currentSpan.get() ?: return
currentSpan.set(null) // Prevent ClassLoader leak

doQuietly { // Must proceed to close() statement to prevent leak
span["time_elapsed_nanos"] = timeElapsedNanos
if (e != null) {
Expand All @@ -37,7 +39,7 @@ open class M3TracingJdbcEventListener: SimpleJdbcEventListener() {
/**
* `On Error Resume Next` in 21st century.
*/
protected inline fun doQuietly(action: () -> Unit) {
protected fun doQuietly(action: () -> Unit) {
try {
action()
} catch (e: Throwable) {
Expand Down
1 change: 1 addition & 0 deletions jvm/settings.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
include(
"apache-httpclient",
"core",
"jdbc-p6spy",
"opencensus",
Expand Down

0 comments on commit d8ce8dd

Please sign in to comment.