/*
* Copyright 2015-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.glowroot.common.repo.util;
import java.util.List;
import java.util.regex.Pattern;
import com.google.common.base.CharMatcher;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import org.glowroot.common.repo.GaugeValueRepository.Gauge;
import org.glowroot.common.repo.ImmutableGauge;
public class Gauges {
public static final String DISPLAY_PATH_SEPARATOR = " / ";
private static final ImmutableList<UnitPattern> unitPatterns;
private static final String GROUPING_PREFIX = "grouping-";
static {
List<UnitPattern> patterns = Lists.newArrayList();
patterns.add(new UnitPattern(
"java.lang:type=Memory:(Non)?HeapMemoryUsage\\.(init|used|committed|max)",
"bytes"));
patterns.add(new UnitPattern(
"java.lang:type=OperatingSystem:(Free|Total)(Physical|Swap)MemorySize", "bytes"));
patterns.add(
new UnitPattern("java.lang:type=OperatingSystem:(ProcessCpuLoad|SystemCpuLoad)",
GROUPING_PREFIX + "1"));
patterns.add(new UnitPattern("java.lang:type=Runtime:Uptime", "milliseconds"));
patterns.add(new UnitPattern("java.lang:type=Threading:CurrentThread(Cpu|User)Time",
"nanoseconds"));
patterns.add(new UnitPattern("java.lang:type=MemoryPool,name=[^:]+:(Peak)?Usage"
+ "\\.(init|used|committed|max)", "bytes"));
patterns.add(new UnitPattern(
"java.lang:type=GarbageCollector,name=[^:]+:LastGcInfo\\.duration",
"milliseconds"));
patterns.add(new UnitPattern("java.lang:type=GarbageCollector,name=[^:]+:CollectionTime",
"milliseconds"));
patterns.add(new UnitPattern("java.lang:type=GarbageCollector,name=[^:]+:CollectionCount",
GROUPING_PREFIX + "2"));
patterns.add(
new UnitPattern("java.lang:type=Compilation:TotalCompilationTime", "milliseconds"));
patterns.add(new UnitPattern("sun.management:type=HotspotRuntime:SafepointSyncTime",
"milliseconds"));
patterns.add(new UnitPattern("sun.management:type=HotspotRuntime:TotalSafepointTime",
"milliseconds"));
patterns.add(new UnitPattern("org.glowroot:type=FileSystem,name=[^:]+:(Total|Free)Space",
"bytes"));
patterns.add(
new UnitPattern("org.glowroot:type=FileSystem,name=[^:]+:PercentFull", "percent"));
patterns.add(new UnitPattern("org.apache.cassandra.metrics:type=ColumnFamily,"
+ "keyspace=[^,]+,scope=[^,]+,name=LiveDiskSpaceUsed:Count", "bytes"));
patterns.add(new UnitPattern("org.apache.cassandra.metrics:type=ColumnFamily,"
+ "keyspace=[^,]+,scope=[^,]+,name=TotalDiskSpaceUsed:Count", "bytes"));
unitPatterns = ImmutableList.copyOf(patterns);
}
private Gauges() {}
public static Gauge getGauge(String gaugeName) {
int index = gaugeName.lastIndexOf(':');
String mbeanObjectName = gaugeName.substring(0, index);
String mbeanAttributeName = gaugeName.substring(index + 1);
boolean counter = mbeanAttributeName.endsWith("[counter]");
if (counter) {
mbeanAttributeName = mbeanAttributeName.substring(0,
mbeanAttributeName.length() - "[counter]".length());
}
mbeanAttributeName = mbeanAttributeName.replaceAll("\\.", DISPLAY_PATH_SEPARATOR);
List<String> displayPath = displayPath(mbeanObjectName);
displayPath.addAll(Splitter.on('.').splitToList(mbeanAttributeName));
String display = Joiner.on(DISPLAY_PATH_SEPARATOR).join(displayPath);
String unit = unit(gaugeName);
ImmutableGauge.Builder gauge = ImmutableGauge.builder()
.name(gaugeName)
.display(display)
.displayPath(displayPath)
.counter(counter)
.grouping(unit);
if (unit.startsWith(GROUPING_PREFIX)) {
if (unit.endsWith(" per second")) {
return gauge.unit("per second").build();
} else {
return gauge.unit("").build();
}
} else {
return gauge.unit(unit).build();
}
}
public static List<String> displayPath(String mbeanObjectName) {
// e.g. java.lang:name=PS Eden Space,type=MemoryPool
List<String> parts = Splitter.on(CharMatcher.anyOf(":,")).splitToList(mbeanObjectName);
List<String> display = Lists.newArrayList();
display.add(parts.get(0));
for (int i = 1; i < parts.size(); i++) {
String part = parts.get(i).split("=")[1];
if (part.startsWith("\"") && part.endsWith("\"")) {
part = part.substring(1, part.length() - 1);
}
if (part.contains("/")) {
// special case since this is also the display path separator
display.add("\"" + part + "\"");
} else {
display.add(part);
}
}
return display;
}
private static String unit(String gaugeName) {
if (gaugeName.endsWith("[counter]")) {
String baseUnit =
getBaseUnit(gaugeName.substring(0, gaugeName.length() - "[counter]".length()));
if (baseUnit.isEmpty()) {
return "per second";
} else {
return baseUnit + " per second";
}
} else {
return getBaseUnit(gaugeName);
}
}
private static String getBaseUnit(String gaugeName) {
for (UnitPattern unitPattern : unitPatterns) {
if (unitPattern.pattern.matcher(gaugeName).matches()) {
return unitPattern.unit;
}
}
return "";
}
private static class UnitPattern {
private final Pattern pattern;
private final String unit;
private UnitPattern(String pattern, String unit) {
this.pattern = Pattern.compile(pattern);
this.unit = unit;
}
}
}