in apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/TransactionImpl.java [512:559]
private void trackMetrics() {
try {
phaser.readerLock();
phaser.flipPhase();
// timers are guaranteed to be stable now
// - no concurrent updates possible as finished is true
// - no other thread is running the incrementTimer method,
// as flipPhase only returns when all threads have exited that method
final String type = getType();
if (type == null) {
return;
}
labelsMutable.resetState();
labelsMutable.serviceName(getTraceContext().getServiceName())
.serviceVersion(getTraceContext().getServiceVersion())
.transactionName(name)
.transactionType(type);
final MetricRegistry metricRegistry = tracer.getMetricRegistry();
long criticalValueAtEnter = metricRegistry.writerCriticalSectionEnter();
try {
if (collectBreakdownMetrics) {
List<String> types = timerBySpanTypeAndSubtype.keyList();
for (int i = 0; i < types.size(); i++) {
String spanType = types.get(i);
KeyListConcurrentHashMap<String, Timer> timerBySubtype = timerBySpanTypeAndSubtype.get(spanType);
List<String> subtypes = timerBySubtype.keyList();
for (int j = 0; j < subtypes.size(); j++) {
String subtype = subtypes.get(j);
final Timer timer = timerBySubtype.get(subtype);
if (timer.getCount() > 0) {
if (subtype.equals("")) {
subtype = null;
}
labelsMutable.spanType(spanType).spanSubType(subtype);
metricRegistry.updateTimer("span.self_time", labelsMutable, timer.getTotalTimeUs(), timer.getCount());
timer.resetState();
}
}
}
}
} finally {
metricRegistry.writerCriticalSectionExit(criticalValueAtEnter);
}
} finally {
phaser.readerUnlock();
}
}