From 3daf5cba66edbd7d8b608be1372a1665189b3c67 Mon Sep 17 00:00:00 2001 From: Alexandre Montplaisir Date: Wed, 26 Aug 2015 20:10:50 -0400 Subject: [PATCH] Manage complete "event rules" in the Java agent Instead of just tracking which event names are enabled in the tracing session, we can track the complete name/filter/loglevel tuple. This allows the same event name to be specified multiple times but with different parameters. Right now the sessiond does not send the filter string, a new protocol version will be required to do so. But we can prepare for it in the meantime. The agent will continue to use the event names to decide if events should be sent through JNI or not. However, full rules will be useable for other purposes, like the upcoming filter notifications. Signed-off-by: Alexandre Montplaisir Signed-off-by: Mathieu Desnoyers --- .../java/lttng-ust-agent-common/Makefile.am | 8 +- .../lttng/ust/agent/AbstractLttngAgent.java | 8 +- .../agent/client/ILttngTcpClientListener.java | 10 +- .../client/SessiondEnableEventCommand.java | 17 +- .../lttng/ust/agent/session/EventRule.java | 134 ++++++++++++ .../ust/agent/session/LogLevelSelector.java | 191 ++++++++++++++++++ 6 files changed, 354 insertions(+), 14 deletions(-) create mode 100644 liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/session/EventRule.java create mode 100644 liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/session/LogLevelSelector.java diff --git a/liblttng-ust-java-agent/java/lttng-ust-agent-common/Makefile.am b/liblttng-ust-java-agent/java/lttng-ust-agent-common/Makefile.am index bbf98f64..6b961b55 100644 --- a/liblttng-ust-java-agent/java/lttng-ust-agent-common/Makefile.am +++ b/liblttng-ust-java-agent/java/lttng-ust-agent-common/Makefile.am @@ -21,14 +21,16 @@ dist_noinst_JAVA = $(pkgpath)/AbstractLttngAgent.java \ $(pkgpath)/client/SessiondCommandHeader.java \ $(pkgpath)/client/SessiondDisableEventCommand.java \ $(pkgpath)/client/SessiondEnableEventCommand.java \ - $(pkgpath)/client/SessiondListLoggersCommand.java + $(pkgpath)/client/SessiondListLoggersCommand.java \ + $(pkgpath)/session/EventRule.java \ + $(pkgpath)/session/LogLevelSelector.java dist_noinst_DATA = $(jarfile_manifest) jar_DATA = $(jarfile) -classes = $(pkgpath)/*.class $(pkgpath)/client/*.class +classes = $(pkgpath)/*.class $(pkgpath)/client/*.class $(pkgpath)/session/*.class $(jarfile): classnoinst.stamp $(JAR) cfm $(JARFLAGS) $@ $(jarfile_manifest) $(classes) && rm -f $(jarfile_symlink) && $(LN_S) $@ $(jarfile_symlink) @@ -41,4 +43,4 @@ install-data-hook: uninstall-hook: cd $(DESTDIR)/$(jardir) && rm -f $(jarfile_symlink) -CLEANFILES = $(jarfile) $(pkgpath)/*.class $(pkgpath)/client/*.class +CLEANFILES = $(jarfile) $(pkgpath)/*.class $(pkgpath)/client/*.class $(pkgpath)/session/*.class diff --git a/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/AbstractLttngAgent.java b/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/AbstractLttngAgent.java index c3fc339b..ef3b1dbe 100644 --- a/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/AbstractLttngAgent.java +++ b/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/AbstractLttngAgent.java @@ -30,6 +30,7 @@ import java.util.concurrent.atomic.AtomicInteger; import org.lttng.ust.agent.client.ILttngTcpClientListener; import org.lttng.ust.agent.client.LttngTcpSessiondClient; +import org.lttng.ust.agent.session.EventRule; /** * Base implementation of a {@link ILttngAgent}. @@ -55,7 +56,7 @@ public abstract class AbstractLttngAgent * falls to 0, this means we can avoid sending log events through JNI * because nobody wants them. * - * It uses a concurrent hash set", so that the {@link #isEventEnabled} and + * It uses a concurrent hash map, so that the {@link #isEventEnabled} and * read methods do not need to take a synchronization lock. */ private final Map enabledEvents = new ConcurrentHashMap(); @@ -189,12 +190,13 @@ public abstract class AbstractLttngAgent } @Override - public boolean eventEnabled(String eventName) { + public boolean eventEnabled(EventRule eventRule) { + String eventName = eventRule.getEventName(); + if (eventName.equals(WILDCARD)) { enabledWildcards.incrementAndGet(); return true; } - if (eventName.endsWith(WILDCARD)) { /* Strip the "*" from the name. */ String prefix = eventName.substring(0, eventName.length() - 1); diff --git a/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/ILttngTcpClientListener.java b/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/ILttngTcpClientListener.java index 662b9982..031d4e04 100644 --- a/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/ILttngTcpClientListener.java +++ b/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/ILttngTcpClientListener.java @@ -17,6 +17,8 @@ package org.lttng.ust.agent.client; +import org.lttng.ust.agent.session.EventRule; + /** * TCP client listener interface. * @@ -30,14 +32,14 @@ public interface ILttngTcpClientListener { /** * Callback for the TCP client to notify the listener agent that a request - * for enabling an event was sent from the session daemon. + * for enabling an event rule was sent from the session daemon. * - * @param eventName - * The name of the event that was requested to be enabled. + * @param eventRule + * The event rule that was requested to be enabled * @return Since we do not track individual sessions, right now this command * cannot fail. It will always return true. */ - boolean eventEnabled(String eventName); + boolean eventEnabled(EventRule eventRule); /** * Callback for the TCP client to notify the listener agent that a request diff --git a/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondEnableEventCommand.java b/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondEnableEventCommand.java index 82204eb1..388edc7d 100644 --- a/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondEnableEventCommand.java +++ b/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondEnableEventCommand.java @@ -21,6 +21,9 @@ package org.lttng.ust.agent.client; import java.nio.ByteBuffer; import java.nio.ByteOrder; +import org.lttng.ust.agent.session.EventRule; +import org.lttng.ust.agent.session.LogLevelSelector; + /** * Session daemon command indicating to the Java agent that some events were * enabled in the tracing session. @@ -32,8 +35,10 @@ class SessiondEnableEventCommand implements ISessiondCommand { private static final int INT_SIZE = 4; - /** Event name to enable in the tracing session */ + /* Parameters of the event rule being enabled */ private final String eventName; + private final LogLevelSelector logLevelFilter; + private final String filterString; public SessiondEnableEventCommand(byte[] data) { if (data == null) { @@ -43,14 +48,18 @@ class SessiondEnableEventCommand implements ISessiondCommand { ByteBuffer buf = ByteBuffer.wrap(data); buf.order(ByteOrder.LITTLE_ENDIAN); - buf.getInt(); // logLevel, currently unused - buf.getInt(); // logLevelType, currently unused + int logLevel = buf.getInt(); + int logLevelType = buf.getInt(); + logLevelFilter = new LogLevelSelector(logLevel, logLevelType); + eventName = new String(data, dataOffset, data.length - dataOffset).trim(); + filterString = null; /* Not yet sent by the sessiond */ } @Override public LttngAgentResponse execute(ILttngTcpClientListener agent) { - boolean success = agent.eventEnabled(this.eventName); + EventRule rule = new EventRule(eventName, logLevelFilter, filterString); + boolean success = agent.eventEnabled(rule); return (success ? LttngAgentResponse.SUCESS_RESPONSE : LttngAgentResponse.FAILURE_RESPONSE); } } diff --git a/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/session/EventRule.java b/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/session/EventRule.java new file mode 100644 index 00000000..c25045d9 --- /dev/null +++ b/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/session/EventRule.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2015 - EfficiOS Inc., Alexandre Montplaisir + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License, version 2.1 only, + * as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package org.lttng.ust.agent.session; + +/** + * Event filtering rule present in a tracing session. + * + * It typically comes from a "lttng enable-event" command, and contains a + * domain, event name, log level and filter string. + * + * @author Alexandre Montplaisir + */ +public class EventRule { + + private final String eventName; + private final LogLevelSelector logLevelSelector; + private final String filterString; + + /** + * Constructor. + * + * @param eventName + * The name of the tracepoint + * @param logLevelSelector + * The log level of the event rule + * @param filterString + * The filtering string. May be null if there is no extra filter. + */ + public EventRule(String eventName, LogLevelSelector logLevelSelector, String filterString) { + this.eventName = eventName; + this.logLevelSelector = logLevelSelector; + this.filterString = filterString; + } + + /** + * Get the event name of this rule. + * + * @return The event name + */ + public String getEventName() { + return eventName; + } + + /** + * Get the log level filter configuration of the rule. + * + * @return The log level selector + */ + public LogLevelSelector getLogLevelSelector() { + return logLevelSelector; + } + + /** + * Get the filter string associated with this rule. + * + * @return The filter string, may be null for no filter string. + */ + public String getFilterString() { + return filterString; + } + + // ------------------------------------------------------------------------ + // Methods from Object + // ------------------------------------------------------------------------ + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((eventName == null) ? 0 : eventName.hashCode()); + result = prime * result + ((filterString == null) ? 0 : filterString.hashCode()); + result = prime * result + ((logLevelSelector == null) ? 0 : logLevelSelector.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + EventRule other = (EventRule) obj; + + if (eventName == null) { + if (other.eventName != null) { + return false; + } + } else if (!eventName.equals(other.eventName)) { + return false; + } + /* else, continue */ + + if (filterString == null) { + if (other.filterString != null) { + return false; + } + } else if (!filterString.equals(other.filterString)) { + return false; + } + /* else, continue */ + + if (logLevelSelector == null) { + if (other.logLevelSelector != null) { + return false; + } + } else if (!logLevelSelector.equals(other.logLevelSelector)) { + return false; + } + /* else, continue */ + + return true; + } + +} diff --git a/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/session/LogLevelSelector.java b/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/session/LogLevelSelector.java new file mode 100644 index 00000000..87d4172c --- /dev/null +++ b/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/session/LogLevelSelector.java @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2015 - EfficiOS Inc., Alexandre Montplaisir + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License, version 2.1 only, + * as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package org.lttng.ust.agent.session; + +/** + * Log level filtering element, which is part of an {@link EventRule}. + * + * @author Alexandre Montplaisir + */ +public class LogLevelSelector { + + /** + * The type of log level filter that is enabled. + * + * Defined from lttng-tools' include/lttng/event.h. + */ + public enum LogLevelType { + /** + * All log levels are enabled. This overrides the value of + * {@link LogLevelSelector#getLogLevel}. + */ + LTTNG_EVENT_LOGLEVEL_ALL(0), + + /** This log level along with all log levels of higher severity are enabled. */ + LTTNG_EVENT_LOGLEVEL_RANGE(1), + + /** Only this exact log level is enabled. */ + LTTNG_EVENT_LOGLEVEL_SINGLE(2); + + private final int value; + + private LogLevelType(int value) { + this.value = value; + } + + /** + * Get the numerical (int) value representing this log level type in the + * communication protocol. + * + * @return The int value + */ + public int getValue() { + return value; + } + + static LogLevelType fromValue(int val) { + switch (val) { + case 0: + return LTTNG_EVENT_LOGLEVEL_ALL; + case 1: + return LTTNG_EVENT_LOGLEVEL_RANGE; + case 2: + return LTTNG_EVENT_LOGLEVEL_SINGLE; + default: + throw new IllegalArgumentException(); + } + } + } + + private final int logLevel; + private final LogLevelType logLevelType; + + /** + * Constructor using numerical values straight from the communication + * protocol. + * + * @param logLevel + * The numerical value of the log level. The exact value depends + * on the tracing domain, see include/lttng/event.h in the + * lttng-tools tree for the complete enumeration. + * @param logLevelType + * The numerical value of the log level type. It will be + * converted to a {@link LogLevelType} by this constructor. + * @throws IllegalArgumentException + * If the 'logLevelType' does not correspond to a valid value. + */ + public LogLevelSelector(int logLevel, int logLevelType) { + this.logLevel = logLevel; + this.logLevelType = LogLevelType.fromValue(logLevelType); + } + + /** + * "Manual" constructor, specifying the {@link LogLevelType} directly. + * + * @param logLevel + * The numerical value of the log level. The exact value depends + * on the tracing domain, see include/lttng/event.h in the + * lttng-tools tree for the complete enumeration. + * @param type + * The log level filter type. + */ + public LogLevelSelector(int logLevel, LogLevelType type) { + this.logLevel = logLevel; + this.logLevelType = type; + } + + /** + * Get the numerical value of the log level element. Does not apply if + * {@link #getLogLevelType} returns + * {@link LogLevelType#LTTNG_EVENT_LOGLEVEL_ALL}. + * + * @return The numerical value of the log level + */ + public int getLogLevel() { + return logLevel; + } + + /** + * Get the log level filter type. + * + * @return The log level filter type + */ + public LogLevelType getLogLevelType() { + return logLevelType; + } + + /** + * Helper method to determine if an event with the given log level should be + * traced when considering this filter. + * + * For example, if this filter object represents "higher severity than 5", + * and the log level passed in parameter is "8", it will return that it + * matches (higher value means higher severity). + * + * @param targetLogLevel + * The log level value of the event to check for + * @return Should this event be traced, or not + */ + public boolean matches(int targetLogLevel) { + switch (logLevelType) { + case LTTNG_EVENT_LOGLEVEL_ALL: + return true; + case LTTNG_EVENT_LOGLEVEL_RANGE: + return (targetLogLevel >= logLevel); + case LTTNG_EVENT_LOGLEVEL_SINGLE: + return (targetLogLevel == logLevel); + default: + throw new IllegalStateException(); + } + } + + // ------------------------------------------------------------------------ + // Methods from Object + // ------------------------------------------------------------------------ + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + logLevel; + result = prime * result + ((logLevelType == null) ? 0 : logLevelType.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + LogLevelSelector other = (LogLevelSelector) obj; + + if (logLevel != other.logLevel) { + return false; + } + if (logLevelType != other.logLevelType) { + return false; + } + return true; + } +} -- 2.34.1