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

com.eg.agent.android.trace.TracerMachine Maven / Gradle / Ivy

The newest version!
package com.eg.agent.android.trace;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Stack;
import java.util.concurrent.CopyOnWriteArrayList;

import com.eg.agent.android.harvest.ExceptionMarker;
import com.eg.agent.android.harvest.HistoryTransformer;
import com.eg.agent.android.harvest.Reaper;
import com.eg.agent.android.harvest.ReaperAdapter;
import com.eg.agent.android.harvest.VisibilityTransformer;
import com.eg.agent.android.instrumentation.MetricType;
import com.eg.agent.android.logging.EGAgentLog;
import com.eg.agent.android.logging.EGAgentLogManager;
import com.eg.agent.android.DataMeasurements;
import com.eg.agent.android.Features;
import com.eg.agent.android.MobileAgentUpload;
import com.eg.agent.android.Queue;

public class TracerMachine extends ReaperAdapter {
	public static final String ACTIVITY_METRIC_PREFIX = "Mobile/Activity/Name/";
	public static final String ACTIVITY_BACKGROUND_METRIC_PREFIX = "Mobile/Activity/Background/Name/";
	public static final String ACTIVTY_DISPLAY_NAME_PREFIX = "";
	private static final Collection traceListeners = new CopyOnWriteArrayList();
	private static final List activityHistory = new CopyOnWriteArrayList();
	private static final Object TRACE_MACHINE_LOCK = new Object();
	private static final ThreadLocal threadLocalTrace = new ThreadLocal();
	private static final ThreadLocal threadLocalTraceStack = new ThreadLocal();
	private static TracerMachine traceMachine = null;
	private static TracerFieldInterface traceMachineInterface;
	static EGAgentLog log = EGAgentLogManager.getAgentLog();
	public static int HEALTHY_TRACE_TIMEOUT = 500000;
	public static int UNHEALTHY_TRACE_TIMEOUT = 6000000;

	static long entryTime;
	static long exitTime;
	static String status;

	static String method = "";
	static String category = "";
	static String APItype = "";
	private ActivityTracer activityTrace;

	public static void setAPIType(String api) {
		log.debug("TracerMachine:setAPIType::" + api);
		APItype = api;
	}

	protected TracerMachine(Tracer rootTrace) {
		this.activityTrace = new ActivityTracer(rootTrace);
		Reaper.addHarvestListener(this);
	}

	public static void startTracing(String name) {
		TracerMachine.startTracing(name, false);
	}

	public static void startTracing(String name, boolean customName) {
		TracerMachine.startTracing(name, customName, false);
	}
	
	 public static void clearActivityHistory() {
	     activityHistory.clear();
	  }

	public static void startTracing(String name, boolean customName, boolean customInteraction) {
		try {
			if (!Features.featureEnabled(Features.DefaultInteractions)) {
				return;
			}
			Object object = TRACE_MACHINE_LOCK;
			synchronized (object) {

				threadLocalTrace.remove();
				threadLocalTraceStack.set(new TracerStack());
				Tracer rootTrace = new Tracer();
				rootTrace.activityClassName = name;
				rootTrace.displayName = customName ? name : TracerMachine.formatActivityDisplayName(name);
				rootTrace.metricName = TracerMachine.formatActivityMetricName(rootTrace.displayName);
				rootTrace.metricBackgroundName = TracerMachine
						.formatActivityBackgroundMetricName(rootTrace.displayName);
				rootTrace.entryTimestamp = System.currentTimeMillis();
				log.debug("Started trace of " + name + ":" + rootTrace.myUUID.toString());
				rootTrace.traceMachine = traceMachine = new TracerMachine(rootTrace);
				TracerMachine.pushTraceContext(rootTrace);
				TracerMachine.traceMachine.activityTrace.previousActivity = TracerMachine.getLastVisibilityTransformer();
				activityHistory.add(new VisibilityTransformer(rootTrace.entryTimestamp, rootTrace.displayName));
				for (TracerLifecycle listener : traceListeners) {
					listener.onTraceStart(TracerMachine.traceMachine.activityTrace);
				}
			}
		} catch (Exception e) {
			log.error("Caught error while initializing TraceMachine, shutting it down", e);
			ExceptionMarker.noticeException(e);
			traceMachine = null;
			threadLocalTrace.remove();
			threadLocalTraceStack.remove();
		}

	}

	public static void haltTracing() {
		Object object = TRACE_MACHINE_LOCK;
		synchronized (object) {
			TracerMachine finishedMachine = traceMachine;
			traceMachine = null;
			finishedMachine.activityTrace.discard();
			TracerMachine.endLastVisibilityTransformer();
			Reaper.removeHarvestListener(finishedMachine);
			threadLocalTrace.remove();
			threadLocalTraceStack.remove();
		}
	}

	public void storeCompletedTrace(Tracer trace) {
		try {
			if (TracerMachine.isTracingInactive()) {
				log.debug("Attempted to store a completed trace with no trace machine!");
				return;
			}
			this.activityTrace.addCompletedTrace(trace);
		} catch (Exception e) {
			log.error("Caught error while calling storeCompletedTrace()", e);
			throw new RuntimeException();
		}
	}

	public static void endTrace() {
		traceMachine.completeActivityTrace();
	}

	public static void endTrace(String id) {
		try {
			if (TracerMachine.getActivityTrace().rootTrace.myUUID.toString().equals(id)) {
				traceMachine.completeActivityTrace();
			}
		} catch (Exception Exception) {
			// empty catch block
		}
	}

	public static ActivityTracer getActivityTrace() throws Exception {
		try {
			return TracerMachine.traceMachine.activityTrace;
		} catch (NullPointerException e) {
			throw new Exception();
		}

	}

	public static boolean isTracingActive() {
		return traceMachine != null;
	}

	public static boolean isTracingInactive() {
		return !TracerMachine.isTracingActive();
	}

	public static Tracer getCurrentTrace() throws Exception {
		if (TracerMachine.isTracingInactive()) {
			throw new Exception();
		}
		Tracer trace = threadLocalTrace.get();
		if (trace != null) {
			return trace;
		}
		return TracerMachine.getRootTrace();
	}

	public static Tracer getRootTrace() {
		try {
			return TracerMachine.traceMachine.activityTrace.rootTrace;
		} catch (NullPointerException e) {
			log.error(e.getMessage(), e);
		}
		return null;
	}

	private static Tracer registerNewTrace(String name) throws Exception {
		if (TracerMachine.isTracingInactive()) {
			log.debug("Tried to register a new trace but tracing is inactive!");
			throw new Exception();
		}
		Tracer parentTrace = TracerMachine.getCurrentTrace();
		Tracer childTrace = new Tracer(name, parentTrace.myUUID, traceMachine);
		try {
			TracerMachine.traceMachine.activityTrace.addTrace(childTrace);
		} catch (Exception e) {
			throw new Exception();
		}
		log.verbose("Registering trace of " + name + " with parent " + parentTrace.displayName);
		parentTrace.addChild(childTrace);
		return childTrace;
	}

	/*
	 * WARNING - Removed try catching itself - possible behaviour change.
	 */
	protected void completeActivityTrace() {
		Object object = TRACE_MACHINE_LOCK;
		synchronized (object) {
			if (TracerMachine.isTracingInactive()) {
				return;
			}
			TracerMachine finishedMachine = traceMachine;
			traceMachine = null;
			finishedMachine.activityTrace.complete();
			TracerMachine.endLastVisibilityTransformer();
			for (TracerLifecycle listener : traceListeners) {
				listener.onTraceComplete(finishedMachine.activityTrace);
			}
			Reaper.removeHarvestListener(finishedMachine);
		}
	}

	public static void enterNetworkSegment(String name) {
		try {
			if (TracerMachine.isTracingInactive()) {
				return;
			}
			Tracer currentTrace = TracerMachine.getCurrentTrace();
			if (currentTrace.getTracerType() == TracerTypes.NETWORK) {
				TracerMachine.exitMethod();
			}
			TracerMachine.enterMethod(name);
			Tracer networkTrace = TracerMachine.getCurrentTrace();
			networkTrace.setTracerType(TracerTypes.NETWORK);
		}

		catch (Exception e) {
			log.error("Caught error while calling enterNetworkSegment()", e);
			ExceptionMarker.noticeException(e);
		}
	}

	public static void enterMethod(String name) {
		TracerMachine.enterMethod(name, null);
	}

	public static void enterMethod(String name, ArrayList annotationParams) {

		TracerMachine.enterMethod(null, name, annotationParams);
	}

	public static void enterMethod(String method, String category, String APItype) {
		entryTime = System.currentTimeMillis();
		TracerMachine.method = method;
		TracerMachine.category = category;
		TracerMachine.APItype = APItype;
		ArrayList categoryParams = new ArrayList(Arrays.asList(category, MetricType.class.getName(), APItype));
		enterMethod(method, categoryParams);
	}

	public static void enterMethod(Tracer trace, String name, ArrayList annotationParams) {
		try {
			log.debug("TransactionUtil.enterMethod:::TracerMachine.isTracingInactive()::::"+TracerMachine.isTracingInactive());
			if (TracerMachine.isTracingInactive()) {
				return;
			}
			entryTime = System.currentTimeMillis();
			long currentTime = System.currentTimeMillis();
			long lastUpdatedAt = TracerMachine.traceMachine.activityTrace.lastUpdatedAt;
			long inception = TracerMachine.traceMachine.activityTrace.startedAt;
			if (lastUpdatedAt + (long) HEALTHY_TRACE_TIMEOUT < currentTime
					&& !TracerMachine.traceMachine.activityTrace.hasMissingChildren()) {
				log.error(String.format("LastUpdated[%d] CurrentTime[%d] Trigger[%d]", lastUpdatedAt, currentTime,
						currentTime - lastUpdatedAt));
				log.debug("Completing activity trace after hitting healthy timeout (" + HEALTHY_TRACE_TIMEOUT + "ms)");
				if (TracerMachine.isTracingActive()) {
					traceMachine.completeActivityTrace();
				}
				return;
			}
			if (inception + (long) UNHEALTHY_TRACE_TIMEOUT < currentTime) {
				log.debug("Completing activity trace after hitting unhealthy timeout (" + UNHEALTHY_TRACE_TIMEOUT
						+ "ms)");
				if (TracerMachine.isTracingActive()) {
					traceMachine.completeActivityTrace();
				}
				return;
			}
			TracerMachine.loadTraceContext(trace);
			Tracer childTrace = TracerMachine.registerNewTrace(name);
			log.debug("TracerMachine:enterMethod::annotationParams::" + annotationParams);
			if (annotationParams != null && annotationParams.size() > 1) {
				childTrace.metricName = annotationParams.get(2);
			}
			log.debug("TracerMachine:enterMethod::childTrace.metricName::" + childTrace.metricName);
			TracerMachine.pushTraceContext(childTrace);
			childTrace.scope = TracerMachine.getCurrentScope();
			childTrace.setAnnotationParams(annotationParams);
			for (TracerLifecycle listener : traceListeners) {
				listener.onEnterMethod();
			}
			childTrace.entryTimestamp = System.currentTimeMillis();
		}

		catch (Exception e) {
			log.error("Caught error while calling enterMethod()", e);
			ExceptionMarker.noticeException(e);
		}
	}

	private static void loadTraceContext(Tracer trace) {
		if (TracerMachine.isTracingInactive()) {
			return;
		}
		if (threadLocalTrace.get() == null) {
			threadLocalTrace.set(trace);
			threadLocalTraceStack.set(new TracerStack());
			if (trace == null) {
				return;
			}
			threadLocalTraceStack.get().push(trace);
		} else if (trace == null) {
			if (threadLocalTraceStack.get().isEmpty()) {
				log.debug("No context to load!");
				threadLocalTrace.set(null);
				return;
			}
			trace = (Tracer) threadLocalTraceStack.get().peek();
			threadLocalTrace.set(trace);
		}
		log.verbose("Trace " + trace.myUUID.toString() + " is now active");
	}

	public static void exitMethod() {
		try {
			if (TracerMachine.isTracingInactive()) {
				return;
			}

			exitTime = System.currentTimeMillis();

			Tracer trace = threadLocalTrace.get();
			log.debug("TracerMachine::exitMethod:::trace::::" + trace);
			
			if (trace == null) {
				log.debug("threadLocalTrace is null");
				return;
			}

			
			trace.exitTimestamp = exitTime;
			if (trace.threadId == 0L && traceMachineInterface != null) {
				trace.threadId = traceMachineInterface.getCurrentThreadId();
				trace.threadName = traceMachineInterface.getCurrentThreadName();
			}
			for (TracerLifecycle listener : traceListeners) {
				listener.onExitMethod();
			}
			if (trace.getActivityClassName() == null) {
				trace.activityClassName = TracerMachine.getRootTrace().activityClassName;
			}
			if (trace.getFullActivityClassName() == null) {
				trace.setFullActivityClassName(TracerMachine.getRootTrace().getFullActivityClassName());
			}
			
			if (trace.getActivityClassName() == null) {
				trace.activityClassName = TracerMachine.getRootTrace().getFragmentClassName();
			}
			if (trace.getFullActivityClassName() == null) {
				trace.setFullActivityClassName(TracerMachine.getRootTrace().getFullFragmentClassName());
			}
			log.debug("TracerMachine::exitMethod:::trace.getMetricName()::::" + trace.getMetricName());
			if ("trace".equalsIgnoreCase(trace.getMetricName())) {
				setMetricName(trace);
			}
			try {
				trace.complete();
			} catch (Exception e) {
				e.printStackTrace();
				threadLocalTrace.remove();
				threadLocalTraceStack.remove();
				if (trace.getTracerType() == TracerTypes.TRACE) {
					if(!Queue.isExcluded(trace.getFullActivityClassName())) { 
						trace.setMainJson(MobileAgentUpload.getJSONObject(trace.getActivityClassName(), trace.displayName,
								trace.getMetricName(), trace.exclusiveTime, trace.getMetricName()));
						Queue.queue(trace);
					}
				}
				return;
			}

			threadLocalTraceStack.get().pop();
			if (threadLocalTraceStack.get().empty()) {
				threadLocalTrace.set(null);
			} else {
				Tracer parentTrace = (Tracer) threadLocalTraceStack.get().peek();
				threadLocalTrace.set(parentTrace);
				parentTrace.childExclusiveTime += trace.getDurationAsMilliseconds();
			}
			if (trace.getTracerType() == TracerTypes.TRACE) {
				log.debug("TracerMahine:exitMethod::trace == " + trace.toString());
				Queue.queue(trace);
			}

		} catch (Exception e) {
			log.error("Caught error while calling exitMethod()", e);
			ExceptionMarker.noticeException(e);
		}
	}

	private static void setMetricName(Tracer tracer) {
		log.debug("TracerMachie:setMetricName:displayName::::" + tracer.displayName);
		if (tracer != null && tracer.displayName != null) {
			if (tracer.displayName.endsWith("onCreate") || tracer.displayName.endsWith("onCreateView")) {
				tracer.metricName = TracerMachine.APItype;
			} else {
				tracer.metricName = "trace";
				if (tracer.getAnnotationParameters() == null || tracer.getAnnotationParameters().size() > 1) {
					tracer.metricName = "trace";
				} else {
					tracer.metricName = tracer.getAnnotationParameters().get(2);
				}
			}
		}
		log.debug("TracerMachie:setMetricName:metricName::::" + tracer.metricName);
	}

	public static void exit(Tracer trace) {
		exitTime = System.currentTimeMillis();
		long excution_time = exitTime - entryTime;
		try {
			log.debug("TracerMachine:::exit::trace.getMetricName():::"+trace.getMetricName());
			log.debug("TracerMachine:::exit::TracerMachine.APItype:::"+TracerMachine.APItype);
			log.debug("TracerMachine:::exit::Queue.isExcluded("+trace.getFullActivityClassName()+"):::"+Queue.isExcluded(trace.getFullActivityClassName()));
			if(!Queue.isExcluded(trace.getFullActivityClassName())) {
				if (trace.getActivityClassName() != null && "trace".equalsIgnoreCase(TracerMachine.APItype)) {
					
					Queue.queue(MobileAgentUpload.getJSONObject(trace.getActivityClassName(), trace.displayName,
							trace.getMetricName(), excution_time, trace.getMetricName()));
				
				} else if (!"trace".equalsIgnoreCase(TracerMachine.APItype)) {
					Queue.queue(MobileAgentUpload.getJSONObject(trace.getActivityClassName(), trace.displayName,
							trace.getMetricName(), excution_time, trace.getMetricName()));
				
				}
			}
		} catch (IOException e) {
			log.error(e.getMessage(), e);
		}
		
	}

	public static void setCurrentTraceParam(String key, Object value) {

	}

	public static void setMethodName(String name) {
		log.debug("TracerMachine:setMethodName::" + name);
		TracerMachine.method = name;
	}

	private static void pushTraceContext(Tracer trace) {
		if (trace == null) {
			return;
		}
		TracerStack traceStack = threadLocalTraceStack.get();
		if (traceStack.empty()) {
			traceStack.push(trace);
		} else if (traceStack.peek() != trace) {
			traceStack.push(trace);
		}
		threadLocalTrace.set(trace);
	}

	public static String getStatus() {
		return status;
	}

	public static void setStatus(String status) {
		TracerMachine.status = status;
	}

	public static long getEntryTime() {
		return entryTime;
	}

	public static void setEntryTime(long entryTime) {
		TracerMachine.entryTime = entryTime;
	}

	public static long getExitTime() {
		return exitTime;
	}

	public static void setExitTime(long exitTime) {
		TracerMachine.exitTime = exitTime;
	}

	public static String getCurrentScope() {
		try {

		} catch (Exception e) {

			return null;
		}
		return null;
	}

	public static String formatActivityMetricName(String name) {
		return ACTIVITY_METRIC_PREFIX + name;
	}

	public static String formatActivityBackgroundMetricName(String name) {
		return ACTIVITY_BACKGROUND_METRIC_PREFIX + name;
	}

	public static String formatActivityDisplayName(String name) {
		return ACTIVTY_DISPLAY_NAME_PREFIX + name;
	}

	public static void addTraceListener(TracerLifecycle listener) {
		traceListeners.add(listener);
	}

	public static void removeTraceListener(TracerLifecycle listener) {
		traceListeners.remove(listener);
	}

	public static VisibilityTransformer getLastVisibilityTransformer() {
		if (activityHistory.isEmpty()) {
			return null;
		}
		return activityHistory.get(activityHistory.size() - 1);
	}

	public static void endLastVisibilityTransformer() {
		VisibilityTransformer activitySighting = TracerMachine.getLastVisibilityTransformer();
		if (activitySighting != null) {
			activitySighting.end(System.currentTimeMillis());
		}
	}

	public static HistoryTransformer getActivityHistory() {
		return new HistoryTransformer(activityHistory);
	}

	public static void setFragmentClassName(String currentActiviteName) {
		try {
			getCurrentTrace().setFragmentClassName(currentActiviteName);
		} catch (Exception e) {
			log.error("Tracing is inactive::"+e.getMessage());
		}
	}
	
	public static void setCurrentActivityFullName(String currentActiviteName) {
		try {
			getCurrentTrace().setFullActivityClassName(currentActiviteName);
		} catch (Exception e) {
			log.error("Tracing is inactive::"+e.getMessage());
		}
	}
	
	public static void setFullFragmentClassName(String currentActiviteName) {
		try {
			getCurrentTrace().setFullFragmentClassName(currentActiviteName);
		} catch (Exception e) {
			log.error("Tracing is inactive::"+e.getMessage());
		}
	}
	
	
	public static void setCurrentActivity(String currentActiviteName) {
		try {
			getCurrentTrace().setActivityClassName(currentActiviteName);
		} catch (Exception e) {
			log.error("Tracing is inactive::"+e.getMessage());
		}
	}

	public static String getCurrentActivity() {
		try {
			return getCurrentTrace().getCurrentActiviteName();
		} catch (Exception e) {
			log.error("Tracing is inactive::"+e.getMessage());
		}
		return "";
	}
	
	public static String getCurrentActivityFullName() {
		try {
			return getCurrentTrace().getFullActivityClassName();
		} catch (Exception e) {
			log.error("Tracing is inactive::"+e.getMessage());
		}
		return "";
	}

	public static void unloadTraceContext(Object object) {
		try {
			if (TracerMachine.isTracingInactive()) {
				return;
			}
			if (traceMachineInterface != null && traceMachineInterface.isUIThread()) {
				return;
			}
			if (threadLocalTrace.get() != null) {
				log.verbose("Trace " + TracerMachine.threadLocalTrace.get().myUUID.toString() + " is now inactive");
			}
			threadLocalTrace.remove();
			threadLocalTraceStack.remove();
			try {
				TracerInterface tfi = (TracerInterface) object;
				tfi.setTrace(null);
			} catch (ClassCastException e) {
				log.error("Not a TraceFieldInterface: " + e.getMessage());
			}
		} catch (Exception e) {
			log.error("Caught error while calling unloadTraceContext()", e);
		}
	}
	
	 public static void setRootDisplayName(String name) {
		    if (isTracingInactive())
		      return; 
		    try {
		      Tracer rootTrace = getRootTrace();
		      DataMeasurements.renameActivity(rootTrace.displayName, name);
		      renameActivityHistory(rootTrace.displayName, name);
		      rootTrace.metricName = formatActivityMetricName(name);
		      rootTrace.metricBackgroundName = formatActivityBackgroundMetricName(name);
		      rootTrace.displayName = name;
		      Tracer currentTrace = getCurrentTrace();
		      currentTrace.scope = getCurrentScope();
		    } catch (Exception e) {
		      return;
		    } 
		  }
	 
	 private static void renameActivityHistory(String oldName, String newName) {
		    for (VisibilityTransformer activitySighting : activityHistory) {
		      if (activitySighting.getName().equals(oldName))
		        activitySighting.setName(newName); 
		    } 
		  }

	private static class TracerStack extends Stack {
		private TracerStack() {
		}
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy