Search in sources :

Example 1 with Instrumentation

use of com.newrelic.agent.bridge.Instrumentation in project newrelic-java-agent by newrelic.

the class TraceClassVisitor method visitMethod.

@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
    MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
    // skip bridge methods. Tracing will occur on impl method.
    if ((access & Opcodes.ACC_BRIDGE) != 0) {
        /*
             * Some versions of the Agent (mid 3.20.* -> low 3.30.*) had a bug here that caused us to trace bridge
             * methods, resulting in double counting of @Trace'd methods. This bug only affected late versions of JDK7
             * and all versions of JDK8 due to annotations being automatically copied by the JVM over to bridge methods.
             */
        return mv;
    }
    Method method = new Method(name, desc);
    if (traceInfo.getIgnoreTransactionMethods().contains(method)) {
        instrumentationContext.markAsModified();
        return new AdviceAdapter(WeaveUtils.ASM_API_LEVEL, mv, access, name, desc) {

            @Override
            protected void onMethodEnter() {
                BridgeUtils.getCurrentTransaction(this);
                BytecodeGenProxyBuilder.newBuilder(Transaction.class, this, true).build().ignore();
            }
        };
    } else {
        final TraceDetails trace = traceInfo.getTraceAnnotations().get(method);
        if (null != trace) {
            tracedMethods.add(method);
            PointCut pointCut = instrumentationContext.getOldStylePointCut(method);
            if (pointCut == null) {
                boolean custom = trace.isCustom();
                boolean noticeSql = noticeSqlMethods.contains(method);
                if (trace.excludeFromTransactionTrace() && trace.isLeaf()) {
                    mv = new FlyweightTraceMethodVisitor(className, mv, access, name, desc, trace, instrumentationContext.getClassBeingRedefined());
                } else {
                    mv = new TraceMethodVisitor(className, mv, access, name, desc, trace, custom, noticeSql, instrumentationContext.getClassBeingRedefined());
                    if (!trace.getParameterAttributeNames().isEmpty()) {
                        for (ParameterAttributeName attr : trace.getParameterAttributeNames()) {
                            final ParameterAttributeName param = attr;
                            if (param.getMethodMatcher().matches(access, name, desc, null)) {
                                try {
                                    final Type type = method.getArgumentTypes()[param.getIndex()];
                                    if (type.getSort() == Type.ARRAY) {
                                        Agent.LOG.log(Level.FINE, "Unable to record an attribute value for {0}.{1} because it is an array", className, method);
                                    } else {
                                        mv = new AdviceAdapter(WeaveUtils.ASM_API_LEVEL, mv, access, name, desc) {

                                            @Override
                                            protected void onMethodEnter() {
                                                super.getStatic(BridgeUtils.AGENT_BRIDGE_TYPE, BridgeUtils.PUBLIC_API_FIELD_NAME, BridgeUtils.PUBLIC_API_TYPE);
                                                PublicApi api = BytecodeGenProxyBuilder.newBuilder(PublicApi.class, this, false).build();
                                                push(param.getAttributeName());
                                                loadArg(param.getIndex());
                                                // if this is a primitive value we need to box it to an object
                                                if (type.getSort() != Type.OBJECT) {
                                                    box(type);
                                                }
                                                Label objectLabel = newLabel();
                                                Label skipLabel = newLabel();
                                                Label popStackLabel = newLabel();
                                                // dup the value for null check
                                                dup();
                                                ifNull(popStackLabel);
                                                // dup the value for instanceOf check
                                                dup();
                                                instanceOf(Type.getType(Number.class));
                                                ifZCmp(EQ, objectLabel);
                                                // if this is a number, cast it to a number and call the
                                                // addCustomParameter api that takes a number
                                                checkCast(Type.getType(Number.class));
                                                api.addCustomParameter("", 0);
                                                goTo(skipLabel);
                                                visitLabel(objectLabel);
                                                // otherwise, it's a non-null object so call toString
                                                invokeVirtual(Type.getType(Object.class), new Method("toString", Type.getType(String.class), new Type[0]));
                                                api.addCustomParameter("", "");
                                                goTo(skipLabel);
                                                // the values originally on the stack won't be consumed by either
                                                // of the api calls above if the attribute was null
                                                visitLabel(popStackLabel);
                                                pop();
                                                pop();
                                                pop();
                                                visitLabel(skipLabel);
                                            }
                                        };
                                    }
                                } catch (ArrayIndexOutOfBoundsException e) {
                                    Agent.LOG.log(Level.FINEST, e, e.toString());
                                }
                            }
                        }
                    }
                    if (trace.rollupMetricName().length > 0) {
                        final int cacheId = AgentBridge.instrumentation.addToObjectCache(trace.rollupMetricName());
                        mv = new AdviceAdapter(WeaveUtils.ASM_API_LEVEL, mv, access, name, desc) {

                            @Override
                            protected void onMethodEnter() {
                                getStatic(BridgeUtils.TRACED_METHOD_TYPE, BridgeUtils.CURRENT_TRANSACTION_FIELD_NAME, BridgeUtils.TRACED_METHOD_TYPE);
                                super.getStatic(BridgeUtils.AGENT_BRIDGE_TYPE, BridgeUtils.INSTRUMENTATION_FIELD_NAME, BridgeUtils.INSTRUMENTATION_TYPE);
                                Instrumentation instrumentation = BytecodeGenProxyBuilder.newBuilder(Instrumentation.class, this, true).build();
                                instrumentation.getCachedObject(cacheId);
                                super.checkCast(Type.getType(String[].class));
                                TracedMethod tracedMethod = BytecodeGenProxyBuilder.newBuilder(TracedMethod.class, this, false).build();
                                tracedMethod.setRollupMetricNames((String[]) null);
                            }
                        };
                    }
                    if (TransactionName.isSimpleTransactionName(trace.transactionName())) {
                        mv = new AdviceAdapter(WeaveUtils.ASM_API_LEVEL, mv, access, name, desc) {

                            @Override
                            protected void onMethodEnter() {
                                TracedMethod tracedMethod = BytecodeGenProxyBuilder.newBuilder(TracedMethod.class, this, true).build();
                                getStatic(BridgeUtils.TRACED_METHOD_TYPE, BridgeUtils.CURRENT_TRANSACTION_FIELD_NAME, BridgeUtils.TRACED_METHOD_TYPE);
                                tracedMethod.nameTransaction(trace.transactionName().transactionNamePriority);
                            }
                        };
                    } else if (trace.transactionName() != null) {
                        mv = new AdviceAdapter(WeaveUtils.ASM_API_LEVEL, mv, access, name, desc) {

                            @Override
                            protected void onMethodEnter() {
                                BridgeUtils.getCurrentTransaction(this);
                                Transaction transaction = BytecodeGenProxyBuilder.newBuilder(Transaction.class, this, true).build();
                                TransactionName transactionName = trace.transactionName();
                                transaction.setTransactionName(transactionName.transactionNamePriority, transactionName.override, transactionName.category, transactionName.path);
                                // the method returns a boolean. Discard it.
                                pop();
                            }
                        };
                    }
                    if (trace.isWebTransaction()) {
                        mv = new AdviceAdapter(WeaveUtils.ASM_API_LEVEL, mv, access, name, desc) {

                            @Override
                            protected void onMethodExit(int opcode) {
                                getStatic(BridgeUtils.TRANSACTION_TYPE, BridgeUtils.CURRENT_TRANSACTION_FIELD_NAME, BridgeUtils.TRANSACTION_TYPE);
                                BytecodeGenProxyBuilder.newBuilder(Transaction.class, this, true).build().convertToWebTransaction();
                            }
                        };
                    }
                    if (null != trace.metricPrefix()) {
                        mv = new AdviceAdapter(WeaveUtils.ASM_API_LEVEL, mv, access, name, desc) {

                            @Override
                            protected void onMethodExit(int opcode) {
                                // write: AgentBridge.getAgent().getTracedMethod.setMetricPrefix("usersPrefix")
                                this.invokeStatic(BridgeUtils.AGENT_BRIDGE_TYPE, new Method(BridgeUtils.AGENT_BRIDGE_GET_AGENT_METHOD, BridgeUtils.AGENT_BRIDGE_AGENT_TYPE, new Type[0]));
                                this.invokeVirtual(BridgeUtils.AGENT_BRIDGE_AGENT_TYPE, new Method(BridgeUtils.GET_TRACED_METHOD_METHOD_NAME, BridgeUtils.TRACED_METHOD_TYPE, new Type[0]));
                                BytecodeGenProxyBuilder.newBuilder(TracedMethod.class, this, true).build().setCustomMetricPrefix(trace.metricPrefix());
                            }
                        };
                    }
                }
                instrumentationContext.addTimedMethods(method);
            } else {
                Agent.LOG.warning(className + '.' + method + " is matched to trace, but it was already instrumented by " + pointCut.toString());
            }
        }
        if (traceInfo.getIgnoreApdexMethods().contains(method)) {
            instrumentationContext.markAsModified();
            mv = new AdviceAdapter(WeaveUtils.ASM_API_LEVEL, mv, access, name, desc) {

                @Override
                protected void onMethodEnter() {
                    invokeStatic(BridgeUtils.NEW_RELIC_API_TYPE, TraceMethodVisitor.IGNORE_APDEX_METHOD);
                }
            };
        }
    }
    return mv;
}
Also used : Label(org.objectweb.asm.Label) Instrumentation(com.newrelic.agent.bridge.Instrumentation) TracedMethod(com.newrelic.agent.bridge.TracedMethod) Method(org.objectweb.asm.commons.Method) MethodVisitor(org.objectweb.asm.MethodVisitor) PointCut(com.newrelic.agent.instrumentation.PointCut) AdviceAdapter(org.objectweb.asm.commons.AdviceAdapter) Type(org.objectweb.asm.Type) Transaction(com.newrelic.agent.bridge.Transaction) TracedMethod(com.newrelic.agent.bridge.TracedMethod) PublicApi(com.newrelic.agent.bridge.PublicApi)

Example 2 with Instrumentation

use of com.newrelic.agent.bridge.Instrumentation in project newrelic-java-agent by newrelic.

the class TraceMethodVisitor method startTracer.

/**
 * Tracer t = null;<br/>
 * t = AgentBridge.instrumentation.createTracer(...);
 */
protected void startTracer() {
    visitInsn(Opcodes.ACONST_NULL);
    storeLocal(tracerLocal, TraceMethodVisitor.TRACER_TYPE);
    visitLabel(startFinallyLabel);
    Label start = new Label();
    Label end = new Label();
    Label handler = new Label();
    visitTryCatchBlock(start, end, handler, TraceMethodVisitor.THROWABLE_TYPE.getInternalName());
    visitLabel(start);
    super.getStatic(BridgeUtils.AGENT_BRIDGE_TYPE, BridgeUtils.INSTRUMENTATION_FIELD_NAME, BridgeUtils.INSTRUMENTATION_TYPE);
    String metricName = traceDetails.getFullMetricName(className, method.getName());
    String tracerFactory = traceDetails.tracerFactoryName();
    BytecodeGenProxyBuilder<Instrumentation> builder = BytecodeGenProxyBuilder.newBuilder(Instrumentation.class, this, true);
    Variables loader = builder.getVariables();
    Instrumentation instrumentation = builder.build();
    if (tracerFactory == null) {
        int tracerFlags = getTracerFlags();
        if (noticeSql) {
            instrumentation.createSqlTracer(loader.loadThis(this.access), signatureId, metricName, tracerFlags);
        } else {
            instrumentation.createTracer(loader.loadThis(this.access), signatureId, metricName, tracerFlags);
        }
    } else {
        Object[] loadArgs = loader.load(Object[].class, new Runnable() {

            @Override
            public void run() {
                loadArgArray();
            }
        });
        instrumentation.createTracer(loader.loadThis(this.access), signatureId, traceDetails.dispatcher(), metricName, tracerFactory, loadArgs);
    }
    storeLocal(tracerLocal, TraceMethodVisitor.TRACER_TYPE);
    goTo(end);
    visitLabel(handler);
    // toss the exception on the stack
    pop();
    visitLabel(end);
}
Also used : Variables(com.newrelic.agent.util.asm.Variables) Label(org.objectweb.asm.Label) Instrumentation(com.newrelic.agent.bridge.Instrumentation)

Aggregations

Instrumentation (com.newrelic.agent.bridge.Instrumentation)2 Label (org.objectweb.asm.Label)2 PublicApi (com.newrelic.agent.bridge.PublicApi)1 TracedMethod (com.newrelic.agent.bridge.TracedMethod)1 Transaction (com.newrelic.agent.bridge.Transaction)1 PointCut (com.newrelic.agent.instrumentation.PointCut)1 Variables (com.newrelic.agent.util.asm.Variables)1 MethodVisitor (org.objectweb.asm.MethodVisitor)1 Type (org.objectweb.asm.Type)1 AdviceAdapter (org.objectweb.asm.commons.AdviceAdapter)1 Method (org.objectweb.asm.commons.Method)1