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

com.orbitz.monitoring.api.engine.StackBasedInheritableStrategy Maven / Gradle / Ivy

package com.orbitz.monitoring.api.engine;

import com.orbitz.monitoring.api.Attribute;
import com.orbitz.monitoring.api.CompositeMonitor;
import com.orbitz.monitoring.api.InheritableStrategy;
import com.orbitz.monitoring.api.Monitor;
import com.orbitz.monitoring.api.MonitoringEngine;
import com.orbitz.monitoring.api.MonitoringLevel;
import com.orbitz.monitoring.api.monitor.AttributeHolder;
import com.orbitz.monitoring.api.monitor.CompositeAttributeHolder;
import org.apache.log4j.Logger;

import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;

/**
 *
 */
public class StackBasedInheritableStrategy implements InheritableStrategy {

    private static final Logger log = Logger.getLogger(StackBasedInheritableStrategy.class);

    private static final String DEFAULT_PARENT_SEQUENCE_ID = "m";

    private final ConcurrentMap threadBasedMap = new ConcurrentHashMap();
    private AtomicReference eventPatternLevel = new AtomicReference(MonitoringLevel.INFO);

    public int clearCurrentThread() {
        LinkedList stack = getStack();
        int count = 0;
        if (stack != null) {
            count = stack.size();
            if (count > 0) {
                StringBuffer monitorNames = new StringBuffer();
                for (Iterator i = stack.iterator(); i.hasNext();) {
                    StackFrame stackFrame = (StackFrame) i.next();
                    Monitor m = stackFrame.getCompositeMonitor();
                    String s = (String) m.get(Attribute.NAME);
                    if (monitorNames.length() > 0) {
                        monitorNames.append(", ");
                    }
                    monitorNames.append(s);
                }
                log.warn("clearing old CompositeMonitor refs for current thread; "+count+" found; names: "+monitorNames);
                stack.clear();
            }
        }
        return count;
    }

    /**
     * This method should be called by all CompositeMonitor implementations
     * before they call process().
     *
     * @param monitor the monitor that is completed
     */
    public void compositeMonitorCompleted(CompositeMonitor monitor) {
        LinkedList stack = getStack();

        if (stack != null && !stack.isEmpty()) {
            StackFrame target = new StackFrame(monitor);
            if (!stack.getLast().equals(target) && !stack.contains(target)) {
                // This monitor is being double processed on accident.
                // Ignore it.
                return;
            }

            while (!stack.getLast().equals(target)) {
                // A child monitor was not processed, process them now.
                StackFrame stackFrame = (StackFrame) stack.removeLast();
                CompositeMonitor missedMonitor = stackFrame.getCompositeMonitor();
                String name = (String) missedMonitor.get(Attribute.NAME);
                log.warn("unfinished child monitor \""+name+"\" found so will process now and remove; app is fine");
                MonitoringEngine.getInstance().process(missedMonitor);
            }

            stack.removeLast();
        }
    }

    /**
     * This method should be called by all CompositeMonitor implementations
     * before they call monitorStarted().
     *
     * @param compositeMonitor the composite monitor
     */
    public void compositeMonitorStarted(CompositeMonitor compositeMonitor) {
        if (getEventPatternLevel().hasHigherPriorityThan(compositeMonitor.getLevel())) {
            if (log.isDebugEnabled()) {
                log.debug("skipping " + compositeMonitor.getAsString(Attribute.NAME));
            }
            return;
        }

        LinkedList stack = getStack();

        if (stack == null) {
            stack = new LinkedList();
            threadBasedMap.put(Thread.currentThread(), stack);
        }

        stack.addLast(new StackFrame(compositeMonitor));
    }

    /**
     * Obtains the first CompositeMonitor found on the per thread stack that has
     * its name attribute equal to the supplied name. This method should be used
     * in situations where stateless code is unable to hold a reference to
     * the CompositeMonitor that was originally created. Supplying the name
     * value is needed to ensure that instrumentation errors in code called by
     * users of this method does not interfere with the ability to correctly
     * obtain the original CompositeMonitor.
     *
     * @param name the value of name that our Monitor was created with.
     * @return the first CompositeMonitor with the supplied name, or null if not
     *         found
     * @throws IllegalArgumentException if name is null
     */
    public CompositeMonitor getCompositeMonitorNamed(String name) throws IllegalArgumentException {
        if (name == null) {
            throw new IllegalArgumentException("name cannot be null");
        }

        CompositeMonitor monitorToReturn = null;

        LinkedList stack = getStack();

        if (stack != null) {
            int size = stack.size();
            ListIterator i = stack.listIterator(size);

            while (i.hasPrevious()) {
                StackFrame stackFrame = (StackFrame) i.previous();
                CompositeMonitor monitor = stackFrame.getCompositeMonitor();

                if (name.equals(monitor.get(Attribute.NAME))) {
                    monitorToReturn = monitor;
                    break;
                }
            }
        }

        return monitorToReturn;
    }

    /**
     * Returns the current inheritable attributes for this thread.
     *
     * @return the inheritable attributes that would be applied to a monitor
     *         if it were made right now, or an empty Map if there are none
     */
    public Map getInheritableAttributes() {
        Map inheritable = new HashMap();

        String parentSequenceId = DEFAULT_PARENT_SEQUENCE_ID;

        LinkedList stack = getStack();

        if (stack != null && !stack.isEmpty()) {
            Iterator i = stack.iterator();
            while (i.hasNext()) {
                StackFrame stackFrame = (StackFrame) i.next();
                CompositeMonitor monitor = stackFrame.getCompositeMonitor();
                inheritable.putAll(monitor.getInheritableAttributeHolders());
            }
            StackFrame stackFrame = (StackFrame) stack.getLast();
            CompositeMonitor parent = stackFrame.getCompositeMonitor();

            parentSequenceId = parent.getAsString(Attribute.SEQUENCE_ID);

            inheritable.put(Attribute.PARENT_SEQUENCE_ID,
                    new CompositeAttributeHolder(parentSequenceId, true).serializable().lock());

        }

        String sequenceId = parentSequenceId;
        if (stack != null && !stack.isEmpty()) {
            StackFrame stackFrame = (StackFrame) stack.getLast();
            AtomicInteger counter = stackFrame.getCounter();
            sequenceId += "_" + counter.getAndIncrement();
        }

        inheritable.put(Attribute.SEQUENCE_ID, new CompositeAttributeHolder(sequenceId, true).serializable().lock());

        return inheritable;
    }

    public void processMonitorForCompositeMonitor(Monitor monitor) {
        LinkedList stack = getStack();

        if (stack != null) {
            if (! stack.isEmpty()) {
                StackFrame stackFrame = (StackFrame) stack.getLast();
                CompositeMonitor parentMonitor = stackFrame.getCompositeMonitor();

                // only add this monitor being processed to a parent if it is enabled
                // by its monitoring level
                MonitoringLevel monitorLevel = monitor.getLevel();

                if ((monitorLevel != null) && (monitorLevel.hasHigherOrEqualPriorityThan(getEventPatternLevel()))) {
                    parentMonitor.addChildMonitor(monitor);
                }
            } else {
                threadBasedMap.remove(Thread.currentThread());
            }
        }
    }

    public void setInheritable(CompositeMonitor monitor, String key, AttributeHolder origional) {
        // no-op
    }

    public void shutdown() {
        threadBasedMap.clear();
    }

    public void startup() {
        threadBasedMap.clear();
    }

    public MonitoringLevel getEventPatternLevel() {
        return (MonitoringLevel) eventPatternLevel.get();
    }

    public void setEventPatternLevel(MonitoringLevel eventPatternLevel) {
        this.eventPatternLevel.set(eventPatternLevel);
    }

    private LinkedList getStack() {
        return (LinkedList) threadBasedMap.get(Thread.currentThread());
    }

    /**
     * Private class used in synced stacks.
     */
    private class StackFrame {

        private final CompositeMonitor _monitor;
        private final AtomicInteger _counter;

        public StackFrame(CompositeMonitor monitor) {
            super();
            _monitor = monitor;
            _counter = new AtomicInteger(0);
        }

        public CompositeMonitor getCompositeMonitor() {
            return _monitor;
        }

        public AtomicInteger getCounter() {
            return _counter;
        }

        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;

            final StackFrame other = (StackFrame) o;

            return (_monitor == null ? other._monitor == null : _monitor == other._monitor);
        }

        public int hashCode() {
            return  (_monitor == null ? 0 : _monitor.hashCode());
        }

    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy