Package org.apache.sirona.tracking

Source Code of org.apache.sirona.tracking.PathTracker$ListenerComparator

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.sirona.tracking;


import org.apache.sirona.configuration.Configuration;
import org.apache.sirona.configuration.ioc.Destroying;
import org.apache.sirona.configuration.ioc.IoCs;
import org.apache.sirona.spi.Order;
import org.apache.sirona.spi.SPI;
import org.apache.sirona.store.DataStoreFactory;
import org.apache.sirona.store.tracking.PathTrackingDataStore;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
* Contains logic to track class#method invocation path
*/
public class PathTracker
{
    private static final String NODE =
        Configuration.getProperty( Configuration.CONFIG_PROPERTY_PREFIX + "javaagent.path.tracking.marker", //
                                   Configuration.getProperty( "org.apache.sirona.cube.CubeBuilder.marker", "node" ) );

    private static final PathTrackingDataStore PATH_TRACKING_DATA_STORE =
        IoCs.findOrCreateInstance( DataStoreFactory.class ).getPathTrackingDataStore();


    private static final ThreadLocal<Context> THREAD_LOCAL = new ThreadLocal<Context>()
    {
        @Override
        protected Context initialValue()
        {
            return new Context();
        }
    };

    private final PathTrackingInformation pathTrackingInformation;

    private static final boolean USE_EXECUTORS = Boolean.parseBoolean(
        Configuration.getProperty( Configuration.CONFIG_PROPERTY_PREFIX + "pathtracking.useexecutors", "false" ) );

    private static boolean USE_SINGLE_STORE = Boolean.parseBoolean(
        Configuration.getProperty( Configuration.CONFIG_PROPERTY_PREFIX + "pathtracking.singlestore", "false" ) );

    protected static ExecutorService EXECUTORSERVICE;

    static
    {

        if ( USE_EXECUTORS )
        {
            int threadsNumber =
                Configuration.getInteger( Configuration.CONFIG_PROPERTY_PREFIX + "pathtracking.executors", 5 );
            EXECUTORSERVICE = Executors.newFixedThreadPool( threadsNumber );
        }
    }

    private static PathTrackingInvocationListener[] LISTENERS;

    static
    {
        ClassLoader classLoader = PathTracker.class.getClassLoader();

        if ( classLoader == null )
        {
            classLoader = Thread.currentThread().getContextClassLoader();
        }

        List<PathTrackingInvocationListener> listeners = new ArrayList<PathTrackingInvocationListener>(  );

        Iterator<PathTrackingInvocationListener> iterator =
            SPI.INSTANCE.find( PathTrackingInvocationListener.class, classLoader ).iterator();

        while ( iterator.hasNext() )
        {
            try
            {
                listeners.add( IoCs.autoSet( iterator.next() ) );
            }
            catch ( Exception e )
            {
                throw new RuntimeException( e.getMessage(), e );
            }
        }

        Collections.sort( listeners, ListenerComparator.INSTANCE );
        LISTENERS = listeners.toArray( new PathTrackingInvocationListener[listeners.size()] );
    }


    public static PathTrackingInvocationListener[] getPathTrackingInvocationListeners()
    {
        return LISTENERS;
    }

    private PathTracker( final PathTrackingInformation pathTrackingInformation )
    {
        this.pathTrackingInformation = pathTrackingInformation;
    }


    private static void cleanUp()
    {
        THREAD_LOCAL.remove();
    }

    // An other solution could be using Thread.currentThread().getStackTrace() <- very slow

    public static PathTracker start( PathTrackingInformation pathTrackingInformation )
    {

        final Context context = THREAD_LOCAL.get();

        int level = 0;
        final PathTrackingInformation current = context.getPathTrackingInformation();
        if ( current == null )
        {
            level = context.getLevel().incrementAndGet();
            pathTrackingInformation.setLevel( level );
        }
        else
        {
            // same class so no inc
            if ( current != pathTrackingInformation )
            {
                level = context.getLevel().incrementAndGet();
                pathTrackingInformation.setLevel( level );
                pathTrackingInformation.setParent( current );
            }


        }
        pathTrackingInformation.setStart( System.nanoTime() );

        context.setPathTrackingInformation( pathTrackingInformation );

        for ( PathTrackingInvocationListener listener : LISTENERS )
        {
            if ( level == 1 )
            {
                listener.startPath( context );
            }
            else
            {
                listener.enterMethod( context );
            }
        }

        return new PathTracker( pathTrackingInformation );
    }


    public void stop()
    {
        final long end = System.nanoTime();
        final long start = pathTrackingInformation.getStart();
        final Context context = THREAD_LOCAL.get();

        final String uuid = context.getUuid();

        final PathTrackingInformation current = context.getPathTrackingInformation();
        // same invocation so no inc, class can do recursion so don't use classname/methodname
        if ( pathTrackingInformation != current )
        {
            context.getLevel().decrementAndGet();
            context.setPathTrackingInformation( pathTrackingInformation.getParent() );
        }

        if (context.getPathTrackingInformation() != null)
        {
            for ( PathTrackingInvocationListener listener : LISTENERS )
            {
                listener.exitMethod( context );

            }
        }

        final PathTrackingEntry pathTrackingEntry =
            new PathTrackingEntry( uuid, NODE, pathTrackingInformation.getClassName(),
                                   pathTrackingInformation.getMethodName(), start, ( end - start ),
                                   pathTrackingInformation.getLevel() );
        if ( USE_SINGLE_STORE )
        {
            PATH_TRACKING_DATA_STORE.store( pathTrackingEntry );
        }
        else
        {
            context.getEntries().add( pathTrackingEntry );
        }

        if ( pathTrackingInformation.getLevel() == 1 && pathTrackingInformation.getParent() == null )
        { // 0 is never reached so 1 is first
            if ( !USE_SINGLE_STORE )
            {
                Runnable runnable = new Runnable()
                {
                    @Override
                    public void run()
                    {
                        PATH_TRACKING_DATA_STORE.store( context.getEntries() );
                        PathTracker.cleanUp();
                    }
                };
                if ( USE_EXECUTORS )
                {
                    EXECUTORSERVICE.submit( runnable );
                }
                else
                {
                    runnable.run();
                }
            }

            for ( PathTrackingInvocationListener listener : LISTENERS )
            {
                listener.endPath( context );
            }

        }
    }

    @Destroying
    public void destroy()
    {
        PathTracker.shutdown();
    }

    public static void shutdown()
    {
        EXECUTORSERVICE.shutdownNow();
    }


    private static class ListenerComparator
        implements Comparator<PathTrackingInvocationListener>
    {
        private static final ListenerComparator INSTANCE = new ListenerComparator();

        private ListenerComparator()
        {
            // no-op
        }

        @Override
        public int compare( final PathTrackingInvocationListener o1, final PathTrackingInvocationListener o2 )
        {
            final Order order1 = o1.getClass().getAnnotation( Order.class );
            final Order order2 = o2.getClass().getAnnotation( Order.class );
            if ( order2 == null )
            {
                return -1;
            }
            if ( order1 == null )
            {
                return 1;
            }
            return order1.value() - order2.value();
        }
    }

}
TOP

Related Classes of org.apache.sirona.tracking.PathTracker$ListenerComparator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.