All Downloads are FREE. Search and download functionalities are using the official Maven repository.

software.amazon.disco.agent.interception.InterceptionInstaller Maven / Gradle / Ivy

There is a newer version: 0.13.0
Show newest version
/*
 * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 *   Licensed under the Apache License, Version 2.0 (the "License").
 *   You may not use this file except in compliance with the License.
 *   A copy of the License is located at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   or in the "license" file accompanying this file. This file is distributed
 *   on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 *   express or implied. See the License for the specific language governing
 *   permissions and limitations under the License.
 */

package software.amazon.disco.agent.interception;

import software.amazon.disco.agent.config.AgentConfig;
import software.amazon.disco.agent.logging.LogManager;
import software.amazon.disco.agent.logging.Logger;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;

import java.lang.instrument.Instrumentation;
import java.util.Set;
import java.util.function.Supplier;

import static net.bytebuddy.matcher.ElementMatchers.*;

/**
 * Class to control installation of interceptions/advice on target methods.
 */
public class InterceptionInstaller {
    private static final InterceptionInstaller INSTANCE = new InterceptionInstaller(new DefaultAgentBuilderFactory());
    private static final Logger log = LogManager.getLogger(InterceptionInstaller.class);
    private final Supplier agentBuilderFactory;

    /**
     * Non-public constructor for singleton semantics. Package-private for tests
     */
    InterceptionInstaller(Supplier agentBuilderFactory) {
        this.agentBuilderFactory = agentBuilderFactory;
    }

    /**
     * Singleton access
     * @return the InterceptionInstaller singleton
     */
    public static InterceptionInstaller getInstance() {
        return INSTANCE;
    }

    /**
     * Sets up the interceptions as configured by the Agent, passing in a list of Installables.
     * @param instrumentation - the Instrumentation instance, as passed to 'premain'
     * @param installables - the collection of Installable hooks passed in from the Agent
     * @param config - the command line config passed into the agent.
     * @param customIgnoreMatcher extra ignore rules to be OR'd with the default
     */
    public void install(Instrumentation instrumentation, Set installables, AgentConfig config,
                        ElementMatcher.Junction customIgnoreMatcher) {
        final ElementMatcher ignoreMatcher = createIgnoreMatcher(customIgnoreMatcher);

        for (Installable installable: installables) {
            //We create a new Agent for each Installable, otherwise their matching rules can
            //compete with each other.
            AgentBuilder agentBuilder = agentBuilderFactory.get()
                    .ignore(ignoreMatcher);

            //The Interception listener is expensive during class loading, and limited value most of the time
            if (config.isExtraverbose()) {
                agentBuilder = agentBuilder.with(InterceptionListener.create(installable));
            }

            agentBuilder = config.getAgentBuilderTransformer().apply(agentBuilder, installable);

            log.info("DiSCo(Core) attempting to install "+installable.getClass().getName());
            agentBuilder = installable.install(agentBuilder);

            if (agentBuilder != null) {
                agentBuilder.installOn(instrumentation);
            }
        }
    }

    /**
     * Create a matcher to ignore low-level and otherwise problematic namespaces.
     *
     * @param customIgnoreMatcher an extra ignore rule to be OR'd with the default
     * @return - a matcher suitable for passing to AgentBuilder#ignore
     */
    public static ElementMatcher.Junction createIgnoreMatcher(ElementMatcher.Junction customIgnoreMatcher) {
        ElementMatcher.Junction excludedNamespaces =
            //low-level pieces of the JDK and runtime
            nameStartsWith("sun.")
            .or(nameStartsWith("com.sun."))
            .or(nameStartsWith("jdk."))

            //3rd party libraries
            .or(nameStartsWith("org.jacoco."))
            .or(nameStartsWith("org.junit."))
            .or(nameStartsWith("org.aspectj."))

            //disco itself and its internals
            .or(nameStartsWith("software.amazon.disco.agent.")
                .and(not(nameStartsWith("software.amazon.disco.agent.integtest."))));

        return excludedNamespaces.or(customIgnoreMatcher);

    }

    /**
     * A default Factory for creation of AgentBuilder instances
     */
    private static class DefaultAgentBuilderFactory implements Supplier {
        /**
         * Factory method to produce a real AgentBuilder
         * @return an AgentBuilder in the default case
         */
        @Override
        public AgentBuilder get() {
            return new AgentBuilder.Default();
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy