/** * {@inheritDoc} * <p> * Display only for root invocations. */ @Override public boolean canGenerateFor(DefaultData defaultData) { return (defaultData instanceof InvocationSequenceData) && (((InvocationSequenceData) defaultData).getParentSequence() == null); }
/** * Checks whether this data object has a parent element. * * @param data * the <code>InvocationSequenceData</code> object. * @return whether this data object has a parent element. */ public static boolean hasParentElementInSequence(InvocationSequenceData data) { return null != data.getParentSequence(); }
/** * {@inheritDoc} */ @Override public Object getParent(Object o) { InvocationSequenceData invocationSequenceData = (InvocationSequenceData) o; return invocationSequenceData.getParentSequence(); }
/** * Returns root object of the sequence the given data belongs to by iterating till the tree * root. * * @param data * Invocation * @return Root invocation of the sequence given invocation belongs to. */ public static InvocationSequenceData getRootElementInSequence(InvocationSequenceData data) { InvocationSequenceData invoc = data; while (null != invoc.getParentSequence()) { invoc = invoc.getParentSequence(); } return invoc; }
/** * Constructor. * * @param startFrom * the {@link InvocationSequenceData} element to start the iteration from. * @param onlySubTree * if true, only the sub-tree of the given {@link InvocationSequenceData} element is * iterated. If false, parent items (located after the given * {@link InvocationSequenceData} element) are iterated as well. */ public InvocationSequenceDataIterator(InvocationSequenceData startFrom, boolean onlySubTree) { if (null == startFrom) { throw new IllegalArgumentException("Cannot iterate on a null invocation sequence."); } this.nextElement = startFrom; if (onlySubTree) { iterationEnd = startFrom.getParentSequence(); } while (null != startFrom.getParentSequence()) { nextDepth++; startFrom = startFrom.getParentSequence(); } }
/** * {@inheritDoc} */ @Override public boolean canBeProcessed(DefaultData defaultData) { if (null == defaultData) { return false; } else if (!(defaultData instanceof MethodSensorData)) { // we only put to buffer method sensor data return false; } else if (defaultData instanceof InvocationAwareData) { // we don't put to buffer elements that are inside of invocation if (!((InvocationAwareData) defaultData).isOnlyFoundOutsideInvocations()) { return false; } } else if (defaultData instanceof InvocationSequenceData) { // we don't put to buffer invocations that are not root if (((InvocationSequenceData) defaultData).getParentSequence() != null) { return false; } } return true; }
/** * Creates a new cluster from the passed list of {@link #CauseCluster}. Sets the * <code>commonContext</code> to the parent of the new cluster. The parent subsumes all * {@link InvocationSequenceData} the cluster currently holds. * * @param clustersToMerge * List with clusters this cluster is merged with. * */ public CauseCluster(List<CauseCluster> clustersToMerge) { if ((clustersToMerge == null) || (clustersToMerge.isEmpty())) { throw new IllegalArgumentException("Clusters are not allowed to be null or empty!"); } int distanceToParent = clustersToMerge.get(0).getDistanceToNextCluster(); InvocationSequenceData parent = clustersToMerge.get(0).getCommonContext(); for (int i = 0; (i < distanceToParent) && (parent.getParentSequence() != null); i++) { parent = parent.getParentSequence(); } commonContext = parent; for (CauseCluster cluster : clustersToMerge) { causeInvocations.addAll(cluster.getCauseInvocations()); } }
/** * Returns all data elements (of type {@link InvocationSequenceData} or {@link Span}) which are * contained in the given {@link InvocationTreeElement} or in its child nodes. * {@link InvocationTreeElement} of type * {@link InvocationTreeElement.TreeElementType#MISSING_SPAN} will be ignored. * <p> * Note: If <code>includeNestedInvocationSequences</code> is set to false, all nested invocation * sequences will be ignored and not added to the resulting list, thus, the invocation sequences * in the returned list will be only the root invocation sequences. * * @param tree * the top element of the tree to extract the data * @param includeNestedInvocationSequences * whether nested invocation sequences should also be referenced in the returned list * @return {@link List} of {@link InvocationSequenceData} and {@link Span} */ public static List<Object> getDataElements(InvocationTreeElement tree, boolean includeNestedInvocationSequences) { if (tree == null) { return Collections.emptyList(); } return tree.asStream().filter(e -> e.getType() != TreeElementType.MISSING_SPAN).map(InvocationTreeElement::getDataElement) .filter(o -> includeNestedInvocationSequences || (o instanceof Span) || (((InvocationSequenceData) o).getParentSequence() == null)).collect(Collectors.toList()); }
/** * Returns all {@link InvocationSequenceData} which is contained in the given * {@link InvocationTreeElement} or in its child nodes. {@link InvocationTreeElement} of type * {@link InvocationTreeElement.TreeElementType#MISSING_SPAN} or * {@link InvocationTreeElement.TreeElementType#SPAN} will be ignored. * <p> * Note: the returned list will contain only root invocation sequences * * @param tree * the top element of the tree to extract the data * @return {@link List} of {@link InvocationSequenceData} */ public static List<InvocationSequenceData> getInvocationSequences(InvocationTreeElement tree) { if (tree == null) { return Collections.emptyList(); } return tree.asStream().filter(e -> e.getType() == TreeElementType.INVOCATION_SEQUENCE).map(e -> (InvocationSequenceData) e.getDataElement()).filter(i -> i.getParentSequence() == null) .collect(Collectors.toList()); }
/** * In case there is just one cause invocation then the parent of the problem context is the * cause invocation, otherwise a new instance of CauseCluster will be created with the only * invocation in the list. * * @param causeInvocation * Invocation to get the parent of it if is the only one itself it has no parent. * @return Returns the CauseCluster. */ private CauseCluster getCauseCluster(InvocationSequenceData causeInvocation) { if ((causeInvocation.getParentSequence() != null) && !(causeInvocation.equals(globalContext))) { CauseCluster causeCluster = new CauseCluster(causeInvocation.getParentSequence()); causeCluster.getCauseInvocations().clear(); causeCluster.getCauseInvocations().add(causeInvocation); return causeCluster; } else { return new CauseCluster(causeInvocation); } }
if (nestedSequences.isEmpty()) { nextDepth--; return findNext(current.getParentSequence(), current); } else { int nextIndex = getNextChildIndex(child, nestedSequences) + 1; } else { nextDepth--; return findNext(current.getParentSequence(), current);
/** * Check if the data if valid. We currently have following constraints: * * <ul> * <li>If {@link TimerData} instance then charting must be set * <li>If {@link JmxSensorValueData} instance then it must be boolean or numeric * </ul> * * @param defaultData * Data to check. * @return True if data should be used with the pointer and sent to influx. */ private boolean isValidData(DefaultData defaultData) { if ((defaultData instanceof TimerData) && !((TimerData) defaultData).isCharting()) { return false; } if ((defaultData instanceof JmxSensorValueData) && !((JmxSensorValueData) defaultData).isBooleanOrNumeric()) { return false; } if ((defaultData instanceof InvocationSequenceData) && (((InvocationSequenceData) defaultData).getParentSequence() != null)) { return false; } return true; }
@Test public void problemContextMustBeTheProperInvocationIfThereOneAndIsTheInvokerWithAParentSequence() { long methodIdent = 108L; Timestamp defDate = new Timestamp(new Date().getTime()); long platformIdent = RANDOM.nextLong(); long sensorTypeIdent = RANDOM.nextLong(); InvocationSequenceData parentSequence = new InvocationSequenceData(defDate, platformIdent, sensorTypeIdent, methodIdent); InvocationSequenceData childSequence = new InvocationSequenceData(defDate, platformIdent, sensorTypeIdent, methodIdent); List<InvocationSequenceData> rawInvocations = new ArrayList<InvocationSequenceData>(); childSequence.setParentSequence(parentSequence); rawInvocations.add(childSequence); when(timeWastingOperation.getRawInvocationsSequenceElements()).thenReturn(rawInvocations); CauseCluster problemContext = problemContextRule.action(); assertThat("The returned problemContext must be the invoker", problemContext.getCommonContext(), is(childSequence.getParentSequence())); }
@Test public void causeTypeIsRecursiveIfThereIsNotTimerData() { Timestamp defDate = new Timestamp(new Date().getTime()); Random random = new Random(); long platformIdent = random.nextLong(); long sensorTypeIdent = random.nextLong(); long methodIdentEqual = new Long(108); long methodIdentDiff = random.nextLong(); InvocationSequenceData childSequence = new InvocationSequenceData(defDate, platformIdent, sensorTypeIdent, methodIdentDiff); InvocationSequenceData parentSequence = new InvocationSequenceData(defDate, platformIdent, sensorTypeIdent, methodIdentDiff); InvocationSequenceData grandParentSequence = new InvocationSequenceData(defDate, platformIdent, sensorTypeIdent, methodIdentDiff); parentSequence.setParentSequence(grandParentSequence); List<InvocationSequenceData> rawInvocations = new ArrayList<>(); rawInvocations.add(new InvocationSequenceData()); rawInvocations.add(childSequence); when(problemContext.getCommonContext()).thenReturn(commonContext); when(commonContext.getParentSequence()).thenReturn(parentSequence); when(rootCause.getRawInvocationsSequenceElements()).thenReturn(rawInvocations); when(rootCause.getMethodIdent()).thenReturn(methodIdentEqual); CauseStructure causeStructure = causeStructureRule.action(); assertThat("The returned cause type must be iterative", causeStructure.getCauseType(), is(CauseType.ITERATIVE)); } }
@Test public void causeTypeMustBeIterativeWhenTheChildInvocationsOfTheRootCauseAreIterativeAndHasAHttpTimerData() { Timestamp defDate = new Timestamp(new Date().getTime()); Timestamp currentTime = new Timestamp(System.currentTimeMillis()); HttpTimerData timerDataHttp = new HttpTimerData(currentTime, 10L, 20L, 30L); AggregatedDiagnosisTimerData aggregatedTimerDataHttp = new AggregatedDiagnosisTimerData(timerDataHttp); Random random = new Random(); long platformIdent = random.nextLong(); long sensorTypeIdent = random.nextLong(); long methodIdentEqual = new Long(108); long methodIdentDiff = random.nextLong(); InvocationSequenceData childSequence = new InvocationSequenceData(defDate, platformIdent, sensorTypeIdent, methodIdentDiff); childSequence.setTimerData(timerDataHttp); InvocationSequenceData parentSequence = new InvocationSequenceData(defDate, platformIdent, sensorTypeIdent, methodIdentDiff); parentSequence.setTimerData(timerDataHttp); InvocationSequenceData grandParentSequence = new InvocationSequenceData(defDate, platformIdent, sensorTypeIdent, methodIdentDiff); grandParentSequence.setTimerData(timerDataHttp); parentSequence.setParentSequence(grandParentSequence); List<InvocationSequenceData> rawInvocations = new ArrayList<>(); rawInvocations.add(new InvocationSequenceData()); rawInvocations.add(childSequence); when(problemContext.getCommonContext()).thenReturn(commonContext); when(commonContext.getParentSequence()).thenReturn(parentSequence); when(commonContext.getTimerData()).thenReturn(timerDataHttp); when(rootCause.getRawInvocationsSequenceElements()).thenReturn(rawInvocations); when(rootCause.getMethodIdent()).thenReturn(methodIdentEqual); when(rootCause.getAggregatedDiagnosisTimerData()).thenReturn(aggregatedTimerDataHttp); CauseStructure causeStructure = causeStructureRule.action(); assertThat("The returned cause type must be iterative", causeStructure.getCauseType(), is(CauseType.ITERATIVE)); }
@Test public void causeTypeMustBeIterativeWhenTheChildInvocationsOfTheRootCauseAreIterativeAndHasARegularTimerData() { Timestamp defDate = new Timestamp(new Date().getTime()); Timestamp currentTime = new Timestamp(System.currentTimeMillis()); TimerData timerData = new TimerData(currentTime, 10L, 20L, 30L); AggregatedDiagnosisTimerData aggregatedTimerData = new AggregatedDiagnosisTimerData(timerData); Random random = new Random(); long platformIdent = random.nextLong(); long sensorTypeIdent = random.nextLong(); long methodIdentEqual = new Long(108); long methodIdentDiff = random.nextLong(); InvocationSequenceData childSequence = new InvocationSequenceData(defDate, platformIdent, sensorTypeIdent, methodIdentDiff); childSequence.setTimerData(timerData); InvocationSequenceData parentSequence = new InvocationSequenceData(defDate, platformIdent, sensorTypeIdent, methodIdentDiff); parentSequence.setTimerData(timerData); InvocationSequenceData grandParentSequence = new InvocationSequenceData(defDate, platformIdent, sensorTypeIdent, methodIdentDiff); grandParentSequence.setTimerData(timerData); parentSequence.setParentSequence(grandParentSequence); List<InvocationSequenceData> rawInvocations = new ArrayList<>(); rawInvocations.add(new InvocationSequenceData()); rawInvocations.add(childSequence); when(problemContext.getCommonContext()).thenReturn(commonContext); when(commonContext.getParentSequence()).thenReturn(parentSequence); when(commonContext.getTimerData()).thenReturn(timerData); when(rootCause.getRawInvocationsSequenceElements()).thenReturn(rawInvocations); when(rootCause.getMethodIdent()).thenReturn(methodIdentEqual); when(rootCause.getAggregatedDiagnosisTimerData()).thenReturn(aggregatedTimerData); CauseStructure causeStructure = causeStructureRule.action(); assertThat("The returned cause type must be iterative", causeStructure.getCauseType(), is(CauseType.ITERATIVE)); }
rawInvocations.add(childSequence); when(problemContext.getCommonContext()).thenReturn(commonContext); when(commonContext.getParentSequence()).thenReturn(parentSequence); when(commonContext.getTimerData()).thenReturn(timerDataSql); when(commonContext.getSqlStatementData()).thenReturn(timerDataSql);
when(rootCause.getAggregationKey()).thenReturn(pair); when(problemContext.getCommonContext()).thenReturn(commonContext); when(commonContext.getParentSequence()).thenReturn(null); when(commonContext.getNestedSequences()).thenReturn(Collections.singletonList(detectedProblemContext)); when(commonContext.getMethodIdent()).thenReturn(firstMethod.getMethodIdent());
when(rootCause.getAggregationKey()).thenReturn(detectedProblemContext.getNestedSequences().get(0).getMethodIdent()); when(problemContext.getCommonContext()).thenReturn(commonContext); when(commonContext.getParentSequence()).thenReturn(null); when(commonContext.getNestedSequences()).thenReturn(Collections.singletonList(detectedProblemContext)); when(commonContext.getMethodIdent()).thenReturn(firstMethod.getMethodIdent());
/** * Clones invocation sequence. This method returns new object exactly same as the original * object, but with out nested sequences set. * * @return Cloned invocation sequence. */ public InvocationSequenceData getClonedInvocationSequence() { InvocationSequenceData clone = new InvocationSequenceData(this.getTimeStamp(), this.getPlatformIdent(), this.getSensorTypeIdent(), this.getMethodIdent()); clone.setId(this.getId()); clone.setSpanIdent(this.getSpanIdent()); clone.setChildCount(this.getChildCount()); clone.setDuration(this.getDuration()); clone.setEnd(this.getEnd()); clone.setNestedSequences(Collections.<InvocationSequenceData> emptyList()); clone.setParameterContentData(this.getParameterContentData()); clone.setParentSequence(this.getParentSequence()); clone.setPosition(this.getPosition()); clone.setSqlStatementData(this.getSqlStatementData()); clone.setTimerData(this.getTimerData()); clone.setExceptionSensorDataObjects(this.getExceptionSensorDataObjects()); clone.setStart(this.getStart()); clone.setNestedSqlStatements(this.isNestedSqlStatements()); clone.setNestedExceptions(this.isNestedExceptions()); clone.setLoggingData(this.getLoggingData()); clone.setApplicationId(this.getApplicationId()); clone.setBusinessTransactionId(this.getBusinessTransactionId()); return clone; }