Manage complete "event rules" in the Java agent
authorAlexandre Montplaisir <alexmonthy@efficios.com>
Thu, 27 Aug 2015 00:10:50 +0000 (20:10 -0400)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Thu, 22 Oct 2015 20:54:54 +0000 (16:54 -0400)
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 <alexmonthy@efficios.com>
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
liblttng-ust-java-agent/java/lttng-ust-agent-common/Makefile.am
liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/AbstractLttngAgent.java
liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/ILttngTcpClientListener.java
liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondEnableEventCommand.java
liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/session/EventRule.java [new file with mode: 0644]
liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/session/LogLevelSelector.java [new file with mode: 0644]

index bbf98f643bb8d88bf29ba196f273060e0d94223a..6b961b55e247ed7592fdd07a946e9047f4852b8e 100644 (file)
@@ -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
index c3fc339bc628b09234e1ed41962f2197fb221b8f..ef3b1dbe9afddddd5922a0e91d9999254c40209e 100644 (file)
@@ -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<T extends ILttngHandler>
         * 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<String, Integer> enabledEvents = new ConcurrentHashMap<String, Integer>();
@@ -189,12 +190,13 @@ public abstract class AbstractLttngAgent<T extends ILttngHandler>
        }
 
        @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);
index 662b998283eb33902fd6d2e6ff15d95c4571cf8b..031d4e048863c4e74802e03a90029c17401b6896 100644 (file)
@@ -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
index 82204eb19b895af2d22eca200169769f40d59114..388edc7d328afcaaf1134cc5f45d2d5023b60b6c 100644 (file)
@@ -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 (file)
index 0000000..c25045d
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2015 - EfficiOS Inc., Alexandre Montplaisir <alexmonthy@efficios.com>
+ *
+ * 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 (file)
index 0000000..87d4172
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2015 - EfficiOS Inc., Alexandre Montplaisir <alexmonthy@efficios.com>
+ *
+ * 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;
+       }
+}
This page took 0.031195 seconds and 5 git commands to generate.