Remove jre logging integration
This commit is contained in:
parent
3295739e28
commit
6ffaa9e04f
|
@ -1,19 +0,0 @@
|
|||
// Set properties before any plugins get loaded
|
||||
project.ext {
|
||||
// Execute tests on all JVMs, even rare and outdated ones
|
||||
coreJavaInstrumentation = true
|
||||
}
|
||||
|
||||
apply from: "${rootDir}/gradle/java.gradle"
|
||||
|
||||
dependencies {
|
||||
compile project(':dd-trace-api')
|
||||
compile project(':dd-java-agent:agent-tooling')
|
||||
|
||||
compile deps.bytebuddy
|
||||
compile deps.opentracing
|
||||
annotationProcessor deps.autoservice
|
||||
implementation deps.autoservice
|
||||
|
||||
testCompile project(':dd-java-agent:testing')
|
||||
}
|
|
@ -1,223 +0,0 @@
|
|||
package datadog.trace.instrumentation.jre.logging;
|
||||
|
||||
import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.failSafe;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import datadog.trace.agent.tooling.ClassLoaderMatcher;
|
||||
import datadog.trace.agent.tooling.Instrumenter;
|
||||
import datadog.trace.agent.tooling.Utils;
|
||||
import datadog.trace.agent.tooling.muzzle.Reference;
|
||||
import datadog.trace.agent.tooling.muzzle.ReferenceMatcher;
|
||||
import java.security.ProtectionDomain;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.bytebuddy.agent.builder.AgentBuilder;
|
||||
import net.bytebuddy.asm.AsmVisitorWrapper;
|
||||
import net.bytebuddy.description.field.FieldDescription;
|
||||
import net.bytebuddy.description.field.FieldList;
|
||||
import net.bytebuddy.description.method.MethodList;
|
||||
import net.bytebuddy.description.type.TypeDescription;
|
||||
import net.bytebuddy.dynamic.DynamicType;
|
||||
import net.bytebuddy.implementation.Implementation;
|
||||
import net.bytebuddy.jar.asm.ClassVisitor;
|
||||
import net.bytebuddy.jar.asm.ClassWriter;
|
||||
import net.bytebuddy.jar.asm.Label;
|
||||
import net.bytebuddy.jar.asm.MethodVisitor;
|
||||
import net.bytebuddy.jar.asm.Opcodes;
|
||||
import net.bytebuddy.jar.asm.Type;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
import net.bytebuddy.pool.TypePool;
|
||||
import net.bytebuddy.utility.JavaModule;
|
||||
|
||||
/**
|
||||
* This instrumentation patches java.util.logging.Logger to return a "safe" logger which doesn't
|
||||
* touch the global log manager when static log creators (e.g. getLogger) are invoked under datadog
|
||||
* threads.
|
||||
*
|
||||
* <p>Our PatchLogger solution is not enough here because it's possible for dd-threads to use
|
||||
* bootstrap utils which in turn use call Logger.getLogger(...)
|
||||
*/
|
||||
@Slf4j
|
||||
@AutoService(Instrumenter.class)
|
||||
public class LoggerInstrumentation implements Instrumenter {
|
||||
// Intentionally doing the string replace to bypass gradle shadow rename
|
||||
// loggerClassName = java.util.logging.Logger
|
||||
private static final String loggerClassName =
|
||||
"java.util.logging.TMP".replaceFirst("TMP", "Logger");
|
||||
private ReferenceMatcher referenceMatcher = null;
|
||||
|
||||
public LoggerInstrumentation() {}
|
||||
|
||||
@Override
|
||||
public AgentBuilder instrument(AgentBuilder agentBuilder) {
|
||||
return agentBuilder
|
||||
.type(
|
||||
failSafe(
|
||||
named(loggerClassName),
|
||||
"Instrumentation type matcher unexpected exception: " + getClass().getName()),
|
||||
failSafe(
|
||||
new ElementMatcher<ClassLoader>() {
|
||||
@Override
|
||||
public boolean matches(ClassLoader target) {
|
||||
return target == ClassLoaderMatcher.BOOTSTRAP_CLASSLOADER;
|
||||
}
|
||||
},
|
||||
"Instrumentation class loader matcher unexpected exception: "
|
||||
+ getClass().getName()))
|
||||
.and(
|
||||
new AgentBuilder.RawMatcher() {
|
||||
@Override
|
||||
public boolean matches(
|
||||
TypeDescription typeDescription,
|
||||
ClassLoader classLoader,
|
||||
JavaModule module,
|
||||
Class<?> classBeingRedefined,
|
||||
ProtectionDomain protectionDomain) {
|
||||
// make sure the private constructor is present before applying instrumentation.
|
||||
return getReferenceMatcher().matches(classLoader);
|
||||
}
|
||||
})
|
||||
.transform(
|
||||
new AgentBuilder.Transformer() {
|
||||
@Override
|
||||
public DynamicType.Builder<?> transform(
|
||||
DynamicType.Builder<?> builder,
|
||||
TypeDescription typeDescription,
|
||||
ClassLoader classLoader,
|
||||
JavaModule module) {
|
||||
return builder.visit(new ReturnPatchLoggerForDDThreadsVisitor());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create or build a muzzle reference matcher to assert private logging constructor is present.
|
||||
*
|
||||
* <p>Logging instrumentation uses this private constructor because it's the only path to create a
|
||||
* logger which does not touch the global log manager.
|
||||
*/
|
||||
private synchronized ReferenceMatcher getReferenceMatcher() {
|
||||
if (null == referenceMatcher) {
|
||||
referenceMatcher =
|
||||
new ReferenceMatcher(
|
||||
new Reference.Builder(loggerClassName)
|
||||
.withMethod(
|
||||
new Reference.Source[0],
|
||||
new Reference.Flag[] {Reference.Flag.PRIVATE_OR_HIGHER},
|
||||
"<init>",
|
||||
Type.VOID_TYPE,
|
||||
Type.getType(String.class))
|
||||
.build());
|
||||
}
|
||||
return referenceMatcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace java.util.logging.Logger#getLogger() methods with an early-return for datadog threads
|
||||
* to avoid initializing the global log manager.
|
||||
*/
|
||||
private static class ReturnPatchLoggerForDDThreadsVisitor implements AsmVisitorWrapper {
|
||||
@Override
|
||||
public int mergeWriter(int flags) {
|
||||
return flags | ClassWriter.COMPUTE_MAXS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int mergeReader(int flags) {
|
||||
return flags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassVisitor wrap(
|
||||
TypeDescription instrumentedType,
|
||||
ClassVisitor classVisitor,
|
||||
Implementation.Context implementationContext,
|
||||
TypePool typePool,
|
||||
FieldList<FieldDescription.InDefinedShape> fields,
|
||||
MethodList<?> methods,
|
||||
int writerFlags,
|
||||
int readerFlags) {
|
||||
return new ClassVisitor(Opcodes.ASM7, classVisitor) {
|
||||
@Override
|
||||
public void visit(
|
||||
int version,
|
||||
int access,
|
||||
String name,
|
||||
String signature,
|
||||
String superName,
|
||||
String[] interfaces) {
|
||||
super.visit(version, access, name, signature, superName, interfaces);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodVisitor visitMethod(
|
||||
int access,
|
||||
final String methodName,
|
||||
final String methodDesc,
|
||||
String signature,
|
||||
String[] exceptions) {
|
||||
final MethodVisitor mv =
|
||||
super.visitMethod(access, methodName, methodDesc, signature, exceptions);
|
||||
// if isStatic and returns a logger, then add our advice
|
||||
if ((access & Opcodes.ACC_STATIC) != 0) {
|
||||
final Type returnType = Type.getReturnType(methodDesc);
|
||||
if (returnType != null
|
||||
&& returnType.getSort() == Type.OBJECT
|
||||
&& returnType.getInternalName().equals(Utils.getInternalName(loggerClassName))) {
|
||||
return new MethodVisitor(Opcodes.ASM7, mv) {
|
||||
@Override
|
||||
public void visitCode() {
|
||||
/* Appends an early return to the method body for datadog threads:
|
||||
*
|
||||
* if (Thread.currentThread().getName().startsWith("dd-")) {
|
||||
* // intentionally invoke private constructor to avoid initializing the LogManager
|
||||
* return new Logger("datadog");
|
||||
* }
|
||||
* // original method body
|
||||
*/
|
||||
final Label originalMethodBody = new Label();
|
||||
mv.visitMethodInsn(
|
||||
Opcodes.INVOKESTATIC,
|
||||
"java/lang/Thread",
|
||||
"currentThread",
|
||||
"()Ljava/lang/Thread;",
|
||||
false);
|
||||
mv.visitMethodInsn(
|
||||
Opcodes.INVOKEVIRTUAL,
|
||||
"java/lang/Thread",
|
||||
"getName",
|
||||
"()Ljava/lang/String;",
|
||||
false);
|
||||
// TODO: move dd- prefix to a constant once agent-bootstrap project is visible to
|
||||
// all subprojects
|
||||
mv.visitLdcInsn("dd-");
|
||||
mv.visitMethodInsn(
|
||||
Opcodes.INVOKEVIRTUAL,
|
||||
"java/lang/String",
|
||||
"startsWith",
|
||||
"(Ljava/lang/String;)Z",
|
||||
false);
|
||||
mv.visitJumpInsn(Opcodes.IFEQ, originalMethodBody);
|
||||
mv.visitTypeInsn(Opcodes.NEW, Utils.getInternalName(loggerClassName));
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitLdcInsn("datadog-logger");
|
||||
mv.visitMethodInsn(
|
||||
Opcodes.INVOKESPECIAL,
|
||||
Utils.getInternalName(loggerClassName),
|
||||
"<init>",
|
||||
"(Ljava/lang/String;)V",
|
||||
false);
|
||||
mv.visitInsn(Opcodes.ARETURN);
|
||||
mv.visitLabel(originalMethodBody);
|
||||
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
|
||||
super.visitCode();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
return mv;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
import datadog.trace.agent.test.AgentTestRunner
|
||||
|
||||
import java.util.logging.Logger
|
||||
|
||||
class LoggerPatchTest extends AgentTestRunner {
|
||||
def "datadog threads receive custom logger"() {
|
||||
setup:
|
||||
String threadName = Thread.currentThread().getName()
|
||||
Thread.currentThread().setName("dd-test")
|
||||
Logger log = Logger.getLogger("foobar")
|
||||
|
||||
expect:
|
||||
log.getName() == "datadog-logger"
|
||||
|
||||
cleanup:
|
||||
Thread.currentThread().setName(threadName)
|
||||
}
|
||||
|
||||
def "normal threads can reach the normal logger"() {
|
||||
setup:
|
||||
Logger log = Logger.getLogger("foobar")
|
||||
|
||||
expect:
|
||||
log.getName() == "foobar"
|
||||
}
|
||||
}
|
|
@ -50,7 +50,6 @@ include ':dd-java-agent:instrumentation:jdbc'
|
|||
include ':dd-java-agent:instrumentation:jedis-1.4'
|
||||
include ':dd-java-agent:instrumentation:jetty-8'
|
||||
include ':dd-java-agent:instrumentation:jms'
|
||||
include ':dd-java-agent:instrumentation:jre-logging'
|
||||
include ':dd-java-agent:instrumentation:jsp-2.3'
|
||||
include ':dd-java-agent:instrumentation:kafka-clients-0.11'
|
||||
include ':dd-java-agent:instrumentation:kafka-streams-0.11'
|
||||
|
|
Loading…
Reference in New Issue