Skip to content
Permalink
Browse files
filter autosetup and zipkin basic integration
  • Loading branch information
rmannibucau committed May 21, 2018
1 parent c916417 commit 0d4bb178157c99baa5d3195448af408a0a113417
Showing 18 changed files with 664 additions and 49 deletions.
@@ -2,6 +2,9 @@

Geronimo OpenTracing provides an OpenTracing implementation and a Microprofile OpenTracing implementation at once.

NOTE: sampling is not yet supported because it leads to push inconsistent spans to the backend, however you can always specialize (CDI)
your `FinishSpan` observer to implement it if desired.

== Configuration

NOTE: if you are using Microprofile Config it is used, otherwise it uses system properties.
@@ -10,6 +13,8 @@ NOTE: if you are using Microprofile Config it is used, otherwise it uses system
| Key | Description | Default
|geronimo.opentracing.filter.active|Should OpenTracing be activated|true
|geronimo.opentracing.filter.forcedTracing.urls|Urls for which the tracking should be activated automatically. The urls are actually the requets uri minus the context path.|-
|geronimo.opentracing.filter.skippedTracing.urls|Urls for which the tracking should be skipped.|-
|geronimo.opentracing.filter.skippedTracing.matcherType|Type of matcher for the url, default is `prefix` which means a `startsWith` is used on the url but you can also use `regex` which compiles the url as a `Pattern`|prefix
|geronimo.opentracing.filter.forcedTracing.matcherType|Type of matcher for the url, default is `prefix` which means a `startsWith` is used on the url but you can also use `regex` which compiles the url as a `Pattern`|prefix
|geronimo.opentracing.filter.forcedTracing.skipDefaultTags|Should `HTTP_METHOD`, `HTTP_URL` not be added to tags|false
|geronimo.opentracing.server.filter.request.skip.<endpoint class>_<endpoint method>|Should server instrumentation be ignored|false
@@ -22,4 +27,7 @@ NOTE: if you are using Microprofile Config it is used, otherwise it uses system
|geronimo.opentracing.propagation.headers.traceId|Name of the header used to host the traceId value|`X-B3-TraceId`
|geronimo.opentracing.propagation.headers.baggagePrefix|Prefix of headers used to host the baggage values|`baggage-`
|geronimo.opentracing.cdi.executorServices.wrappedNames|Name (as CDI names of the beans) of executor services which will get an interceptor propagating the current scope (span)|-
|geronimo.opentracing.id.generator|`counter` (to generate longs), `uuid` (to generate random uuids) or `hex` (to use the hexa representation of the uuid generator). Specifies which kind of trace and span id are in use.|hex
|geronimo.opentracing.span.converter.zipkin.active|Should spans converted to a zipkin representation. True until there is a standard opentracing format.|true
|geronimo.opentracing.span.converter.zipkin.logger.active|Should a logger named `org.apache.geronimo.opentracing.zipkin` log each span as a Zipkin JSON. This allows to use a logger implementation to push the spans to any backend (like log4j2 kafka appender). It uses JUL as a facade.|true
|===
@@ -35,13 +35,6 @@
</properties>

<dependencies>
<dependency>
<groupId>org.eclipse.microprofile.config</groupId>
<artifactId>microprofile-config-api</artifactId>
<version>1.2</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.geronimo</groupId>
<artifactId>geronimo-microprofile-opentracing-spec</artifactId>
@@ -55,6 +48,21 @@
<scope>provided</scope>
</dependency>

<dependency>
<groupId>org.eclipse.microprofile.config</groupId>
<artifactId>microprofile-config-api</artifactId>
<version>1.2</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-jsonb_1.0_spec</artifactId>
<version>1.0</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>

<dependency>
<groupId>org.apache.openwebbeans</groupId>
<artifactId>openwebbeans-impl</artifactId>
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.geronimo.microprofile.config;
package org.apache.geronimo.microprofile.opentracing.config;

import java.io.IOException;
import java.io.InputStream;
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.geronimo.microprofile.config;
package org.apache.geronimo.microprofile.opentracing.config;

@FunctionalInterface
public interface GeronimoOpenTracingConfig {
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.geronimo.microprofile.config;
package org.apache.geronimo.microprofile.opentracing.config;

import javax.enterprise.inject.Vetoed;

@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.geronimo.microprofile.config;
package org.apache.geronimo.microprofile.opentracing.config;

import javax.enterprise.inject.Vetoed;

@@ -40,7 +40,7 @@
import io.opentracing.propagation.Format;
import io.opentracing.propagation.TextMap;

import org.apache.geronimo.microprofile.config.GeronimoOpenTracingConfig;
import org.apache.geronimo.microprofile.opentracing.config.GeronimoOpenTracingConfig;

@ApplicationScoped
public class GeronimoTracer implements Tracer {
@@ -16,14 +16,57 @@
*/
package org.apache.geronimo.microprofile.opentracing.impl;

import java.nio.charset.StandardCharsets;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Supplier;

import javax.annotation.PostConstruct;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;

import org.apache.geronimo.microprofile.opentracing.config.GeronimoOpenTracingConfig;

@ApplicationScoped
public class IdGenerator {
private static final char[] HEXA_MAPPING = "0123456789ABCDEF".toCharArray();

@Inject
private GeronimoOpenTracingConfig config;

private Supplier<Object> delegate;

@PostConstruct
private void createDelegate() {
switch (config.read("id.generator", "counter")) {
case "counter":
delegate = new Supplier<Object>() {
private final AtomicLong counter = new AtomicLong();

@Override
public Object get() {
return counter.incrementAndGet();
}
};
break;
case "uuid":
delegate = () -> UUID.randomUUID().toString();
break;
case "hex":
default:
delegate = () -> toHex(UUID.randomUUID().toString().replace("-", "").getBytes(StandardCharsets.UTF_8));
}
}

public Object next() {
return UUID.randomUUID().toString();
return delegate.get();
}

private String toHex(final byte[] uuid) {
final StringBuilder representation = new StringBuilder(uuid.length * 2);
for (final byte current : uuid) {
representation.append(HEXA_MAPPING[(current >> 4) & 0xF]).append(HEXA_MAPPING[(current & 0xF)]);
}
return representation.toString();
}
}
@@ -189,6 +189,10 @@ public Collection<Log> getLogs() {
return logs;
}

public Collection<ReferenceImpl> getReferences() {
return references;
}

public static class Log {

private final long timestampMicros;
@@ -40,8 +40,10 @@
import javax.ws.rs.HttpMethod;
import javax.ws.rs.Path;

import org.apache.geronimo.microprofile.config.GeronimoOpenTracingConfig;
import org.apache.geronimo.microprofile.opentracing.config.GeronimoOpenTracingConfig;
import org.apache.geronimo.microprofile.opentracing.microprofile.thread.OpenTracingExecutorService;
import org.apache.geronimo.microprofile.opentracing.microprofile.zipkin.ZipkinConverter;
import org.apache.geronimo.microprofile.opentracing.microprofile.zipkin.ZipkinLogger;
import org.eclipse.microprofile.opentracing.Traced;

public class OpenTracingExtension implements Extension {
@@ -50,12 +52,29 @@ public class OpenTracingExtension implements Extension {

private Collection<String> instrumentedExecutorServices;

private boolean useZipkin;
private boolean useZipkinLogger;

void onStart(@Observes final BeforeBeanDiscovery beforeBeanDiscovery) {
config = GeronimoOpenTracingConfig.create();
useZipkin = Boolean.parseBoolean(config.read("span.converter.zipkin.active", "true"));
useZipkinLogger = useZipkin && Boolean.parseBoolean(config.read("span.converter.zipkin.logger.active", "true"));
instrumentedExecutorServices = ofNullable(config.read("cdi.executorServices.wrappedNames", null))
.map(s -> Stream.of(s.split(",")).map(String::trim).filter(it -> !it.isEmpty()).collect(toSet())).orElse(null);
}

void zipkinConverterToggle(@Observes final ProcessAnnotatedType<ZipkinConverter> onZipkinConverter) {
if (!useZipkin) {
onZipkinConverter.veto();
}
}

void zipkinLoggerToggle(@Observes final ProcessAnnotatedType<ZipkinLogger> onZipkinLogger) {
if (!useZipkinLogger) {
onZipkinLogger.veto();
}
}

<T> void removeTracedFromJaxRsEndpoints(@Observes @WithAnnotations(Traced.class) final ProcessAnnotatedType<T> pat) {
if (isJaxRs(pat.getAnnotatedType())) { // we have filters with more accurate timing
final AnnotatedTypeConfigurator<T> configurator = pat.configureAnnotatedType();
@@ -27,7 +27,7 @@
import javax.ws.rs.client.ClientRequestContext;
import javax.ws.rs.client.ClientRequestFilter;

import org.apache.geronimo.microprofile.config.GeronimoOpenTracingConfig;
import org.apache.geronimo.microprofile.opentracing.config.GeronimoOpenTracingConfig;
import org.apache.geronimo.microprofile.opentracing.impl.JaxRsHeaderTextMap;

import io.opentracing.Scope;
@@ -76,9 +76,9 @@ public void filter(final ClientRequestContext context) {
Tags.HTTP_METHOD.set(span, context.getMethod());
Tags.HTTP_URL.set(span, context.getUri().toASCIIString());
}
if ("true".equalsIgnoreCase(
String.valueOf(context.getProperty("org.apache.geronimo.microprofile.opentracing.client.addPeerTags")))) {
Tags.PEER_HOSTNAME.set(span, context.getUri().getHost());
if (!skipPeerTags) {
final String host = context.getUri().getHost();
Tags.PEER_HOSTNAME.set(span, host);
Tags.PEER_PORT.set(span, context.getUri().getPort());
}
// customization point
@@ -30,7 +30,7 @@
import javax.ws.rs.core.FeatureContext;
import javax.ws.rs.ext.Provider;

import org.apache.geronimo.microprofile.config.GeronimoOpenTracingConfig;
import org.apache.geronimo.microprofile.opentracing.config.GeronimoOpenTracingConfig;
import org.eclipse.microprofile.opentracing.Traced;

import io.opentracing.Tracer;
@@ -6,6 +6,7 @@
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Predicate;
@@ -24,7 +25,7 @@
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.geronimo.microprofile.config.GeronimoOpenTracingConfig;
import org.apache.geronimo.microprofile.opentracing.config.GeronimoOpenTracingConfig;
import org.apache.geronimo.microprofile.opentracing.impl.ScopeManagerImpl;
import org.apache.geronimo.microprofile.opentracing.impl.ServletHeaderTextMap;

@@ -47,29 +48,39 @@ public class OpenTracingFilter implements Filter {

private Collection<Predicate<String>> forcedUrls;

private List<Predicate<String>> skipUrls;

private boolean skipDefaultTags;

@Override
public void init(final FilterConfig filterConfig) throws ServletException {
skipDefaultTags = Boolean.parseBoolean(config.read("filter.forcedTracing.skipDefaultTags", "false"));
forcedUrls = ofNullable(config.read("filter.forcedTracing.urls", null)).map(String::trim).filter(v -> !v.isEmpty())
.map(v -> {
final String matchingType = config.read("filter.forcedTracing.matcherType", "prefix");
final Function<String, Predicate<String>> matcherFactory;
switch (matchingType) {
case "regex":
matcherFactory = from -> {
final Pattern compiled = Pattern.compile(from);
return url -> compiled.matcher(url).matches();
};
break;
case "prefix":
default:
matcherFactory = from -> url -> url.startsWith(from);
}
return Stream.of(v.split(",")).map(String::trim).filter(it -> !it.isEmpty()).map(matcherFactory)
.collect(toList());
}).orElse(null);
forcedUrls = ofNullable(config.read("filter.forcedTracing.urls", null))
.map(String::trim).filter(v -> !v.isEmpty())
.map(v -> toMatchingPredicates(v, "forcedTracing"))
.orElse(null);
skipUrls = ofNullable(config.read("filter.skippedTracing.urls", null))
.map(String::trim).filter(v -> !v.isEmpty())
.map(v -> toMatchingPredicates(v, "skippedTracing"))
.orElse(null);
}

private List<Predicate<String>> toMatchingPredicates(final String v, final String keyMarker) {
final String matchingType = config.read("filter." + keyMarker + ".matcherType", "prefix");
final Function<String, Predicate<String>> matcherFactory;
switch (matchingType) {
case "regex":
matcherFactory = from -> {
final Pattern compiled = Pattern.compile(from);
return url -> compiled.matcher(url).matches();
};
break;
case "prefix":
default:
matcherFactory = from -> url -> url.startsWith(from);
}
return Stream.of(v.split(",")).map(String::trim).filter(it -> !it.isEmpty()).map(matcherFactory)
.collect(toList());
}

@Override
@@ -103,6 +114,14 @@ public void doFilter(final ServletRequest request, final ServletResponse respons
request.setAttribute(OpenTracingFilter.class.getName(), scope);
}
}
if (skipUrls != null && !skipUrls.isEmpty()) {
final HttpServletRequest req = HttpServletRequest.class.cast(request);
final String matching = req.getRequestURI().substring(req.getContextPath().length());
if (forcedUrls.stream().anyMatch(p -> p.test(matching))) {
chain.doFilter(request, response);
return;
}
}
try {
chain.doFilter(request, response);
} catch (final Exception ex) {
@@ -24,7 +24,7 @@
import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;

import org.apache.geronimo.microprofile.config.GeronimoOpenTracingConfig;
import org.apache.geronimo.microprofile.opentracing.config.GeronimoOpenTracingConfig;

public class ServletTracingSetup implements ServletContainerInitializer {
@Override

0 comments on commit 0d4bb17

Please sign in to comment.