/**
* Copyright 2014 SAP AG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License 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 org.aim.mainagent;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.aim.api.exceptions.InstrumentationException;
import org.aim.description.InstrumentationDescription;
import org.aim.description.InstrumentationEntity;
import org.aim.description.builder.InstrumentationDescriptionBuilder;
import org.aim.description.builder.InstrumentationEntityBuilder;
import org.aim.description.builder.RestrictionBuilder;
import org.aim.description.restrictions.Restriction;
import org.aim.description.scopes.APIScope;
import org.aim.description.scopes.ConstructorScope;
import org.aim.description.scopes.CustomScope;
import org.aim.description.scopes.MethodScope;
import org.aim.description.scopes.MethodsEnclosingScope;
import org.aim.description.scopes.TraceScope;
import org.aim.logging.AIMLogger;
import org.aim.logging.AIMLoggerFactory;
import org.aim.mainagent.probes.IncrementalInstrumentationProbe;
/**
* Instrumentor for traces.
*
* @author Alexander Wert
*
*/
public final class TraceInstrumentor implements IInstrumentor {
private static final AIMLogger LOGGER = AIMLoggerFactory.getLogger(TraceInstrumentor.class);
private static TraceInstrumentor instance;
/**
*
* @return singleton instance
*/
public static synchronized TraceInstrumentor getInstance() {
if (instance == null) {
instance = new TraceInstrumentor();
}
return instance;
}
private final Map<Long, Set<String>> incrementalInstrumentationProbes;
private final Map<Long, Restriction> incrementalInstrumentationRestrictions;
private final Set<String> instrumentationFlags;
private volatile long idCounter = 0;
private TraceInstrumentor() {
incrementalInstrumentationProbes = new HashMap<>();
incrementalInstrumentationRestrictions = new HashMap<>();
instrumentationFlags = new HashSet<>();
}
/**
* Does an incremental step in instrumentation.
*
* @param methodName
* method to instrument
* @param jobID
* incremental instrumentation job id identifying the
* instrumentation details
*/
public void instrumentIncrementally(String methodName, long jobID) {
try {
String keyString = methodName + "__" + jobID;
if (!instrumentationFlags.contains(keyString)) {
LOGGER.info("Incrementally going to instrument method: {}", methodName);
InstrumentationDescriptionBuilder idBuilder = new InstrumentationDescriptionBuilder();
RestrictionBuilder<?> restrictionBuilder = idBuilder.newGlobalRestriction();
for (String inc : incrementalInstrumentationRestrictions.get(jobID).getPackageIncludes()) {
restrictionBuilder.includePackage(inc);
}
for (String exc : incrementalInstrumentationRestrictions.get(jobID).getPackageExcludes()) {
restrictionBuilder.excludePackage(exc);
}
for (int modifier : incrementalInstrumentationRestrictions.get(jobID).getModifierIncludes()) {
restrictionBuilder.includeModifier(modifier);
}
for (int modifier : incrementalInstrumentationRestrictions.get(jobID).getModifierExcludes()) {
restrictionBuilder.excludeModifier(modifier);
}
restrictionBuilder.restrictionDone();
InstrumentationEntityBuilder<MethodScope> ieBuilder = idBuilder.newMethodScopeEntityWithId(jobID,
methodName);
for (String probe : incrementalInstrumentationProbes.get(jobID)) {
ieBuilder.addProbe(probe);
ieBuilder.addProbe(IncrementalInstrumentationProbe.MODEL_PROBE);
}
ieBuilder.entityDone();
InstrumentationDescription instDescr = idBuilder.build();
AdaptiveInstrumentationFacade.getInstance().instrument(instDescr);
instrumentationFlags.add(keyString);
}
} catch (Throwable e) {
// Catch all exceptions and errors since this code is executed
// directly from the target application
LOGGER.error("Error during incremental instrumentation: {}", e);
}
}
@Override
public void instrument(InstrumentationDescription descr) throws InstrumentationException {
if (!descr.containsScopeType(TraceScope.class)) {
return;
}
for (InstrumentationEntity<TraceScope> instrumentationEntity : descr
.getInstrumentationEntities(TraceScope.class)) {
TraceScope tScope = instrumentationEntity.getScope();
long scopeId = idCounter++;
incrementalInstrumentationProbes.put(scopeId, instrumentationEntity.getProbesAsStrings());
Restriction restriction = new Restriction();
restriction.getPackageExcludes().addAll(descr.getGlobalRestriction().getPackageExcludes());
restriction.getPackageIncludes().addAll(descr.getGlobalRestriction().getPackageIncludes());
restriction.getModifierExcludes().addAll(descr.getGlobalRestriction().getModifierExcludes());
restriction.getModifierIncludes().addAll(descr.getGlobalRestriction().getModifierIncludes());
incrementalInstrumentationRestrictions.put(scopeId, restriction);
InstrumentationDescription extendedDescr = getExtendedInstrumentationDescription(descr, tScope,
instrumentationEntity, scopeId);
AdaptiveInstrumentationFacade.getInstance().instrument(extendedDescr);
}
}
@Override
public void undoInstrumentation() throws InstrumentationException {
incrementalInstrumentationProbes.clear();
incrementalInstrumentationRestrictions.clear();
instrumentationFlags.clear();
}
private InstrumentationDescription getExtendedInstrumentationDescription(InstrumentationDescription descr,
TraceScope tScope, InstrumentationEntity<TraceScope> eiEntity, Long scopeId)
throws InstrumentationException {
MethodsEnclosingScope initialScopes = tScope.getSubScope();
InstrumentationDescriptionBuilder idBuilder = new InstrumentationDescriptionBuilder();
RestrictionBuilder<?> restrictionBuilder = idBuilder.newGlobalRestriction();
for (String inc : descr.getGlobalRestriction().getPackageIncludes()) {
restrictionBuilder.includePackage(inc);
}
for (String exc : descr.getGlobalRestriction().getPackageExcludes()) {
restrictionBuilder.excludePackage(exc);
}
for (int modifier : descr.getGlobalRestriction().getModifierIncludes()) {
restrictionBuilder.includeModifier(modifier);
}
for (int modifier : descr.getGlobalRestriction().getModifierExcludes()) {
restrictionBuilder.excludeModifier(modifier);
}
restrictionBuilder.restrictionDone();
if (initialScopes instanceof MethodScope) {
buildMethodInstEntity(eiEntity, scopeId, idBuilder, initialScopes);
} else if (initialScopes instanceof ConstructorScope) {
buildConstructorInstEntity(eiEntity, scopeId, idBuilder, initialScopes);
} else if (initialScopes instanceof APIScope) {
buildAPIInstEntity(eiEntity, scopeId, idBuilder, initialScopes);
} else if (initialScopes instanceof CustomScope) {
buildCustomInstEntity(eiEntity, scopeId, idBuilder, initialScopes);
} else {
throw new InstrumentationException("Invalid sub scope type for full trace instrumentation scope: "
+ initialScopes.getClass().getName());
}
return idBuilder.build();
}
private void buildCustomInstEntity(InstrumentationEntity<TraceScope> eiEntity, Long scopeId,
InstrumentationDescriptionBuilder idBuilder, MethodsEnclosingScope iScope) {
CustomScope cScope = (CustomScope) iScope;
InstrumentationEntityBuilder<CustomScope> csBuilder = idBuilder.newCustomScopeEntityWithId(scopeId,
cScope.getScopeName());
csBuilder.addProbe(IncrementalInstrumentationProbe.MODEL_PROBE);
for (String probe : eiEntity.getProbesAsStrings()) {
csBuilder.addProbe(probe);
}
RestrictionBuilder<?> restrictionBuilder = csBuilder.newLocalRestriction();
for (String exclusion : eiEntity.getLocalRestriction().getPackageExcludes()) {
restrictionBuilder.excludePackage(exclusion);
}
for (String inclusion : eiEntity.getLocalRestriction().getPackageIncludes()) {
restrictionBuilder.includePackage(inclusion);
}
for (int modifier : eiEntity.getLocalRestriction().getModifierExcludes()) {
restrictionBuilder.excludeModifier(modifier);
}
for (int modifier : eiEntity.getLocalRestriction().getModifierIncludes()) {
restrictionBuilder.includeModifier(modifier);
}
restrictionBuilder.restrictionDone();
csBuilder.entityDone();
}
private void buildAPIInstEntity(InstrumentationEntity<TraceScope> eiEntity, Long scopeId,
InstrumentationDescriptionBuilder idBuilder, MethodsEnclosingScope iScope) {
APIScope apiScope = (APIScope) iScope;
InstrumentationEntityBuilder<APIScope> apisBuilder = idBuilder.newAPIScopeEntityWithId(scopeId,
apiScope.getApiName());
apisBuilder.addProbe(IncrementalInstrumentationProbe.MODEL_PROBE);
for (String probe : eiEntity.getProbesAsStrings()) {
apisBuilder.addProbe(probe);
}
RestrictionBuilder<?> restrictionBuilder = apisBuilder.newLocalRestriction();
for (String exclusion : eiEntity.getLocalRestriction().getPackageExcludes()) {
restrictionBuilder.excludePackage(exclusion);
}
for (String inclusion : eiEntity.getLocalRestriction().getPackageIncludes()) {
restrictionBuilder.includePackage(inclusion);
}
for (int modifier : eiEntity.getLocalRestriction().getModifierExcludes()) {
restrictionBuilder.excludeModifier(modifier);
}
for (int modifier : eiEntity.getLocalRestriction().getModifierIncludes()) {
restrictionBuilder.includeModifier(modifier);
}
restrictionBuilder.restrictionDone();
apisBuilder.entityDone();
}
private void buildConstructorInstEntity(InstrumentationEntity<TraceScope> eiEntity, Long scopeId,
InstrumentationDescriptionBuilder idBuilder, MethodsEnclosingScope iScope) {
ConstructorScope cScope = (ConstructorScope) iScope;
InstrumentationEntityBuilder<ConstructorScope> csBuilder = idBuilder.newConstructorScopeEntityWithId(scopeId,
cScope.getTargetClasses());
csBuilder.addProbe(IncrementalInstrumentationProbe.MODEL_PROBE);
for (String probe : eiEntity.getProbesAsStrings()) {
csBuilder.addProbe(probe);
}
RestrictionBuilder<?> restrictionBuilder = csBuilder.newLocalRestriction();
for (String exclusion : eiEntity.getLocalRestriction().getPackageExcludes()) {
restrictionBuilder.excludePackage(exclusion);
}
for (String inclusion : eiEntity.getLocalRestriction().getPackageIncludes()) {
restrictionBuilder.includePackage(inclusion);
}
for (int modifier : eiEntity.getLocalRestriction().getModifierExcludes()) {
restrictionBuilder.excludeModifier(modifier);
}
for (int modifier : eiEntity.getLocalRestriction().getModifierIncludes()) {
restrictionBuilder.includeModifier(modifier);
}
restrictionBuilder.restrictionDone();
csBuilder.entityDone();
}
private void buildMethodInstEntity(InstrumentationEntity<TraceScope> eiEntity, Long scopeId,
InstrumentationDescriptionBuilder idBuilder, MethodsEnclosingScope iScope) {
MethodScope mScope = (MethodScope) iScope;
InstrumentationEntityBuilder<MethodScope> msBuilder = idBuilder.newMethodScopeEntityWithId(scopeId,
mScope.getMethods());
msBuilder.addProbe(IncrementalInstrumentationProbe.MODEL_PROBE);
for (String probe : eiEntity.getProbesAsStrings()) {
msBuilder.addProbe(probe);
}
RestrictionBuilder<?> restrictionBuilder = msBuilder.newLocalRestriction();
for (String exclusion : eiEntity.getLocalRestriction().getPackageExcludes()) {
restrictionBuilder.excludePackage(exclusion);
}
for (String inclusion : eiEntity.getLocalRestriction().getPackageIncludes()) {
restrictionBuilder.includePackage(inclusion);
}
for (int modifier : eiEntity.getLocalRestriction().getModifierExcludes()) {
restrictionBuilder.excludeModifier(modifier);
}
for (int modifier : eiEntity.getLocalRestriction().getModifierIncludes()) {
restrictionBuilder.includeModifier(modifier);
}
restrictionBuilder.restrictionDone();
msBuilder.entityDone();
}
}