package io.pcp.parfait.timing; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Strings; import com.google.common.base.Function; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; public class InProgressSnapshot { private static final Logger LOG = LoggerFactory.getLogger(InProgressSnapshot.class); public static final Function<InProgressSnapshot, String> TO_TABBED_STRING = new InProgressFormatter(); public static final Function<InProgressSnapshot, String> TO_FORMATTED_STRING = new InProgressFormatter() { @Override protected String formatColumnValue(String value) { return Strings.padStart(value, 20, ' '); } }; private final List<String> names = new ArrayList<String>(); private final List<String> descriptions = new ArrayList<String>(); private final List<Class<?>> classes = new ArrayList<Class<?>>(); private final List<Map<String, Object>> values = Lists.newArrayList(); private InProgressSnapshot(EventTimer timer, ThreadContext context) { names.add("Thread name"); descriptions.add("Thread name"); classes.add(String.class); names.add("Thread ID"); descriptions.add("Thread ID"); classes.add(Long.class); names.add("Event"); descriptions.add("Event"); classes.add(String.class); for (ThreadMetric metric : timer.getMetricSuite().metrics()) { names.add(metric.getMetricName()); descriptions.add(metric.getDescription()); classes.add(Long.class); } Collection<String> contextKeys = (context == null) ? Collections.<String> emptyList() : context.allKeys(); for (String contextEntry : contextKeys) { names.add(contextEntry); descriptions.add(contextEntry); classes.add(String.class); } for (Map.Entry<Thread, EventMetricCollector> entry : timer.getCollectorThreadMap() .entrySet()) { StepMeasurements m = entry.getValue().getInProgressMeasurements(); if (m != null) { String event = m.getBackTrace(); Map<ThreadMetric, Long> snapshotValues = m.snapshotValues(); Map<String, Object> keyedValues = new HashMap<String, Object>(); keyedValues.put("Thread name", entry.getKey().getName()); keyedValues.put("Thread ID", entry.getKey().getId()); keyedValues.put("Event", event); for (ThreadMetric metric : timer.getMetricSuite().metrics()) { keyedValues.put(metric.getMetricName(), snapshotValues.get(metric)); LOG.trace(String.format("Thread %s in event %s, metric %s has value %s", entry .getKey(), event, metric, snapshotValues.get(metric))); } for (String contextEntry : contextKeys) { keyedValues.put(contextEntry, String.valueOf(context.getForThread(entry .getKey(), contextEntry))); } values.add(keyedValues); } } } public int getColumnCount() { return names.size(); } public List<Map<String, Object>> getValues() { return ImmutableList.copyOf(values); } public Collection<String> getColumnDescriptions() { return ImmutableList.copyOf(descriptions); } public Collection<String> getColumnNames() { return ImmutableList.copyOf(names); } public List<Class<?>> getColumnClasses() { return ImmutableList.copyOf(classes); } public static InProgressSnapshot capture(EventTimer timer, ThreadContext context) { return new InProgressSnapshot(timer, context); } public String asTabbedString() { return TO_TABBED_STRING.apply(this); } public String asFormattedString() { return TO_FORMATTED_STRING.apply(this); } private static class InProgressFormatter implements Function<InProgressSnapshot, String> { @Override public String apply(InProgressSnapshot from) { StringBuilder result = new StringBuilder(); for (String column : from.getColumnNames()) { result.append(formatColumnValue(column)).append("\t"); } result.append("\n"); for (Map<String, Object> rowData : from.getValues()) { for (String column : from.getColumnNames()) { result.append(formatColumnValue(String.valueOf(rowData.get(column)))).append( "\t"); } result.append("\n"); } return result.toString(); } protected String formatColumnValue(String value) { return value; } } }