Search in sources :

Example 1 with PointCut

use of com.newrelic.agent.instrumentation.PointCut in project newrelic-java-agent by newrelic.

the class FinalClassTransformer method addModifiedMethodAnnotation.

private ClassVisitor addModifiedMethodAnnotation(ClassVisitor cv, final InstrumentationContext context, final ClassLoader loader) {
    return new ClassVisitor(WeaveUtils.ASM_API_LEVEL, cv) {

        private String className;

        @Override
        public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
            className = name;
            super.visit(version, access, name, signature, superName, interfaces);
        }

        /**
         * @see InstrumentedMethod#instrumentationTypes()
         * @see InstrumentedMethod#instrumentationNames()
         * @see InstrumentedMethod#dispatcher()
         */
        @Override
        public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
            MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
            Method method = new Method(name, desc);
            if (context.isModified(method)) {
                if (loader != null) {
                    TraceDetails traceDetails = context.getTraceInformation().getTraceAnnotations().get(method);
                    boolean dispatcher = false;
                    if (traceDetails != null) {
                        dispatcher = traceDetails.dispatcher();
                    }
                    AnnotationVisitor av = mv.visitAnnotation(Type.getDescriptor(InstrumentedMethod.class), true);
                    av.visit("dispatcher", dispatcher);
                    List<String> instrumentationNames = new ArrayList<>();
                    List<InstrumentationType> instrumentationTypes = new ArrayList<>();
                    Level logLevel = Level.FINER;
                    if (traceDetails != null) {
                        if (traceDetails.instrumentationSourceNames() != null) {
                            instrumentationNames.addAll(traceDetails.instrumentationSourceNames());
                        }
                        if (traceDetails.instrumentationTypes() != null) {
                            for (InstrumentationType type : traceDetails.instrumentationTypes()) {
                                instrumentationTypes.add(type);
                            }
                        }
                        if (traceDetails.isCustom()) {
                            logLevel = Level.FINE;
                        }
                    }
                    PointCut pointCut = context.getOldStylePointCut(method);
                    if (pointCut != null) {
                        instrumentationNames.add(pointCut.getClass().getName());
                        instrumentationTypes.add(InstrumentationType.Pointcut);
                    }
                    Collection<String> instrumentationPackages = context.getMergeInstrumentationPackages(method);
                    if (instrumentationPackages != null && !instrumentationPackages.isEmpty()) {
                        for (String current : instrumentationPackages) {
                            instrumentationNames.add(current);
                            instrumentationTypes.add(InstrumentationType.WeaveInstrumentation);
                        }
                    }
                    if (instrumentationNames.size() == 0) {
                        instrumentationNames.add("Unknown");
                        Agent.LOG.finest("Unknown instrumentation source for " + className + '.' + method);
                    }
                    if (instrumentationTypes.size() == 0) {
                        instrumentationTypes.add(InstrumentationType.Unknown);
                        Agent.LOG.finest("Unknown instrumentation type for " + className + '.' + method);
                    }
                    AnnotationVisitor visitArrayName = av.visitArray("instrumentationNames");
                    for (String current : instrumentationNames) {
                        // the key on this is ignored
                        visitArrayName.visit("", current);
                    }
                    visitArrayName.visitEnd();
                    AnnotationVisitor visitArrayType = av.visitArray("instrumentationTypes");
                    for (InstrumentationType type : instrumentationTypes) {
                        // the key on this is ignored
                        visitArrayType.visitEnum("", Type.getDescriptor(InstrumentationType.class), type.toString());
                    }
                    visitArrayType.visitEnd();
                    av.visitEnd();
                    if (Agent.LOG.isLoggable(logLevel)) {
                        Agent.LOG.log(logLevel, "Instrumented " + Type.getObjectType(className).getClassName() + '.' + method + ", " + instrumentationTypes + ", " + instrumentationNames);
                    }
                }
            }
            return mv;
        }
    };
}
Also used : InstrumentationType(com.newrelic.agent.instrumentation.InstrumentationType) ArrayList(java.util.ArrayList) TraceDetails(com.newrelic.agent.instrumentation.tracing.TraceDetails) InstrumentedMethod(com.newrelic.agent.instrumentation.InstrumentedMethod) ClassVisitor(org.objectweb.asm.ClassVisitor) Method(org.objectweb.asm.commons.Method) WeavedMethod(com.newrelic.agent.instrumentation.WeavedMethod) InstrumentedMethod(com.newrelic.agent.instrumentation.InstrumentedMethod) MethodVisitor(org.objectweb.asm.MethodVisitor) PointCut(com.newrelic.agent.instrumentation.PointCut) AnnotationVisitor(org.objectweb.asm.AnnotationVisitor) Level(java.util.logging.Level)

Example 2 with PointCut

use of com.newrelic.agent.instrumentation.PointCut in project newrelic-java-agent by newrelic.

the class ErrorServiceImpl method getEnabledErrorHandlerPointCuts.

public static Collection<? extends PointCut> getEnabledErrorHandlerPointCuts() {
    AgentConfig config = ServiceFactory.getConfigService().getDefaultAgentConfig();
    Object exceptionHandlers = config.getErrorCollectorConfig().getExceptionHandlers();
    Collection<PointCut> pointcuts = new ArrayList<>();
    if (exceptionHandlers instanceof Collection<?>) {
        for (Object sigObject : ((Collection<?>) exceptionHandlers)) {
            if (sigObject instanceof ExceptionHandlerSignature) {
                ExceptionHandlerSignature exHandlerSig = (ExceptionHandlerSignature) sigObject;
                String msg = MessageFormat.format("Instrumenting exception handler signature {0}", exHandlerSig.toString());
                Agent.LOG.finer(msg);
                ExceptionHandlerPointCut pc = new ExceptionHandlerPointCut(exHandlerSig);
                if (pc.isEnabled()) {
                    pointcuts.add(pc);
                }
            } else if (sigObject instanceof String) {
                ClassMethodSignature signature = PointCutFactory.parseClassMethodSignature(sigObject.toString());
                try {
                    ExceptionHandlerSignature exHandlerSig = new ExceptionHandlerSignature(signature);
                    Agent.LOG.info(MessageFormat.format("Instrumenting exception handler signature {0}", exHandlerSig.toString()));
                    ExceptionHandlerPointCut pc = new ExceptionHandlerPointCut(exHandlerSig);
                    if (pc.isEnabled()) {
                        pointcuts.add(pc);
                    }
                } catch (InvalidMethodDescriptor e) {
                    Agent.LOG.severe(MessageFormat.format("Unable to instrument exception handler {0} : {1}", sigObject.toString(), e.toString()));
                }
            } else if (sigObject instanceof Exception) {
                Agent.LOG.severe(MessageFormat.format("Unable to instrument exception handler : {0}", sigObject.toString()));
            }
        }
    }
    return pointcuts;
}
Also used : PointCut(com.newrelic.agent.instrumentation.PointCut) AgentConfig(com.newrelic.agent.config.AgentConfig) ClassMethodSignature(com.newrelic.agent.tracers.ClassMethodSignature) ArrayList(java.util.ArrayList) Collection(java.util.Collection) InvalidMethodDescriptor(com.newrelic.agent.instrumentation.methodmatchers.InvalidMethodDescriptor)

Example 3 with PointCut

use of com.newrelic.agent.instrumentation.PointCut 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)

Aggregations

PointCut (com.newrelic.agent.instrumentation.PointCut)3 ArrayList (java.util.ArrayList)2 MethodVisitor (org.objectweb.asm.MethodVisitor)2 Method (org.objectweb.asm.commons.Method)2 Instrumentation (com.newrelic.agent.bridge.Instrumentation)1 PublicApi (com.newrelic.agent.bridge.PublicApi)1 TracedMethod (com.newrelic.agent.bridge.TracedMethod)1 Transaction (com.newrelic.agent.bridge.Transaction)1 AgentConfig (com.newrelic.agent.config.AgentConfig)1 InstrumentationType (com.newrelic.agent.instrumentation.InstrumentationType)1 InstrumentedMethod (com.newrelic.agent.instrumentation.InstrumentedMethod)1 WeavedMethod (com.newrelic.agent.instrumentation.WeavedMethod)1 InvalidMethodDescriptor (com.newrelic.agent.instrumentation.methodmatchers.InvalidMethodDescriptor)1 TraceDetails (com.newrelic.agent.instrumentation.tracing.TraceDetails)1 ClassMethodSignature (com.newrelic.agent.tracers.ClassMethodSignature)1 Collection (java.util.Collection)1 Level (java.util.logging.Level)1 AnnotationVisitor (org.objectweb.asm.AnnotationVisitor)1 ClassVisitor (org.objectweb.asm.ClassVisitor)1 Label (org.objectweb.asm.Label)1