/** * 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()); } }
/** * Calculates the absolute maximum depth for the common context of the * <code>ProblemContext</code>. * * @return Returns the maximum depth of the recursion. */ private int calculateMaxRecursionDepth() { // The Root Causes can only be in the invocation tree with the Problem Context as root node. InvocationSequenceDataIterator iterator = new InvocationSequenceDataIterator(problemContext.getCommonContext()); // Checks if a Root Cause method is called by another Root Cause method. If so, there is // recursion. Stack<Integer> recursionStack = new Stack<>(); int maxRecursionDepth = 0; int maxIterationsToCheck = 0; while (iterator.hasNext() && (maxIterationsToCheck < MAX_CALLS_TO_CHECK) && (maxRecursionDepth < 2)) { InvocationSequenceData invocation = iterator.next(); if (!recursionStack.isEmpty() && (recursionStack.peek() >= iterator.currentDepth())) { recursionStack.pop(); } if (isCauseInvocation(invocation)) { recursionStack.push(iterator.currentDepth()); if (recursionStack.size() > maxRecursionDepth) { maxRecursionDepth = recursionStack.size(); } maxIterationsToCheck++; } } return maxRecursionDepth; }
/** * Aggregate all the invocations that are considered as rootCause to the object * {@link RootCause}. * * @return Returns the number of candidates that are already checked. */ private int getRootCauses() { int causeCandidatesChecked = 0; double problemContextCommonContextDuration = InvocationSequenceDataHelper.calculateDuration(problemContext.getCommonContext()); // Root Cause candidates are put into one Root Cause as long as the condition is true. while ((sumExclusiveTime < (PROPORTION * problemContextCommonContextDuration)) && (causeCandidatesChecked < causeCandidates.size())) { InvocationSequenceData invocation = causeCandidates.get(causeCandidatesChecked); if (null == rootCause) { rootCause = diagnosisDataAggregator.getAggregatedDiagnosisData(invocation); } else { diagnosisDataAggregator.aggregate(rootCause, invocation); } sumExclusiveTime += DiagnosisHelper.getExclusiveDuration(invocation); causeCandidatesChecked++; } return causeCandidatesChecked; }
@Test public void problemContextMustBeGlobalContext() { Timestamp currentTime = new Timestamp(System.currentTimeMillis()); List<InvocationSequenceData> rawInvocations = new ArrayList<InvocationSequenceData>(); TimerData timerData = new TimerData(currentTime, 10L, 20L, 30L); timerData.calculateExclusiveMin(RANDOM.nextDouble()); timerData.setExclusiveDuration(RANDOM.nextDouble()); when(globalContext.getTimerData()).thenReturn(timerData); rawInvocations.add(globalContext); when(timeWastingOperation.getRawInvocationsSequenceElements()).thenReturn(rawInvocations); CauseCluster problemContext = problemContextRule.action(); assertThat("The returned problemContext must be the most significant cluster context", problemContext.getCommonContext(), is(globalContext)); }
invocation = iterator.next(); int minDepth = Math.min(iterator.currentDepth(), MAX_CLUSTER_CONTEXT_DISTANCE); if (nextCluster.getCommonContext() == invocation) { if (null != currentCluster) { int depthDistance = Math.max((currentCauseDepth - minDepth) + 1, 0);
@Test public void problemContextMustBeTheSameInvocationIfItIsTheOnlyOneAndIsTheInvoker() { 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>(); parentSequence.getNestedSequences().add(childSequence); rawInvocations.add(parentSequence); when(timeWastingOperation.getRawInvocationsSequenceElements()).thenReturn(rawInvocations); CauseCluster problemContext = problemContextRule.action(); assertThat("The returned problemContext must be the invoker", problemContext.getCommonContext(), is(parentSequence)); }
@Test public void rootCauseMustBeNullWhenMethodIdentIsEqualAndInvocationHasNotTimerData() { double highDuration = RANDOM.nextDouble() + 1000; List<InvocationSequenceData> nestedSequences = new ArrayList<InvocationSequenceData>(); nestedSequences.add(new InvocationSequenceData(DEF_DATE, PLATFORM_IDENT, SENSOR_TYPE_IDENT, METHOD_IDENT_EQUAL)); nestedSequences.add(new InvocationSequenceData(DEF_DATE, PLATFORM_IDENT, SENSOR_TYPE_IDENT, METHOD_IDENT_EQUAL)); when(problemContext.getCommonContext()).thenReturn(commonContext); when(commonContext.getMethodIdent()).thenReturn(1L); when(commonContext.getDuration()).thenReturn(highDuration); when(commonContext.getNestedSequences()).thenReturn(nestedSequences); AggregatedDiagnosisData rootCause = problemCauseRule.action(); assertThat("The returned root cause rule must be null", rootCause, nullValue()); }
@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())); }
ProblemOccurrence problem = new ProblemOccurrence(inputInvocationSequence, globalContext.get(), problemContext.get().getCommonContext(), rootCause, causeStructure.get().getCauseType(), causeStructure.get().getSourceType()); problems.add(problem);
@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 rootCauseMustBeNotNullWhenMethodIdentIsEqualAndTheInvocationHasTimerData() { double highDuration = RANDOM.nextDouble() + 1000; List<InvocationSequenceData> nestedSequences = new ArrayList<InvocationSequenceData>(); InvocationSequenceData firstChildSequenceData = new InvocationSequenceData(DEF_DATE, PLATFORM_IDENT, SENSOR_TYPE_IDENT, METHOD_IDENT_EQUAL); TimerData timerData = new TimerData(new Timestamp(System.currentTimeMillis()), 10L, 20L, 30L); timerData.calculateExclusiveMin(RANDOM.nextDouble()); timerData.setExclusiveDuration(RANDOM.nextDouble()); firstChildSequenceData.setTimerData(timerData); InvocationSequenceData secondChildSequenceData = new InvocationSequenceData(DEF_DATE, PLATFORM_IDENT, SENSOR_TYPE_IDENT, METHOD_IDENT_EQUAL); timerData.calculateExclusiveMin(RANDOM.nextDouble()); timerData.setExclusiveDuration(RANDOM.nextDouble()); secondChildSequenceData.setTimerData(timerData); nestedSequences.add(firstChildSequenceData); nestedSequences.add(secondChildSequenceData); when(problemContext.getCommonContext()).thenReturn(commonContext); when(commonContext.getMethodIdent()).thenReturn(1L); when(commonContext.getDuration()).thenReturn(highDuration); when(problemContext.getCauseInvocations()).thenReturn(nestedSequences); AggregatedDiagnosisData rootCause = problemCauseRule.action(); assertThat("The returned root cause rule must not be null", rootCause, notNullValue()); }
@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)); }
@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 rootCauseMustHaveTwoElementsInRawInvocationSequence() { List<InvocationSequenceData> nestedSequences = new ArrayList<InvocationSequenceData>(); InvocationSequenceData firstChildSequenceData = new InvocationSequenceData(DEF_DATE, PLATFORM_IDENT, SENSOR_TYPE_IDENT, METHOD_IDENT_EQUAL); TimerData timerData = new TimerData(new Timestamp(System.currentTimeMillis()), 10L, 20L, 30L); TimerData firstTimerData = timerData; firstTimerData.setExclusiveDuration(2000); firstTimerData.setDuration(2000); firstChildSequenceData.setTimerData(firstTimerData); InvocationSequenceData secondChildSequenceData = new InvocationSequenceData(DEF_DATE, PLATFORM_IDENT, SENSOR_TYPE_IDENT, METHOD_IDENT_EQUAL); TimerData secondTimerData = timerData; secondTimerData.setExclusiveDuration(100); secondTimerData.setDuration(100); secondChildSequenceData.setTimerData(secondTimerData); nestedSequences.add(firstChildSequenceData); nestedSequences.add(secondChildSequenceData); when(problemContext.getCommonContext()).thenReturn(commonContext); when(commonContext.getMethodIdent()).thenReturn(METHOD_IDENT_EQUAL); when(commonContext.getDuration()).thenReturn(3100.0); when(problemContext.getCauseInvocations()).thenReturn(nestedSequences); AggregatedDiagnosisData rootCause = problemCauseRule.action(); assertThat("Raw invocation sequence must have two elements", rootCause.getRawInvocationsSequenceElements(), hasSize(2)); }
rawInvocations.add(new InvocationSequenceData()); rawInvocations.add(childSequence); when(problemContext.getCommonContext()).thenReturn(commonContext); when(commonContext.getParentSequence()).thenReturn(parentSequence); when(commonContext.getTimerData()).thenReturn(timerDataSql);
Pair<Long, String> pair = new Pair<Long, String>(detectedProblemContext.getNestedSequences().get(0).getMethodIdent(), "n.a."); when(rootCause.getAggregationKey()).thenReturn(pair); when(problemContext.getCommonContext()).thenReturn(commonContext); when(commonContext.getParentSequence()).thenReturn(null); when(commonContext.getNestedSequences()).thenReturn(Collections.singletonList(detectedProblemContext));
when(rootCause.getAggregatedDiagnosisTimerData()).thenReturn(aggregatedTimerData); 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));
@Test public void wrongGlobalContextResultsInWrongCommonContext() { long methodIdent = 108L; InvocationSequenceData root = new InvocationSequenceData(DEF_DATE, 10, 10, methodIdent); InvocationSequenceData firstInvocationSequenceData = new InvocationSequenceData(DEF_DATE, 10, 10, methodIdent); firstInvocationSequenceData.setParentSequence(root); InvocationSequenceData secondInvocationSequenceData = new InvocationSequenceData(DEF_DATE, 10, 10, methodIdent); secondInvocationSequenceData.setParentSequence(root); root.getNestedSequences().add(firstInvocationSequenceData); root.getNestedSequences().add(secondInvocationSequenceData); CauseCluster one = new CauseCluster(root); CauseCluster two = new CauseCluster(secondInvocationSequenceData); one.setDistanceToNextCluster(1); one.setDepthOfCommonContext(1); two.setDistanceToNextCluster(1); two.setDepthOfCommonContext(1); List<CauseCluster> clustersToMerge = new ArrayList<CauseCluster>(); clustersToMerge.add(one); clustersToMerge.add(two); CauseCluster merged = new CauseCluster(clustersToMerge); assertThat("The returned problemContext must has size 2", merged.getCauseInvocations().size(), is(2)); assertThat("The returned root cause rule must not be null", merged.getCommonContext(), not(nullValue())); }
@Test public void isReturningTheProperValue() { long methodIdent = 108L; InvocationSequenceData root = new InvocationSequenceData(DEF_DATE, 10, 10, methodIdent); InvocationSequenceData firstInvocationSequenceData = new InvocationSequenceData(DEF_DATE, 10, 10, methodIdent); firstInvocationSequenceData.setParentSequence(root); InvocationSequenceData secondInvocationSequenceData = new InvocationSequenceData(DEF_DATE, 10, 10, methodIdent); secondInvocationSequenceData.setParentSequence(root); root.getNestedSequences().add(firstInvocationSequenceData); root.getNestedSequences().add(secondInvocationSequenceData); CauseCluster one = new CauseCluster(firstInvocationSequenceData); CauseCluster two = new CauseCluster(secondInvocationSequenceData); one.setDistanceToNextCluster(1); one.setDepthOfCommonContext(1); two.setDistanceToNextCluster(1); two.setDepthOfCommonContext(1); List<CauseCluster> clustersToMerge = new ArrayList<CauseCluster>(); clustersToMerge.add(one); clustersToMerge.add(two); CauseCluster merged = new CauseCluster(clustersToMerge); assertThat("The returned problemContext must have size 2", merged.getCauseInvocations().size(), is(2)); assertThat("The returned problemContext must be the root one element", merged.getCommonContext(), is(root)); }
assertThat("The returned problemContext must be the most significant cluster context", problemContext.getCommonContext(), is(significantContext));