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

com.github.endoscope.core.Engine Maven / Gradle / Ivy

The newest version!
package com.github.endoscope.core;

import java.util.LinkedList;
import java.util.function.Supplier;

import com.github.endoscope.properties.Properties;
import com.github.endoscope.storage.Storage;
import com.github.endoscope.storage.StorageFactory;
import org.apache.commons.lang3.StringUtils;

public class Engine {
    private ThreadLocal> contextStack = new ThreadLocal<>();
    private Boolean enabled = null;
    private Storage storage = null;//may stay null if disabled or cannot setup it
    private CurrentStats currentStats;
    private AsyncTasksFactory currentStatsAsyncTasks;
    private int maxIdLength = Properties.getMaxIdLength();

    public Engine() {
        if (isEnabled()) {
            storage = new StorageFactory().safeCreate();//may return null
            currentStats = new CurrentStats();
            currentStatsAsyncTasks = new CurrentStatsAsyncTasks(currentStats, storage);
        }
    }

    protected Engine(boolean enabled, Storage storage, AsyncTasksFactory tasksFactory) {
        this.enabled = enabled;
        this.storage = storage;
        currentStats = new CurrentStats();
        currentStatsAsyncTasks = tasksFactory;
    }

    public boolean isEnabled() {
        if (enabled == null) {
            enabled = Properties.isEnabled();
        }
        return enabled;
    }

    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
    }

    private void checkEnabled() {
        if (!isEnabled()) {
            throw new IllegalStateException("feature not enabled");
        }
    }

    /**
     * @param id required, might get cut if too long
     * @return true if it was first element pushed to call stack
     */
    protected boolean push(String id) {
        checkEnabled();

        id = prepareId(id);
        Context context = new Context(id, System.currentTimeMillis());

        LinkedList stack = contextStack.get();
        boolean first = false;
        if (stack == null) {
            first = true;
            stack = new LinkedList<>();
            contextStack.set(stack);
        }
        Context parent = stack.peek();
        if (parent != null) {
            parent.addChild(context);
        }
        stack.push(context);
        return first;
    }

    private String prepareId(String id) {
        id = StringUtils.trimToNull(id);
        if (id == null) {
            return "";
        }
        if (id.length() > maxIdLength) {
            return id.substring(0, maxIdLength);
        }
        return id;
    }

    protected void pop(boolean completedWithException) {
        checkEnabled();

        LinkedList stack = contextStack.get();
        if (stack.isEmpty()) {
            return;
        }
        Context context = stack.pop();
        context.setTime(System.currentTimeMillis() - context.getTime());
        context.setErr(completedWithException);

        if (stack.isEmpty()) {
            currentStats.add(context);
            currentStatsAsyncTasks.triggerAsyncTask();
        }
    }

    /*
     * It should always pop last element - but in case we made error we need to make sure we clean the stack.
     */
    protected void popAll(boolean completedWithException) {
        checkEnabled();

        LinkedList stack = contextStack.get();
        Context context = null;
        while (!stack.isEmpty()) {
            context = stack.pop();
            context.setTime(System.currentTimeMillis() - context.getTime());
            context.setErr(completedWithException);
        }
        if (context != null) {
            currentStats.add(context);
            currentStatsAsyncTasks.triggerAsyncTask();
        }
    }

    public CurrentStats getCurrentStats() {
        checkEnabled();
        return currentStats;
    }

    public Storage getStorage() {
        checkEnabled();
        return storage;
    }

    public AsyncTasksFactory getCurrentStatsAsyncTasks() {
        return currentStatsAsyncTasks;
    }

    /**
     * Groups operations under one identifier (next element on monitoring stack).
     *
     * @param id       operation identifier
     * @param runnable result runnable
     */
    public void monitor(String id, Runnable runnable) {
        monitor(id, () -> {
            runnable.run();
            return null;
        });
    }

    /**
     * Groups operations under one identifier (next element on monitoring stack).
     *
     * @param id       operation identifier
     * @param supplier result supplier
     * @param 
     * @return supplier result
     */
    public  T monitor(String id, Supplier supplier) {
        if (!isEnabled()) {
            return supplier.get();
        }

        boolean first = false;
        boolean completedWithException = true;
        try {
            first = push(id);
            T value = supplier.get();
            completedWithException = false;
            return value;
        } finally {
            if (first) {
                popAll(completedWithException);
            } else {
                pop(completedWithException);
            }
        }
    }

    /**
     * Similar to #monitor(String, Supplier) but declared with thrown Exception.
     *
     * @param id       operation identifier
     * @param supplier result supplier that may throw Exception
     * @param 
     * @return supplier result
     */
    public  T monitorEx(String id, ExceptionalSupplier supplier) throws Exception {
        if (!isEnabled()) {
            return supplier.get();
        }

        boolean first = false;
        boolean completedWithException = true;
        try {
            first = push(id);
            T value = supplier.get();
            completedWithException = false;
            return value;
        } finally {
            if (first) {
                popAll(completedWithException);
            } else {
                pop(completedWithException);
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy