From 96e98e3567674eaab22e3032b487aa49064cdb25 Mon Sep 17 00:00:00 2001 From: renaudboutet Date: Tue, 30 May 2017 15:12:18 +0200 Subject: [PATCH] New feature: disabling instrumentations --- dd-java-agent/Readme.md | 25 +++- .../trace/resolver/AgentTracerConfig.java | 13 ++ .../agent/TraceAnnotationsManager.java | 121 +++++++++++++++++- .../src/main/resources/dd-trace.yaml | 9 +- .../agent/TraceAnnotationsManagerTest.java | 4 +- .../src/main/resources/dd-trace.yaml | 7 +- 6 files changed, 165 insertions(+), 14 deletions(-) diff --git a/dd-java-agent/Readme.md b/dd-java-agent/Readme.md index a7c21a880c..45db2db7c8 100644 --- a/dd-java-agent/Readme.md +++ b/dd-java-agent/Readme.md @@ -72,9 +72,17 @@ sampler: # RateSample: only a portion of spans are reported to the writer # - Param 'rate': the portion of spans to keep type: AllSampler + # Skip some traces if the root span tag values matches some regexp patterns + # skipTagsPatterns: {"http.url": ".*/demo/add.*"} + +# Enable custom tracing (Custom annotations for now) +enableCustomTracing: true + +# Disable some instrumentations +# disabledInstrumentations: ["apache http", "mongo", "jetty", "tomcat", ...] ``` -If you want to change it, you should then create it in your project and change it as suited. +If you want to change it, you must create it in your project. ## Instrumented frameworks @@ -114,6 +122,21 @@ But unfortunately this can not be done entirely automatically today. To enable t We also provide an [example project with Spring Boot & MySQL](web application frameworks). +### Disabling instrumentations + +If for some reasons you need to disable an instrumentation you should uncomment the `disabledInstrumentations: ` attribute in the configuration and provide a list as illustrated below: + +```yaml +... + +# Disable a few instrumentations +disabledInstrumentations: ["apache http", "mongo", "tomcat"] + +... +``` + +### + ## Custom instrumentations ### The `@trace` annotation diff --git a/dd-java-agent/src/main/java/com/datadoghq/trace/resolver/AgentTracerConfig.java b/dd-java-agent/src/main/java/com/datadoghq/trace/resolver/AgentTracerConfig.java index 40227180fa..54ee1e5b6a 100644 --- a/dd-java-agent/src/main/java/com/datadoghq/trace/resolver/AgentTracerConfig.java +++ b/dd-java-agent/src/main/java/com/datadoghq/trace/resolver/AgentTracerConfig.java @@ -1,11 +1,24 @@ package com.datadoghq.trace.resolver; +import java.util.ArrayList; +import java.util.List; + /** * Configuration POJO for the agent */ public class AgentTracerConfig extends TracerConfig { private boolean enableCustomTracing = false; + + private List disabledInstrumentations = new ArrayList(); + + public List getDisabledInstrumentations() { + return disabledInstrumentations; + } + + public void setDisabledInstrumentations(List uninstallContributions) { + this.disabledInstrumentations = uninstallContributions; + } public boolean isEnableCustomTracing() { return enableCustomTracing; diff --git a/dd-java-agent/src/main/java/io/opentracing/contrib/agent/TraceAnnotationsManager.java b/dd-java-agent/src/main/java/io/opentracing/contrib/agent/TraceAnnotationsManager.java index 565fbbe299..8a469d33f3 100644 --- a/dd-java-agent/src/main/java/io/opentracing/contrib/agent/TraceAnnotationsManager.java +++ b/dd-java-agent/src/main/java/io/opentracing/contrib/agent/TraceAnnotationsManager.java @@ -1,12 +1,23 @@ package io.opentracing.contrib.agent; +import java.io.IOException; +import java.io.InputStream; import java.io.PrintWriter; import java.io.StringWriter; import java.lang.reflect.Method; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.List; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.jboss.byteman.agent.Location; import org.jboss.byteman.agent.LocationType; @@ -31,11 +42,13 @@ import javassist.bytecode.Descriptor; * * It loads all the scripts contained in all the 'oatrules.btm' resource files then instrument all the methods annoted with the @Trace. */ -public class TraceAnnotationsManager extends OpenTracingManager{ +public class TraceAnnotationsManager { private static Logger log = Logger.getLogger(TraceAnnotationsManager.class.getName()); private static Retransformer transformer; + private static final String AGENT_RULES = "otarules.btm"; + /** * This method initializes the manager. * @@ -44,24 +57,57 @@ public class TraceAnnotationsManager extends OpenTracingManager{ */ public static void initialize(Retransformer trans) throws Exception { transformer = trans; - OpenTracingManager.initialize(trans); - OpenTracingManager.loadRules(ClassLoader.getSystemClassLoader()); - //Load configuration AgentTracerConfig agentTracerConfig = FactoryUtils.loadConfigFromResource(DDTracerFactory.CONFIG_PATH, AgentTracerConfig.class); + + List loadedScripts = loadRules(ClassLoader.getSystemClassLoader()); + + //Check if some rules have to be uninstalled + if(agentTracerConfig != null){ + List uninstallContributions = agentTracerConfig.getDisabledInstrumentations(); + if(uninstallContributions!=null && !uninstallContributions.isEmpty()){ + uninstallScripts(loadedScripts,uninstallContributions); + } + } //Check if annotations are enabled - if(agentTracerConfig.isEnableCustomTracing()){ - loadRules(ClassLoader.getSystemClassLoader()); + if(agentTracerConfig != null && agentTracerConfig.isEnableCustomTracing()){ + loadAnnotationsRules(ClassLoader.getSystemClassLoader()); } } + /** + * Uninstall some scripts from a list of patterns. + * All the rules that contain the pattern will be uninstalled + * + * @param installedScripts + * @param patterns not case sensitive (eg. "mongo", "apache http", "elasticsearch", etc...]) + */ + public static void uninstallScripts(List installedScripts, List patterns) throws Exception{ + Set rulesToRemove = new HashSet(); + + for(String strPattern : patterns){ + Pattern pattern = Pattern.compile("(?i)RULE [^\n]*"+strPattern+"[^\n]*\n"); + for(String loadedScript : installedScripts){ + Matcher matcher = pattern.matcher(loadedScript); + while(matcher.find()){ + rulesToRemove.add(matcher.group()); + } + } + } + StringWriter sw = new StringWriter(); + try(PrintWriter pr = new PrintWriter(sw)){ + transformer.removeScripts(new ArrayList(rulesToRemove), pr); + } + log.log(Level.INFO, sw.toString()); + } + /** * Find all the methods annoted with @Trace and inject rules * * @param classLoader */ - public static void loadRules(ClassLoader classLoader) { + public static void loadAnnotationsRules(ClassLoader classLoader) { Reflections reflections = new Reflections(new ConfigurationBuilder() .forPackages("/") .filterInputsBy(new FilterBuilder().include(".*\\.class")) @@ -140,6 +186,67 @@ public class TraceAnnotationsManager extends OpenTracingManager{ return ruleScript; } + /** + * This method loads any OpenTracing Agent rules (otarules.btm) found as resources + * within the supplied classloader. + * + * @param classLoader The classloader + */ + public static List loadRules(ClassLoader classLoader) { + List scripts = new ArrayList<>(); + if (transformer == null) { + log.severe("Attempt to load OpenTracing agent rules before transformer initialized"); + return scripts; + } + + List scriptNames = new ArrayList<>(); + + // Load default and custom rules + try { + Enumeration iter = classLoader.getResources(AGENT_RULES); + while (iter.hasMoreElements()) { + loadRules(iter.nextElement().toURI(), scriptNames, scripts); + } + + StringWriter sw=new StringWriter(); + try (PrintWriter writer = new PrintWriter(sw)) { + try { + transformer.installScript(scripts, scriptNames, writer); + } catch (Exception e) { + log.log(Level.SEVERE, "Failed to install scripts", e); + } + } + if (log.isLoggable(Level.FINEST)) { + log.finest(sw.toString()); + } + } catch (IOException | URISyntaxException e) { + log.log(Level.SEVERE, "Failed to load OpenTracing agent rules", e); + } + + if (log.isLoggable(Level.FINE)) { + log.fine("OpenTracing Agent rules loaded"); + } + return scripts; + } + + private static void loadRules(URI uri, final List scriptNames, + final List scripts) throws IOException { + if (log.isLoggable(Level.FINE)) { + log.fine("Load rules from URI = " + uri); + } + + StringBuilder str=new StringBuilder(); + try (InputStream is = uri.toURL().openStream()) { + byte[] b = new byte[10240]; + int len; + while ((len = is.read(b)) != -1) { + str.append(new String(b, 0, len)); + } + } + scripts.add(str.toString()); + scriptNames.add(uri.toString()); + } + private static String CURRENT_SPAN_EXISTS = "IF currentSpan() != null\n"; private static String CURRENT_SPAN_NOT_EXISTS = "IF currentSpan() == null\n"; diff --git a/dd-java-agent/src/main/resources/dd-trace.yaml b/dd-java-agent/src/main/resources/dd-trace.yaml index 1a248405b6..43c740b575 100644 --- a/dd-java-agent/src/main/resources/dd-trace.yaml +++ b/dd-java-agent/src/main/resources/dd-trace.yaml @@ -19,6 +19,11 @@ sampler: # RateSample: only a portion of spans are reported to the writer # - Param 'rate': the portion of spans to keep type: AllSampler + # Skip some traces if the root span tag values matches some regexp patterns + # skipTagsPatterns: {"http.url": ".*/demo/add.*"} -# Enable custom tracing (annotations) -# enableCustomTracing: true \ No newline at end of file +# Enable custom tracing (Custom annotations for now) +# enableCustomTracing: true + +# Disable some instrumentations +# disabledInstrumentations: ["apache http", "mongo", "jetty", "tomcat", ...] \ No newline at end of file diff --git a/dd-java-agent/src/test/java/io/opentracing/contrib/agent/TraceAnnotationsManagerTest.java b/dd-java-agent/src/test/java/io/opentracing/contrib/agent/TraceAnnotationsManagerTest.java index a6d367bf82..5c4d590fb2 100644 --- a/dd-java-agent/src/test/java/io/opentracing/contrib/agent/TraceAnnotationsManagerTest.java +++ b/dd-java-agent/src/test/java/io/opentracing/contrib/agent/TraceAnnotationsManagerTest.java @@ -15,11 +15,11 @@ public class TraceAnnotationsManagerTest { @Before public void beforeTest() throws Exception { GlobalTracer.register(tracer); - TraceAnnotationsManager.loadRules(ClassLoader.getSystemClassLoader()); + TraceAnnotationsManager.loadAnnotationsRules(ClassLoader.getSystemClassLoader()); } @Test - public void test() { + public void testAnnotations() { //Test single span in new trace SayTracedHello.sayHello(); diff --git a/dd-trace-examples/dropwizard-mongo-client/src/main/resources/dd-trace.yaml b/dd-trace-examples/dropwizard-mongo-client/src/main/resources/dd-trace.yaml index a11ea8505f..90050545f6 100644 --- a/dd-trace-examples/dropwizard-mongo-client/src/main/resources/dd-trace.yaml +++ b/dd-trace-examples/dropwizard-mongo-client/src/main/resources/dd-trace.yaml @@ -22,5 +22,8 @@ sampler: # Skip some traces if the root span tag values matches some regexp patterns # skipTagsPatterns: {"http.url": ".*/demo/add.*"} -# Enable custom tracing (annotations) -enableCustomTracing: true \ No newline at end of file +# Enable custom tracing (Custom annotations for now) +enableCustomTracing: true + +# Disable some instrumentations +# disabledInstrumentations: ["apache http", "mongo", "jetty", "tomcat", ...] \ No newline at end of file