|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package jdk.jfr.internal; |
|
|
|
import java.util.ArrayList; |
|
import java.util.Collection; |
|
import java.util.Collections; |
|
import java.util.HashMap; |
|
import java.util.HashSet; |
|
import java.util.LinkedHashMap; |
|
import java.util.List; |
|
import java.util.Map; |
|
import java.util.Map.Entry; |
|
import java.util.Set; |
|
import java.util.StringJoiner; |
|
|
|
import jdk.jfr.Event; |
|
import jdk.jfr.internal.handlers.EventHandler; |
|
|
|
final class SettingsManager { |
|
|
|
private static class InternalSetting { |
|
|
|
private final String identifier; |
|
private Map<String, Set<String>> enabledMap = new LinkedHashMap<>(5); |
|
private Map<String, Set<String>> allMap = new LinkedHashMap<>(5); |
|
private boolean enabled; |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public InternalSetting(String settingsId) { |
|
this.identifier = settingsId; |
|
} |
|
|
|
public Set<String> getValues(String key) { |
|
if (enabled) { |
|
return enabledMap.get(key); |
|
} else { |
|
return allMap.get(key); |
|
} |
|
} |
|
|
|
public void add(String attribute, String value) { |
|
if ("enabled".equals(attribute) && "true".equals(value)) { |
|
enabled = true; |
|
allMap = null; |
|
} |
|
addToMap(enabledMap, attribute, value); |
|
if (allMap != null) { |
|
addToMap(allMap, attribute, value); |
|
} |
|
} |
|
|
|
private void addToMap(Map<String, Set<String>> map, String attribute, String value) { |
|
Set<String> values = map.get(attribute); |
|
if (values == null) { |
|
values = new HashSet<String>(5); |
|
map.put(attribute, values); |
|
} |
|
values.add(value); |
|
|
|
} |
|
|
|
public String getSettingsId() { |
|
return identifier; |
|
} |
|
|
|
public void add(InternalSetting enabled) { |
|
for (Map.Entry<String, Set<String>> entry : enabled.enabledMap.entrySet()) { |
|
for (String value : entry.getValue()) { |
|
add(entry.getKey(), value); |
|
} |
|
} |
|
} |
|
|
|
public boolean isEnabled() { |
|
return enabled; |
|
} |
|
|
|
@Override |
|
public String toString() { |
|
StringBuilder sb = new StringBuilder(); |
|
sb.append(identifier); |
|
sb.append(": "); |
|
sb.append(enabledMap.toString()); |
|
return sb.toString(); |
|
} |
|
|
|
public void finish() { |
|
if (!enabled) { |
|
// settings from disabled |
|
// events should not impact results, but |
|
// we can't clear enabledMap since enabled=false |
|
// needs be there, so events that are enabled |
|
|
|
Map<String, Set<String>> disabledMap = new HashMap<>(2); |
|
Set<String> values = new HashSet<>(2); |
|
values.add("false"); |
|
disabledMap.put("enabled", values); |
|
enabledMap = disabledMap; |
|
} |
|
} |
|
} |
|
|
|
private Map<String, InternalSetting> availableSettings = new LinkedHashMap<>(); |
|
|
|
void setSettings(List<Map<String, String>> activeSettings) { |
|
|
|
availableSettings = createSettingsMap(activeSettings); |
|
List<EventControl> eventControls = MetadataRepository.getInstance().getEventControls(); |
|
if (!JVM.getJVM().isRecording()) { |
|
for (EventControl ec : eventControls) { |
|
ec.disable(); |
|
} |
|
} else { |
|
if (Logger.shouldLog(LogTag.JFR_SETTING, LogLevel.INFO)) { |
|
Collections.sort(eventControls, (x,y) -> x.getEventType().getName().compareTo(y.getEventType().getName())); |
|
} |
|
for (EventControl ec : eventControls) { |
|
setEventControl(ec); |
|
} |
|
} |
|
if (JVM.getJVM().getAllowedToDoEventRetransforms()) { |
|
updateRetransform(JVM.getJVM().getAllEventClasses()); |
|
} |
|
} |
|
|
|
public void updateRetransform(List<Class<? extends Event>> eventClasses) { |
|
List<Class<?>> classes = new ArrayList<>(); |
|
for(Class<? extends Event> eventClass: eventClasses) { |
|
EventHandler eh = Utils.getHandler(eventClass); |
|
if (eh != null ) { |
|
PlatformEventType eventType = eh.getPlatformEventType(); |
|
if (eventType.isMarkedForInstrumentation()) { |
|
classes.add(eventClass); |
|
eventType.markForInstrumentation(false); |
|
// A bit premature to set it here, but hard to check |
|
|
|
eventType.setInstrumented(); |
|
} |
|
} |
|
} |
|
if (!classes.isEmpty()) { |
|
JVM.getJVM().retransformClasses(classes.toArray(new Class<?>[0])); |
|
} |
|
} |
|
|
|
private Map<String, InternalSetting> createSettingsMap(List<Map<String,String>> activeSettings) { |
|
Map<String, InternalSetting> map = new LinkedHashMap<>(activeSettings.size()); |
|
for (Map<String, String> rec : activeSettings) { |
|
for (InternalSetting internal : makeInternalSettings(rec)) { |
|
InternalSetting is = map.get(internal.getSettingsId()); |
|
if (is == null) { |
|
map.put(internal.getSettingsId(), internal); |
|
} else { |
|
is.add(internal); |
|
} |
|
} |
|
} |
|
return map; |
|
} |
|
|
|
private Collection<InternalSetting> makeInternalSettings(Map<String, String> rec) { |
|
Map<String, InternalSetting> internals = new LinkedHashMap<>(); |
|
for (Map.Entry<String, String> entry : rec.entrySet()) { |
|
String key = entry.getKey(); |
|
String value = entry.getValue(); |
|
int index = key.indexOf("#"); |
|
if (index > 1 && index < key.length() - 2) { |
|
String eventName = key.substring(0, index); |
|
eventName = Utils.upgradeLegacyJDKEvent(eventName); |
|
InternalSetting s = internals.get(eventName); |
|
String settingName = key.substring(index + 1).trim(); |
|
if (s == null) { |
|
s = new InternalSetting(eventName); |
|
internals.put(eventName, s); |
|
} |
|
s.add(settingName, value); |
|
} |
|
} |
|
for (InternalSetting s : internals.values()) { |
|
s.finish(); |
|
} |
|
|
|
return internals.values(); |
|
} |
|
|
|
void setEventControl(EventControl ec) { |
|
InternalSetting is = getInternalSetting(ec); |
|
Logger.log(LogTag.JFR_SETTING, LogLevel.INFO, "Applied settings for " + ec.getEventType().getLogName() + " {"); |
|
for (Entry<String, Control> entry : ec.getEntries()) { |
|
Set<String> values = null; |
|
String settingName = entry.getKey(); |
|
if (is != null) { |
|
values = is.getValues(settingName); |
|
} |
|
Control control = entry.getValue(); |
|
if (values != null) { |
|
control.apply(values); |
|
String after = control.getLastValue(); |
|
if (Logger.shouldLog(LogTag.JFR_SETTING, LogLevel.INFO)) { |
|
if (Utils.isSettingVisible(control, ec.getEventType().hasEventHook())) { |
|
if (values.size() > 1) { |
|
StringJoiner sj = new StringJoiner(", ", "{", "}"); |
|
for (String s : values) { |
|
sj.add("\"" + s + "\""); |
|
} |
|
String message = " " + settingName + "= " + sj.toString() + " => \"" + after + "\""; |
|
Logger.log(LogTag.JFR_SETTING, LogLevel.INFO, message); |
|
} else { |
|
String message = " " + settingName + "=\"" + control.getLastValue() + "\""; |
|
Logger.log(LogTag.JFR_SETTING, LogLevel.INFO, message); |
|
} |
|
} |
|
} |
|
} else { |
|
control.setDefault(); |
|
if (Logger.shouldLog(LogTag.JFR_SETTING, LogLevel.INFO)) { |
|
String message = " " + settingName + "=\"" + control.getLastValue() + "\""; |
|
Logger.log(LogTag.JFR_SETTING, LogLevel.INFO, message); |
|
} |
|
} |
|
} |
|
ec.writeActiveSettingEvent(); |
|
Logger.log(LogTag.JFR_SETTING, LogLevel.INFO, "}"); |
|
} |
|
|
|
private InternalSetting getInternalSetting(EventControl ec) { |
|
String name = ec.getEventType().getName(); |
|
InternalSetting nameBased = availableSettings.get(name); |
|
InternalSetting idBased = availableSettings.get(ec.getSettingsId()); |
|
|
|
if (nameBased == null && idBased == null) { |
|
return null; |
|
} |
|
if (idBased == null) { |
|
return nameBased; |
|
} |
|
if (nameBased == null) { |
|
return idBased; |
|
} |
|
InternalSetting mixed = new InternalSetting(nameBased.getSettingsId()); |
|
mixed.add(nameBased); |
|
mixed.add(idBased); |
|
return mixed; |
|
} |
|
|
|
@Override |
|
public String toString() { |
|
StringBuilder sb = new StringBuilder(); |
|
for (InternalSetting enabled : availableSettings.values()) { |
|
sb.append(enabled.toString()); |
|
sb.append("\n"); |
|
} |
|
return sb.toString(); |
|
} |
|
|
|
boolean isEnabled(String eventName) { |
|
InternalSetting is = availableSettings.get(eventName); |
|
if (is == null) { |
|
return false; |
|
} |
|
return is.isEnabled(); |
|
} |
|
} |