Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
added opentracing headers support, fixes #287
  • Loading branch information
Brüder, Lena committed Jul 12, 2018
1 parent 54d62a3 commit 6859213
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 16 deletions.
34 changes: 19 additions & 15 deletions src/main/java/org/restheart/Bootstrapper.java
Expand Up @@ -17,6 +17,7 @@
*/
package org.restheart;

import org.restheart.handlers.TracingInstrumentationHandler;
import org.restheart.init.Initializer;
import com.mongodb.MongoClient;
import static com.sun.akuma.CLibrary.LIBC;
Expand Down Expand Up @@ -811,6 +812,7 @@ private static GracefulShutdownHandler getHandlersPipe(final AuthenticationMecha
.allMatch(url -> !isPathTemplate(url));

final PipedHttpHandler baseChain = new MetricsInstrumentationHandler(
new TracingInstrumentationHandler(
new RequestLoggerHandler(
new CORSHandler(
new OptionsHandler(
Expand All @@ -819,7 +821,7 @@ private static GracefulShutdownHandler getHandlersPipe(final AuthenticationMecha
coreHandlerChain,
authenticationMechanism,
identityManager,
accessManager))))));
accessManager)))))));

if (!allPathTemplates && !allPaths) {
LOGGER.error("No mongo resource mounted! Check your mongo-mounts. where url must be either all absolute paths or all path templates");
Expand Down Expand Up @@ -1066,22 +1068,24 @@ private static void pipeApplicationLogicHandlers(
new BodyInjectorHandler(alHandler));

if (alSecured) {
paths.addPrefixPath("/_logic" + alWhere, new RequestLoggerHandler(
new CORSHandler(
new SecurityHandlerDispacher(
handler,
authenticationMechanism,
identityManager,
accessManager))));
paths.addPrefixPath("/_logic" + alWhere, new TracingInstrumentationHandler(
new RequestLoggerHandler(
new CORSHandler(
new SecurityHandlerDispacher(
handler,
authenticationMechanism,
identityManager,
accessManager)))));
} else {
paths.addPrefixPath("/_logic" + alWhere,
new RequestLoggerHandler(
new CORSHandler(
new SecurityHandlerDispacher(
handler,
authenticationMechanism,
identityManager,
new FullAccessManager()))));
new TracingInstrumentationHandler(
new RequestLoggerHandler(
new CORSHandler(
new SecurityHandlerDispacher(
handler,
authenticationMechanism,
identityManager,
new FullAccessManager())))));
}

LOGGER.info("URL {} bound to application logic handler {}."
Expand Down
@@ -0,0 +1,84 @@
package org.restheart.handlers;

import com.google.common.annotations.VisibleForTesting;

import com.codahale.metrics.MetricRegistry;

import org.restheart.Bootstrapper;
import org.restheart.Configuration;
import org.restheart.db.DbsDAO;
import org.restheart.utils.SharedMetricRegistryProxy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;

import java.util.Optional;
import java.util.Random;
import java.util.concurrent.TimeUnit;

import io.undertow.server.HttpServerExchange;
import io.undertow.util.HeaderValues;
import io.undertow.util.HexConverter;
import io.undertow.util.HttpString;

import static org.restheart.Configuration.METRICS_GATHERING_LEVEL.COLLECTION;
import static org.restheart.Configuration.METRICS_GATHERING_LEVEL.DATABASE;
import static org.restheart.Configuration.METRICS_GATHERING_LEVEL.ROOT;

/**
* Handler to write tracing headers to the logging MDC. Pick it up via the default way with "%X{name}", e.g. "%X{x-b3-traceid}".
*/
public class TracingInstrumentationHandler extends PipedHttpHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(TracingInstrumentationHandler.class);
public static final String X_B3_TRACEID = "x-b3-traceid";
public static final String UBER_TRACEID = "uber-trace-id";
public static final String X_B3_SPANID = "x-b3-spanid";
public static final String X_B3_PARENTSPANID = "x-b3-parentspanid";
public static final String X_B3_SAMPLED = "x-b3-sampled";

public TracingInstrumentationHandler(PipedHttpHandler next) {
super(next);
}

@VisibleForTesting
static String generateRandomTraceId() {
byte[] data = new byte[8];
new Random().nextBytes(data);
return HexConverter.convertToHexString(data);
}

@Override
public void handleRequest(HttpServerExchange exchange, RequestContext context) throws Exception {
//header definitions can be found at https://github.com/openzipkin/b3-propagation
//additionally, there is support for incoming trace headers from jaeger
String traceID = Optional.ofNullable(exchange.getRequestHeaders().get(X_B3_TRACEID))
.map(HeaderValues::peekFirst)
//support for jaeger trace header
.orElse(Optional.ofNullable(exchange.getRequestHeaders().get(UBER_TRACEID))
.map(HeaderValues::peekFirst)
.orElse(generateRandomTraceId()));
MDC.put(X_B3_TRACEID, traceID);
String spanID = Optional.ofNullable(exchange.getRequestHeaders().get(X_B3_SPANID))
.map(HeaderValues::peekFirst)
.orElse(generateRandomTraceId());
MDC.put(X_B3_SPANID, spanID);
String parentSpanID = Optional.ofNullable(exchange.getRequestHeaders().get(X_B3_PARENTSPANID))
.map(HeaderValues::peekFirst)
.orElse("");
MDC.put(X_B3_PARENTSPANID, parentSpanID);
String sampled = Optional.ofNullable(exchange.getRequestHeaders().get(X_B3_SAMPLED))
.map(HeaderValues::peekFirst)
.orElse("0");
MDC.put(X_B3_SAMPLED, sampled);

exchange.getResponseHeaders().put(HttpString.tryFromString(X_B3_TRACEID), traceID)
.put(HttpString.tryFromString(UBER_TRACEID), traceID)
.put(HttpString.tryFromString(X_B3_SPANID), spanID)
.put(HttpString.tryFromString(X_B3_PARENTSPANID), parentSpanID)
.put(HttpString.tryFromString(X_B3_SAMPLED), sampled);

if (!exchange.isResponseComplete() && getNext() != null) {
next(exchange, context);
}
}
}
2 changes: 1 addition & 1 deletion src/main/resources/logback.xml
Expand Up @@ -21,7 +21,7 @@
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<withJansi>true</withJansi>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %highlight(%-5level) %logger{36} - %msg%n</pattern>
<pattern>%d{HH:mm:ss.SSS} [%thread / %X{x-b3-traceid}] %highlight(%-5level) %logger{36} - %msg%n</pattern>
</encoder>
</appender>

Expand Down
@@ -0,0 +1,18 @@
package org.restheart.handlers;

import org.junit.Test;

import static org.junit.Assert.*;

public class TracingInstrumentationHandlerTest {

@Test
public void generateRandomTraceId() {
for (int i=0; i<100; i++) {
String traceId = TracingInstrumentationHandler.generateRandomTraceId();
String regex = "[a-f0-9]+";
assertTrue(traceId + "did not match " + regex, traceId.matches(regex));
assertEquals(traceId + " did not have length 16!", 16, traceId.length());
}
}
}

0 comments on commit 6859213

Please sign in to comment.