/** * VMware Continuent Tungsten Replicator * Copyright (C) 2015 VMware, Inc. 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. * 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. * * Initial developer(s): * Contributor(s): */ package com.continuent.tungsten.common.utils; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.util.Map; import java.util.TreeMap; import java.util.concurrent.atomic.AtomicBoolean; import org.apache.log4j.Level; import org.apache.log4j.Logger; public class TraceVectorManager { static private Logger logger = Logger.getLogger(TraceVectorManager.class); private AtomicBoolean enabled = new AtomicBoolean( false); private AtomicBoolean autoDisable = new AtomicBoolean( true); private Map<TraceVectorComponent, TraceVectorInstances> vectorsByComponent = new TreeMap<TraceVectorComponent, TraceVectorInstances>(); /** * Trace commands */ public static final String TRACE_METHOD_TRACE = "trace"; public static final String TRACE_METHOD_TRACE_IS_ENABLED = "traceIsEnabled"; public static final String TRACE_METHOD_GLOBAL_ENABLE = "traceEnable"; public static final String TRACE_METHOD_LIST = "traceList"; public static final String TRACE_METHOD_RESET = "traceReset"; public static final String TRACE_METHOD_AUTO_DISABLE = "traceAutoDisable"; /** * Trace command args */ public static final String TRACE_ARG_VECTOR_PATH = "vectorPath"; public static final String TRACE_ARG_ENABLE_FLAG = "enableFlag"; public void clear() { vectorsByComponent.clear(); } public String reset() { traceEnable(false); autoDisable.set(true); for (TraceVectorInstances instances : vectorsByComponent.values()) { instances.reset(); } return list(); } private void register(TraceVectorComponent component) { TraceVectorInstances instances = vectorsByComponent.get(component); if (instances == null) { vectorsByComponent.put(component, new TraceVectorInstances( component)); } } public void add(TraceVectorComponent component, String category, int target, String description) throws Exception { TraceVectorInstances instances = vectorsByComponent.get(component); if (instances == null) { register(component); instances = vectorsByComponent.get(component); } TraceVector vector = instances.add(category, target, description); if (logger.isDebugEnabled()) logger.debug("Added new vector: " + vector); } public void add(TraceVectorComponent component, Class<?> clazz, int target, String description) throws Exception { add(component, clazz.getSimpleName(), target, description); } public void traceEnable(boolean enableFlag) { enabled.set(enableFlag); logger.info("Global tracing is now " + (enableFlag ? "enabled" : "disabled")); } public void traceAutoDisable(boolean enableFlag) { autoDisable.set(enableFlag); logger.info("Automatic disable of trace vectors is now " + (enableFlag ? "enabled" : "disabled")); } public boolean isEnabled(TraceVectorComponent component, Class<?> clazz, int target) { return isEnabled(component, clazz.getSimpleName(), target); } public boolean isEnabled(TraceVectorComponent component, String category, int target) { if (enabled.get() == false) return false; TraceVectorInstances instances = vectorsByComponent.get(component); if (instances == null) { return false; } boolean isEnabled = instances.isEnabled(category, target); if (isEnabled) { CLUtils.println(String.format("VECTOR FIRING %s: %s", autoDisable.get() ? "ONCE" : "ALWAYS", instances.getTrace(category, target))); if (autoDisable.get() == true) { instances.enable(category, target, false); } } return isEnabled; } public boolean isEnabled(String vectorPath) throws Exception { return isEnabled(TraceVectorArgs.getArgs(vectorPath)); } private boolean isEnabled(TraceVectorArgs args) throws Exception { return isEnabled(args.getComponent(), args.getCategory(), args.getTarget()); } private TraceVector enable(TraceVectorComponent component, String category, int target, boolean enableFlag) { TraceVectorInstances instances = vectorsByComponent.get(component); if (instances == null) { return new TraceVector(); } TraceVector vector = instances.enable(category, target, enableFlag); logger.info(String.format("SET %s", vector)); return vector; } public String enable(String vectorPath, boolean enableFlag) throws Exception { TraceVector vector = enable(TraceVectorArgs.getArgs(vectorPath), enableFlag); return String.format("%s\n%s", describe(), vector.toString()); } private TraceVector enable(TraceVectorArgs args, boolean enableFlag) throws Exception { return enable(args.getComponent(), args.getCategory(), args.getTarget(), enableFlag); } public void set(TraceVectorComponent component, String category, int target) throws Exception { enable(component, category, target, true); } public void set(String vectorPath) throws Exception { enable(vectorPath, true); } public void clear(String vectorPath) throws Exception { enable(vectorPath, false); } public void clear(TraceVectorComponent component, String category, int target) throws Exception { enable(component, category, target, false); } public TraceVector getTrace(TraceVectorComponent component, String category, int target) { TraceVectorInstances instances = vectorsByComponent.get(component); if (instances == null) { return new TraceVector(); } return instances.getTrace(category, target); } public String describe() { return (String.format("VECTOR MANAGER(%s)\nAUTO DISABLE(%s)", enabled.get() ? "ON" : "OFF", autoDisable.get() ? "ON" : "OFF")); } public String list() { return list(true, true); } public String list(boolean listEnabled, boolean listDisabled) { StringBuilder builder = new StringBuilder(); builder.append(describe()).append("\n"); for (TraceVectorComponent component : TraceVectorComponent.values()) { TraceVectorInstances instances = vectorsByComponent.get(component); if (instances == null) { continue; } builder.append(instances.list(listEnabled, listDisabled)); } return builder.toString(); } public void setLogLevel(Level level) { logger.setLevel(level); } public boolean parseBoolean(String boolVal) { if (boolVal.equalsIgnoreCase("on") || boolVal.equalsIgnoreCase("true")) return true; return false; } /** * This method populates the local trace vector manager by using the * TraceVectorArgDesc annotations that it finds on a given class * * @param clazz annotated class */ public void importVectors(Class<?> clazz) { Field fields[] = clazz.getDeclaredFields(); for (int i = 0; i < fields.length; i++) { Field field = fields[i]; Annotation annotation = field .getAnnotation(TraceVectorArgDesc.class); if (annotation == null) continue; TraceVectorArgDesc argDesc = (TraceVectorArgDesc) annotation; try { int target = field.getInt(field); add(argDesc.component(), argDesc.category(), target, argDesc.description()); } catch (Exception e) { logger.warn(String.format( "Failed to add vector for field '%s'", field.getName())); } } } public String getVectorDescription(Class<?> clazz, TraceVectorComponent component, String category, int target) { Field fields[] = clazz.getDeclaredFields(); for (int i = 0; i < fields.length; i++) { Field field = fields[i]; Annotation annotation = field .getAnnotation(TraceVectorArgDesc.class); if (annotation == null) continue; TraceVectorArgDesc argDesc = (TraceVectorArgDesc) annotation; int annotationTarget = -1; try { target = field.getInt(field); } catch (Exception e) { return String.format(String.format("TRACE VECTOR: %s/%s/%s", component, category, target)); } if (argDesc.component() == component && argDesc.category().equalsIgnoreCase(category) && annotationTarget == target) { return argDesc.description(); } } return String.format(String.format("TRACE VECTOR: %s/%s/%s", component, category, target)); } }