Skip to content

Commit 60adf3f

Browse files
committed
Make tool record multiple attribute record separately
1 parent 228db78 commit 60adf3f

File tree

1 file changed

+47
-37
lines changed

1 file changed

+47
-37
lines changed

common4j/src/main/com/microsoft/identity/common/java/opentelemetry/DefaultBenchmarkSpanPrinter.kt

Lines changed: 47 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -255,63 +255,73 @@ class DefaultBenchmarkSpanPrinter(
255255
/**
256256
* Calculate statistical metrics (average, percentiles) for all status entries across the batch of spans.
257257
*
258-
* For each unique status name found across all spans, this method:
258+
* For each status occurrence found across all spans (including duplicates), this method:
259259
* 1. Collects timing values (time since previous status, time since start) from all spans
260260
* 2. Calculates configured statistical metrics (e.g., Avg, P50, P75, P90)
261261
* 3. Returns the results sorted by the first configured metric's time since start value
262262
*
263+
* Note: If the same status name appears multiple times, each occurrence is tracked separately
264+
* with an enumeration (e.g., "status [1]", "status [2]").
265+
*
263266
* @param spans List of spans to analyze (all spans should have the same span name)
264267
*
265-
* @return List of statistical data for each unique status, sorted by the first configured metric's time since start
268+
* @return List of statistical data for each status occurrence, sorted by the first configured metric's time since start
266269
*/
267270
private fun calculateStatistics(spans: List<IBenchmarkSpan>): List<StatisticalStatusData> {
268271
if (spans.isEmpty()) return emptyList()
269272

270-
// Collect all unique status names across all spans
271-
val allStatusNames = mutableSetOf<String>()
273+
// Build a map of status position -> (display name, list of timing data)
274+
// We need to track each occurrence separately across all spans
275+
data class StatusOccurrence(val statusName: String, val occurrenceIndex: Int)
276+
val statusOccurrencesMap = mutableMapOf<StatusOccurrence, MutableList<Pair<Long, Long>>>() // Pair<timeSincePrevious, timeSinceStart>
277+
272278
for (span in spans) {
273-
for ((statusName, _) in span.getStatuses()) {
274-
allStatusNames.add(statusName)
275-
}
276-
}
279+
val statuses = span.getStatuses()
280+
val startTime = span.getStartTimeInNanoSeconds()
277281

278-
val result = mutableListOf<StatisticalStatusData>()
282+
// Track how many times we've seen each status name in this span
283+
val statusCounts = mutableMapOf<String, Int>()
279284

280-
for (statusName in allStatusNames) {
281-
val timeSincePreviousValues = mutableListOf<Long>()
282-
val timeSinceStartValues = mutableListOf<Long>()
285+
statuses.forEachIndexed { statusIndex, (statusName, timestamp) ->
286+
// Determine which occurrence this is (1st, 2nd, 3rd, etc.)
287+
val occurrenceIndex = statusCounts.getOrDefault(statusName, 0) + 1
288+
statusCounts[statusName] = occurrenceIndex
283289

284-
for (span in spans) {
285-
val statuses = span.getStatuses()
286-
val startTime = span.getStartTimeInNanoSeconds()
290+
val timeSinceStartMs = TimeUnit.NANOSECONDS.toMillis(timestamp - startTime)
287291

288-
// Find this status in the span
289-
val statusIndex = statuses.indexOfFirst { it.first == statusName }
290-
if (statusIndex >= 0) {
291-
val entry = statuses[statusIndex]
292-
val timeSinceStartMs = TimeUnit.NANOSECONDS.toMillis(entry.second - startTime)
292+
val previousTime = if (statusIndex > 0) {
293+
statuses[statusIndex - 1].second
294+
} else {
295+
startTime
296+
}
297+
val timeSincePreviousMs = TimeUnit.NANOSECONDS.toMillis(timestamp - previousTime)
293298

294-
val previousTime = if (statusIndex > 0) {
295-
statuses[statusIndex - 1].second
296-
} else {
297-
startTime
298-
}
299-
val timeSincePreviousMs = TimeUnit.NANOSECONDS.toMillis(entry.second - previousTime)
299+
val occurrence = StatusOccurrence(statusName, occurrenceIndex)
300+
statusOccurrencesMap.getOrPut(occurrence) { mutableListOf() }
301+
.add(Pair(timeSincePreviousMs, timeSinceStartMs))
302+
}
303+
}
300304

301-
timeSincePreviousValues.add(timeSincePreviousMs)
302-
timeSinceStartValues.add(timeSinceStartMs)
303-
}
305+
val result = mutableListOf<StatisticalStatusData>()
306+
307+
for ((occurrence, timingPairs) in statusOccurrencesMap) {
308+
val timeSincePreviousValues = timingPairs.map { it.first }
309+
val timeSinceStartValues = timingPairs.map { it.second }
310+
311+
// Create display name with occurrence number if there are multiple occurrences
312+
val displayName = if (statusOccurrencesMap.keys.count { it.statusName == occurrence.statusName } > 1) {
313+
"${occurrence.statusName} [${occurrence.occurrenceIndex}]"
314+
} else {
315+
occurrence.statusName
304316
}
305317

306-
if (timeSincePreviousValues.isNotEmpty()) {
307-
result.add(
308-
StatisticalStatusData(
309-
statusName = statusName,
310-
timeSinceStartStats = calculateMetrics(timeSinceStartValues),
311-
timeSincePreviousStats = calculateMetrics(timeSincePreviousValues)
312-
)
318+
result.add(
319+
StatisticalStatusData(
320+
statusName = displayName,
321+
timeSinceStartStats = calculateMetrics(timeSinceStartValues),
322+
timeSincePreviousStats = calculateMetrics(timeSincePreviousValues)
313323
)
314-
}
324+
)
315325
}
316326

317327
// Sort by the first configured metric's Time Since Start value, or by status name if no metrics

0 commit comments

Comments
 (0)