MetricsAdminI.java
// Copyright (c) ZeroC, Inc.
package com.zeroc.Ice;
import com.zeroc.IceMX.Metrics;
import com.zeroc.IceMX.MetricsAdmin;
import com.zeroc.IceMX.MetricsFailures;
import com.zeroc.IceMX.UnknownMetricsView;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
/**
* @hidden Public because it's used by IceMX.
*/
public class MetricsAdminI
implements MetricsAdmin, Consumer<Map<String, String>> {
private static final String[] suffixes = {
"Disabled", "GroupBy", "Accept.*", "Reject.*", "RetainDetached", "Map.*",
};
static void validateProperties(String prefix, Properties properties) {
Map<String, String> props = properties.getPropertiesForPrefix(prefix);
List<String> unknownProps = new ArrayList<>();
for (String prop : props.keySet()) {
boolean valid = false;
for (String suffix : suffixes) {
if (StringUtil.match(prop, prefix + suffix, false)) {
valid = true;
break;
}
}
if (!valid) {
unknownProps.add(prop);
}
}
if (unknownProps.size() > 0) {
throw new PropertyException(
"found unknown IceMX properties for:"
+ ": '"
+ prefix
+ "'\n "
+ String.join("\n ", unknownProps));
}
}
static class MetricsMapFactory<T extends Metrics> {
public MetricsMapFactory(Runnable updater, Class<T> cl) {
_updater = updater;
_class = cl;
}
public void update() {
assert (_updater != null);
_updater.run();
}
public MetricsMap<T> create(String mapPrefix, Properties properties) {
return new MetricsMap<T>(mapPrefix, _class, properties, _subMaps);
}
public <S extends Metrics> void registerSubMap(
String subMap, Class<S> cl, java.lang.reflect.Field field) {
_subMaps.put(subMap, new MetricsMap.SubMapFactory<S>(cl, field));
}
private final Runnable _updater;
private final Class<T> _class;
private final Map<String, MetricsMap.SubMapFactory<?>> _subMaps =
new HashMap<>();
}
public MetricsAdminI(Properties properties, Logger logger) {
_logger = logger;
_properties = properties;
updateViews();
}
public void updateViews() {
Set<MetricsMapFactory<?>> updatedMaps = new HashSet<>();
synchronized (this) {
String viewsPrefix = "IceMX.Metrics.";
Map<String, String> viewsProps =
_properties.getPropertiesForPrefix(viewsPrefix);
Map<String, MetricsViewI> views = new HashMap<>();
_disabledViews.clear();
for (Map.Entry<String, String> e : viewsProps.entrySet()) {
String viewName = e.getKey().substring(viewsPrefix.length());
int dotPos = viewName.indexOf('.');
if (dotPos > 0) {
viewName = viewName.substring(0, dotPos);
}
if (views.containsKey(viewName) || _disabledViews.contains(viewName)) {
continue; // View already configured.
}
validateProperties(viewsPrefix + viewName + '.', _properties);
if (_properties.getPropertyAsIntWithDefault(viewsPrefix + viewName + ".Disabled", 0)
> 0) {
_disabledViews.add(viewName);
continue; // The view is disabled
}
//
// Create the view or update it.
//
MetricsViewI v = _views.get(viewName);
if (v == null) {
v = new MetricsViewI(viewName);
}
views.put(viewName, v);
for (Map.Entry<String, MetricsMapFactory<?>> f : _factories.entrySet()) {
if (v.addOrUpdateMap(_properties, f.getKey(), f.getValue(), _logger)) {
updatedMaps.add(f.getValue());
}
}
}
Map<String, MetricsViewI> tmp = _views;
_views = views;
views = tmp;
//
// Go through removed views to collect maps to update.
//
for (Map.Entry<String, MetricsViewI> v : views.entrySet()) {
if (!_views.containsKey(v.getKey())) {
for (String n : v.getValue().getMaps()) {
updatedMaps.add(_factories.get(n));
}
}
}
}
//
// Call the updaters to update the maps.
//
for (MetricsMapFactory<?> f : updatedMaps) {
f.update();
}
}
@Override
public synchronized MetricsAdmin.GetMetricsViewNamesResult getMetricsViewNames(
Current current) {
MetricsAdmin.GetMetricsViewNamesResult r = new MetricsAdmin.GetMetricsViewNamesResult();
r.disabledViews = _disabledViews.toArray(new String[_disabledViews.size()]);
r.returnValue = _views.keySet().toArray(new String[_views.size()]);
return r;
}
@Override
public void enableMetricsView(String name, Current current) throws UnknownMetricsView {
synchronized (this) {
getMetricsView(name); // Throws if unknown view.
_properties.setProperty("IceMX.Metrics." + name + ".Disabled", "0");
}
updateViews();
}
@Override
public void disableMetricsView(String name, Current current) throws UnknownMetricsView {
synchronized (this) {
getMetricsView(name); // Throws if unknown view.
_properties.setProperty("IceMX.Metrics." + name + ".Disabled", "1");
}
updateViews();
}
@Override
public synchronized MetricsAdmin.GetMetricsViewResult getMetricsView(
String viewName, Current current) throws UnknownMetricsView {
MetricsAdmin.GetMetricsViewResult r = new MetricsAdmin.GetMetricsViewResult();
MetricsViewI view = getMetricsView(viewName);
r.timestamp = Time.currentMonotonicTimeMillis();
if (view != null) {
r.returnValue = view.getMetrics();
} else {
r.returnValue = new HashMap<>();
}
return r;
}
@Override
public synchronized MetricsFailures[] getMapMetricsFailures(
String viewName, String mapName, Current current) throws UnknownMetricsView {
MetricsViewI view = getMetricsView(viewName);
if (view != null) {
return view.getFailures(mapName);
}
return new MetricsFailures[0];
}
@Override
public synchronized MetricsFailures getMetricsFailures(
String viewName, String mapName, String id, Current current) throws UnknownMetricsView {
MetricsViewI view = getMetricsView(viewName);
if (view != null) {
return view.getFailures(mapName, id);
}
return new MetricsFailures();
}
public <T extends Metrics> void registerMap(String map, Class<T> cl, Runnable updater) {
boolean updated;
MetricsMapFactory<T> factory;
synchronized (this) {
factory = new MetricsMapFactory<T>(updater, cl);
_factories.put(map, factory);
updated = addOrUpdateMap(map, factory);
}
if (updated) {
factory.update();
}
}
public synchronized <S extends Metrics> void registerSubMap(
String map, String subMap, Class<S> cl, java.lang.reflect.Field field) {
boolean updated;
MetricsMapFactory<?> factory;
synchronized (this) {
factory = _factories.get(map);
if (factory == null) {
return;
}
factory.registerSubMap(subMap, cl, field);
removeMap(map);
updated = addOrUpdateMap(map, factory);
}
if (updated) {
factory.update();
}
}
public void unregisterMap(String mapName) {
boolean updated;
MetricsMapFactory<?> factory;
synchronized (this) {
factory = _factories.remove(mapName);
if (factory == null) {
return;
}
updated = removeMap(mapName);
}
if (updated) {
factory.update();
}
}
public <T extends Metrics> List<MetricsMap<T>> getMaps(String mapName, Class<T> cl) {
List<MetricsMap<T>> maps = new ArrayList<>();
for (MetricsViewI v : _views.values()) {
MetricsMap<T> map = v.getMap(mapName, cl);
if (map != null) {
maps.add(map);
}
}
return maps;
}
public Logger getLogger() {
return _logger;
}
@Override
public void accept(Map<String, String> props) {
for (Map.Entry<String, String> e : props.entrySet()) {
if (e.getKey().indexOf("IceMX.") == 0) {
// Update the metrics views using the new configuration.
try {
updateViews();
} catch (Exception ex) {
_logger.warning(
"unexpected exception while updating metrics view configuration:\n"
+ ex.toString());
}
return;
}
}
}
private MetricsViewI getMetricsView(String name) throws UnknownMetricsView {
MetricsViewI view = _views.get(name);
if (view == null) {
if (!_disabledViews.contains(name)) {
throw new UnknownMetricsView();
}
return null;
}
return view;
}
private boolean addOrUpdateMap(String mapName, MetricsMapFactory<?> factory) {
boolean updated = false;
for (MetricsViewI v : _views.values()) {
updated |= v.addOrUpdateMap(_properties, mapName, factory, _logger);
}
return updated;
}
private boolean removeMap(String mapName) {
boolean updated = false;
for (MetricsViewI v : _views.values()) {
updated |= v.removeMap(mapName);
}
return updated;
}
private final Properties _properties;
private final Logger _logger;
private final Map<String, MetricsMapFactory<?>> _factories =
new HashMap<>();
private Map<String, MetricsViewI> _views = new HashMap<>();
private final Set<String> _disabledViews = new HashSet<>();
}