Implement Java agent application context retrieval
authorAlexandre Montplaisir <alexmonthy@efficios.com>
Thu, 7 Jan 2016 22:43:34 +0000 (17:43 -0500)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Fri, 12 Feb 2016 22:54:29 +0000 (17:54 -0500)
Java application can now register an IContextInfoRetriever to provide
context information. This information can be used for filtering:

  lttng enable-event -j myevent --filter '$app.retriever:context=="something"'

or for saving in the trace directly by enabling the context:

  lttng add-context -j -t '$app.retriever:context'

See the "ApplicationContextExample.java" program for an example of
utilization.

Signed-off-by: Alexandre Montplaisir <alexmonthy@efficios.com>
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
29 files changed:
.gitignore
configure.ac
doc/examples/java-jul/ApplicationContextExample.java [new file with mode: 0644]
doc/examples/java-jul/Makefile
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/ILttngAgent.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/LttngAgentResponse.java
liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/LttngTcpSessiondClient.java
liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondCommand.java
liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondDisableAppContextCommand.java [new file with mode: 0644]
liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondDisableEventCommand.java
liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondEnableAppContextCommand.java [new file with mode: 0644]
liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/context/ContextInfoManager.java
liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/context/ContextInfoSerializer.java [new file with mode: 0644]
liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/context/LttngContextApi.java [new file with mode: 0644]
liblttng-ust-java-agent/java/lttng-ust-agent-jul/org/lttng/ust/agent/jul/LttngJulApi.java
liblttng-ust-java-agent/java/lttng-ust-agent-jul/org/lttng/ust/agent/jul/LttngLogHandler.java
liblttng-ust-java-agent/java/lttng-ust-agent-log4j/org/lttng/ust/agent/log4j/LttngLog4jApi.java
liblttng-ust-java-agent/java/lttng-ust-agent-log4j/org/lttng/ust/agent/log4j/LttngLogAppender.java
liblttng-ust-java-agent/jni/Makefile.am
liblttng-ust-java-agent/jni/common/Makefile.am [new file with mode: 0644]
liblttng-ust-java-agent/jni/common/lttng_ust_context.c [new file with mode: 0644]
liblttng-ust-java-agent/jni/common/lttng_ust_context.h [new file with mode: 0644]
liblttng-ust-java-agent/jni/jul/Makefile.am
liblttng-ust-java-agent/jni/jul/lttng_ust_jul.c
liblttng-ust-java-agent/jni/log4j/Makefile.am
liblttng-ust-java-agent/jni/log4j/lttng_ust_log4j.c

index d480867e5288fdabe86862df7f5cf95a05f197d7..87d55d9cce4179e5f38943802d6bfc753290e0d2 100644 (file)
@@ -59,8 +59,10 @@ tests/benchmark/bench2
 lttng-ust-agent*.jar
 classnoinst.stamp
 jni-header.stamp
+context-jni-header.stamp
 jul-jni-header.stamp
 log4j-jni-header.stamp
+org_lttng_ust_agent_context_LttngContextApi.h
 org_lttng_ust_agent_jul_LttngJulApi.h
 org_lttng_ust_agent_log4j_LttngLog4jApi.h
 
index 9d972ccf2680c273f1fc6f1844c0b0a7372f1675..7dcaab85eaa7cf1815b988b13132b6574a9c91a0 100644 (file)
@@ -389,6 +389,7 @@ AC_CONFIG_FILES([
        liblttng-ust-java-agent/java/lttng-ust-agent-jul/Makefile
        liblttng-ust-java-agent/java/lttng-ust-agent-log4j/Makefile
        liblttng-ust-java-agent/jni/Makefile
+       liblttng-ust-java-agent/jni/common/Makefile
        liblttng-ust-java-agent/jni/jul/Makefile
        liblttng-ust-java-agent/jni/log4j/Makefile
        liblttng-ust-libc-wrapper/Makefile
diff --git a/doc/examples/java-jul/ApplicationContextExample.java b/doc/examples/java-jul/ApplicationContextExample.java
new file mode 100644 (file)
index 0000000..3da3ac8
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2016 - EfficiOS Inc., Alexandre Montplaisir <alexmonthy@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+import java.io.IOException;
+import java.util.logging.Handler;
+import java.util.logging.Logger;
+
+import org.lttng.ust.agent.context.ContextInfoManager;
+import org.lttng.ust.agent.context.IContextInfoRetriever;
+import org.lttng.ust.agent.jul.LttngLogHandler;
+
+/**
+ * Example program defining a application context retriever, which allows
+ * attaching application-defined contexts to trace events.
+ *
+ * FIXME Use custom context names, and several names/types
+ *
+ * <p>
+ * Usage:
+ * <ul>
+ * <li>$ lttng create</li>
+ * <li>$ lttng enable-event -j -a</li>
+ * <li>$ lttng add-context -j -t '$app.myprovider:mystringcontext'</li>
+ * <li>$ lttng add-context -j -t '$app.myprovider:myshortcontext'</li>
+ * <li>$ lttng start</li>
+ * <li>(run this program)</li>
+ * <li>$ lttng stop</li>
+ * <li>$ lttng view</li>
+ * <li>$ lttng destroy</li>
+ * </ul>
+ * </p>
+ *
+ * The events present in the resulting trace should carry the context
+ * information defined in the example retriever.
+ *
+ * @author Alexandre Montplaisir
+ */
+public class ApplicationContextExample {
+
+       /** Class-wide JUL logger object */
+       private static final Logger LOGGER = Logger.getLogger(ApplicationContextExample.class.getName());
+
+       private static final String RETRIEVER_NAME = "myprovider";
+       private static final String CONTEXT_NAME_STRING = "mystringcontext";
+       private static final String CONTEXT_NAME_SHORT = "myshortcontext";
+
+       private static class ExampleContextInfoRetriever implements IContextInfoRetriever {
+
+               @Override
+               public Object retrieveContextInfo(String key) {
+                       switch (key) {
+                       case CONTEXT_NAME_SHORT:
+                               return (short) 42;
+                       case CONTEXT_NAME_STRING:
+                               return "context-value!";
+                       default:
+                               return null;
+                       }
+               }
+
+       }
+
+       /**
+        * Application start
+        *
+        * @param args
+        *            Command-line arguments
+        * @throws IOException
+        * @throws InterruptedException
+        */
+       public static void main(String args[]) throws IOException, InterruptedException {
+               /* Instantiate and attach a logger object */
+               Handler lttngHandler = new LttngLogHandler();
+               LOGGER.addHandler(lttngHandler);
+
+               /* Instantiate and register the context retriever */
+               IContextInfoRetriever cir = new ExampleContextInfoRetriever();
+               ContextInfoManager.getInstance().registerContextInfoRetriever(RETRIEVER_NAME, cir);
+
+               /*
+                * Make sure you have a LTTng session running with the appropriate
+                * events and contexts enabled! See the class Javadoc.
+                */
+
+               /* Trigger a tracing event using the JUL Logger created before. */
+               LOGGER.info("Log event #1");
+               LOGGER.warning("Log event #2");
+               LOGGER.severe("Log event #3");
+
+               /* Unregister our context retriever, and dispose the log handler */
+               ContextInfoManager.getInstance().unregisterContextInfoRetriever(RETRIEVER_NAME);
+               lttngHandler.close();
+       }
+}
index f4dacdd621ee0699f3e770605a7cdcca565b080f..3eb68708dd149b04d0674c89409f98ddb8d6dff8 100644 (file)
@@ -40,7 +40,7 @@ JC = javac -classpath "$(CLASSPATH):."
 .java.class:
        $(JC) $(JFLAGS) $*.java
 
-CLASSES = Hello.java FilterChangeListenerExample.java
+CLASSES = Hello.java FilterChangeListenerExample.java ApplicationContextExample.java
 
 all: classes
 
index 33476ae3082a3d9a1964b2293cab280df039fe70..683e451b15721cff825ee93c15662ec9f563d49a 100644 (file)
@@ -7,8 +7,8 @@ jarfile_manifest = $(srcdir)/Manifest.txt
 jarfile_symlink = lttng-ust-agent-common.jar
 jarfile = lttng-ust-agent-common-$(jarfile_version).jar
 
-
 jardir = $(datadir)/java
+jnioutdir = ../../jni/common
 
 dist_noinst_JAVA = $(pkgpath)/AbstractLttngAgent.java \
                                   $(pkgpath)/ILttngAgent.java \
@@ -19,10 +19,13 @@ dist_noinst_JAVA = $(pkgpath)/AbstractLttngAgent.java \
                                   $(pkgpath)/client/LttngAgentResponse.java \
                                   $(pkgpath)/client/LttngTcpSessiondClient.java \
                                   $(pkgpath)/client/SessiondCommandHeader.java \
+                                  $(pkgpath)/client/SessiondDisableAppContextCommand.java \
                                   $(pkgpath)/client/SessiondDisableEventCommand.java \
+                                  $(pkgpath)/client/SessiondEnableAppContextCommand.java \
                                   $(pkgpath)/client/SessiondEnableEventCommand.java \
                                   $(pkgpath)/client/SessiondListLoggersCommand.java \
                                   $(pkgpath)/context/ContextInfoManager.java \
+                                  $(pkgpath)/context/ContextInfoSerializer.java \
                                   $(pkgpath)/context/IContextInfoRetriever.java \
                                   $(pkgpath)/filter/FilterChangeNotifier.java \
                                   $(pkgpath)/filter/IFilterChangeListener.java \
@@ -34,12 +37,20 @@ dist_noinst_DATA = $(jarfile_manifest)
 
 jar_DATA = $(jarfile)
 
-classes = $(pkgpath)/*.class $(pkgpath)/client/*.class $(pkgpath)/context/*.class $(pkgpath)/filter/*.class $(pkgpath)/session/*.class
+classes = $(pkgpath)/*.class \
+                 $(pkgpath)/client/*.class \
+                 $(pkgpath)/context/*.class \
+                 $(pkgpath)/filter/*.class \
+                 $(pkgpath)/session/*.class
 
 $(jarfile): classnoinst.stamp
        $(JAR) cfm $(JARFLAGS) $@ $(jarfile_manifest) $(classes) && rm -f $(jarfile_symlink) && $(LN_S) $@ $(jarfile_symlink)
 
-all-local:
+context-jni-header.stamp: $(dist_noinst_JAVA)
+       $(JAVAH) -classpath $(CLASSPATH):$(srcdir) -d $(jnioutdir) $(JAVAHFLAGS) org.lttng.ust.agent.context.LttngContextApi && \
+       echo "Context API JNI header generated" > context-jni-header.stamp
+
+all-local: context-jni-header.stamp
 
 install-data-hook:
        cd $(DESTDIR)/$(jardir) && rm -f $(jarfile_symlink) && $(LN_S) $(jarfile) $(jarfile_symlink)
@@ -47,4 +58,9 @@ install-data-hook:
 uninstall-hook:
        cd $(DESTDIR)/$(jardir) && rm -f $(jarfile_symlink)
 
-CLEANFILES = $(jarfile) $(pkgpath)/*.class $(pkgpath)/client/*.class $(pkgpath)/context/*.class $(pkgpath)/filter/*.class $(pkgpath)/session/*.class
+CLEANFILES = $(jarfile) $(pkgpath)/*.class \
+                        $(pkgpath)/client/*.class \
+                        $(pkgpath)/context/*.class \
+                        $(pkgpath)/filter/*.class \
+                        $(pkgpath)/session/*.class \
+                        $(juljniout)/org_lttng_ust_agent_context_LttngContextApi.h
index e97a7bdb222b172b62524fa7245f400287dd3d5b..22c58265c0c8429e38fcac90bba73f0a45f03ca3 100644 (file)
@@ -75,6 +75,19 @@ public abstract class AbstractLttngAgent<T extends ILttngHandler>
        /** Number of sessions currently enabling the wildcard "*" event */
        private final AtomicInteger enabledWildcards = new AtomicInteger(0);
 
+       /**
+        * The application contexts currently enabled in the tracing sessions.
+        *
+        * It is first indexed by context retriever, then by context name. This
+        * allows to efficiently query all the contexts for a given retriever.
+        *
+        * Works similarly as {@link #enabledEvents}, but for app contexts (and with
+        * an extra degree of indexing).
+        *
+        * TODO Could be changed to a Guava Table once/if we start using it.
+        */
+       private final Map<String, Map<String, Integer>> enabledAppContexts = new ConcurrentHashMap<String, Map<String, Integer>>();
+
        /** Tracing domain. Defined by the sub-classes via the constructor. */
        private final Domain domain;
 
@@ -186,7 +199,6 @@ public abstract class AbstractLttngAgent<T extends ILttngHandler>
                enabledWildcards.set(0);
 
                initialized = false;
-
        }
 
        @Override
@@ -203,10 +215,10 @@ public abstract class AbstractLttngAgent<T extends ILttngHandler>
                if (eventName.endsWith(WILDCARD)) {
                        /* Strip the "*" from the name. */
                        String prefix = eventName.substring(0, eventName.length() - 1);
-                       return incrementEventCount(prefix, enabledEventPrefixes);
+                       return incrementRefCount(prefix, enabledEventPrefixes);
                }
 
-               return incrementEventCount(eventName, enabledEvents);
+               return incrementRefCount(eventName, enabledEvents);
        }
 
        @Override
@@ -227,10 +239,44 @@ public abstract class AbstractLttngAgent<T extends ILttngHandler>
                if (eventName.endsWith(WILDCARD)) {
                        /* Strip the "*" from the name. */
                        String prefix = eventName.substring(0, eventName.length() - 1);
-                       return decrementEventCount(prefix, enabledEventPrefixes);
+                       return decrementRefCount(prefix, enabledEventPrefixes);
+               }
+
+               return decrementRefCount(eventName, enabledEvents);
+       }
+
+       @Override
+       public boolean appContextEnabled(String contextRetrieverName, String contextName) {
+               synchronized (enabledAppContexts) {
+                       Map<String, Integer> retrieverMap = enabledAppContexts.get(contextRetrieverName);
+                       if (retrieverMap == null) {
+                               /* There is no submap for this retriever, let's create one. */
+                               retrieverMap = new ConcurrentHashMap<String, Integer>();
+                               enabledAppContexts.put(contextRetrieverName, retrieverMap);
+                       }
+
+                       return incrementRefCount(contextName, retrieverMap);
                }
+       }
+
+       @Override
+       public boolean appContextDisabled(String contextRetrieverName, String contextName) {
+               synchronized (enabledAppContexts) {
+                       Map<String, Integer> retrieverMap = enabledAppContexts.get(contextRetrieverName);
+                       if (retrieverMap == null) {
+                               /* There was no submap for this retriever, invalid command? */
+                               return false;
+                       }
+
+                       boolean ret = decrementRefCount(contextName, retrieverMap);
 
-               return decrementEventCount(eventName, enabledEvents);
+                       /* If the submap is now empty we can remove it from the main map. */
+                       if (retrieverMap.isEmpty()) {
+                               enabledAppContexts.remove(contextRetrieverName);
+                       }
+
+                       return ret;
+               }
        }
 
        /*
@@ -260,12 +306,17 @@ public abstract class AbstractLttngAgent<T extends ILttngHandler>
                return false;
        }
 
-       private static boolean incrementEventCount(String eventName, Map<String, Integer> eventMap) {
-               synchronized (eventMap) {
-                       Integer count = eventMap.get(eventName);
+       @Override
+       public Collection<Map.Entry<String, Map<String, Integer>>> getEnabledAppContexts() {
+               return enabledAppContexts.entrySet();
+       }
+
+       private static boolean incrementRefCount(String key, Map<String, Integer> refCountMap) {
+               synchronized (refCountMap) {
+                       Integer count = refCountMap.get(key);
                        if (count == null) {
                                /* This is the first instance of this event being enabled */
-                               eventMap.put(eventName, Integer.valueOf(1));
+                               refCountMap.put(key, Integer.valueOf(1));
                                return true;
                        }
                        if (count.intValue() <= 0) {
@@ -273,14 +324,14 @@ public abstract class AbstractLttngAgent<T extends ILttngHandler>
                                throw new IllegalStateException();
                        }
                        /* The event was already enabled, increment its refcount */
-                       eventMap.put(eventName, Integer.valueOf(count.intValue() + 1));
+                       refCountMap.put(key, Integer.valueOf(count.intValue() + 1));
                        return true;
                }
        }
 
-       private static boolean decrementEventCount(String eventName, Map<String, Integer> eventMap) {
-               synchronized (eventMap) {
-                       Integer count = eventMap.get(eventName);
+       private static boolean decrementRefCount(String key, Map<String, Integer> refCountMap) {
+               synchronized (refCountMap) {
+                       Integer count = refCountMap.get(key);
                        if (count == null || count.intValue() <= 0) {
                                /*
                                 * The sessiond asked us to disable an event that was not
@@ -293,14 +344,14 @@ public abstract class AbstractLttngAgent<T extends ILttngHandler>
                                 * This is the last instance of this event being disabled,
                                 * remove it from the map so that we stop sending it.
                                 */
-                               eventMap.remove(eventName);
+                               refCountMap.remove(key);
                                return true;
                        }
                        /*
                         * Other sessions are still looking for this event, simply decrement
                         * its refcount.
                         */
-                       eventMap.put(eventName, Integer.valueOf(count.intValue() - 1));
+                       refCountMap.put(key, Integer.valueOf(count.intValue() - 1));
                        return true;
                }
        }
index fd20a9ebc1d8246b67f5b0f7027a5288494b4579..5de0924256bfa59156c47ea861830c01c52c4f25 100644 (file)
@@ -17,6 +17,9 @@
 
 package org.lttng.ust.agent;
 
+import java.util.Collection;
+import java.util.Map;
+
 /**
  * Interface to define LTTng Java agents.
  *
@@ -93,4 +96,12 @@ public interface ILttngAgent<T extends ILttngHandler> {
         * @return True if the event is currently enabled, false if it is not.
         */
        boolean isEventEnabled(String eventName);
+
+       /**
+        * Return the list of application contexts enabled in the tracing sessions.
+        *
+        * @return The application contexts, first indexed by retriever name, then
+        *         by context name
+        */
+       Collection<Map.Entry<String, Map<String, Integer>>> getEnabledAppContexts();
 }
index ef0c11d95656db784c48a738fb5174454356121b..21189730befb9bb353d68740fc0b5248011defce 100644 (file)
@@ -54,6 +54,36 @@ public interface ILttngTcpClientListener {
         */
        boolean eventDisabled(String eventName);
 
+       /**
+        * Callback for the TCP client to notify the listener agent that a request
+        * for enabling an application-specific context was sent from the session
+        * daemon.
+        *
+        * @param contextRetrieverName
+        *            The name of the retriever in which the context is present.
+        *            This is used to namespace the contexts.
+        * @param contextName
+        *            The name of the context 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 appContextEnabled(String contextRetrieverName, String contextName);
+
+       /**
+        * Callback for the TCP client to notify the listener agent that a request
+        * for disabling an application-specific context was sent from the session
+        * daemon.
+        *
+        * @param contextRetrieverName
+        *            The name of the retriever in which the context is present.
+        *            This is used to namespace the contexts.
+        * @param contextName
+        *            The name of the context that was requested to be disabled.
+        * @return True if the command completed successfully, false if we should
+        *         report an error (context was not previously enabled for example)
+        */
+       boolean appContextDisabled(String contextRetrieverName, String contextName);
+
        /**
         * List the events that are available in the agent's tracing domain.
         *
index 3c5a27e52d4d4350f98710fa14846a547819570d..40c38a55c1bf4588ea1fcd8862882a0e7fef3716 100644 (file)
@@ -40,7 +40,7 @@ abstract class LttngAgentResponse {
 
                CODE_SUCCESS_CMD(1),
                CODE_INVALID_CMD(2),
-               CODE_UNK_LOGGER_NAME(3);
+               CODE_UNKNOWN_LOGGER_NAME(3);
 
                private int code;
 
index 2b31889c3019a5ae88864dee2995c42f34086c51..5b5d50c4e3f360b563fb3fd2062934bdb47afac0 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2015-2016 EfficiOS Inc., Alexandre Montplaisir <alexmonthy@efficios.com>
  * Copyright (C) 2013 - David Goulet <dgoulet@efficios.com>
  *
  * This library is free software; you can redistribute it and/or modify it
@@ -255,27 +256,51 @@ public class LttngTcpSessiondClient implements Runnable {
                                responseData = response.getBytes();
                                break;
                        }
-                       case CMD_ENABLE:
+                       case CMD_EVENT_ENABLE:
                        {
                                if (inputData == null) {
                                        /* Invalid command */
                                        responseData = LttngAgentResponse.FAILURE_RESPONSE.getBytes();
                                        break;
                                }
-                               SessiondCommand enableCmd = new SessiondEnableEventCommand(inputData);
-                               LttngAgentResponse response = enableCmd.execute(logAgent);
+                               SessiondCommand enableEventCmd = new SessiondEnableEventCommand(inputData);
+                               LttngAgentResponse response = enableEventCmd.execute(logAgent);
                                responseData = response.getBytes();
                                break;
                        }
-                       case CMD_DISABLE:
+                       case CMD_EVENT_DISABLE:
                        {
                                if (inputData == null) {
                                        /* Invalid command */
                                        responseData = LttngAgentResponse.FAILURE_RESPONSE.getBytes();
                                        break;
                                }
-                               SessiondCommand disableCmd = new SessiondDisableEventCommand(inputData);
-                               LttngAgentResponse response = disableCmd.execute(logAgent);
+                               SessiondCommand disableEventCmd = new SessiondDisableEventCommand(inputData);
+                               LttngAgentResponse response = disableEventCmd.execute(logAgent);
+                               responseData = response.getBytes();
+                               break;
+                       }
+                       case CMD_APP_CTX_ENABLE:
+                       {
+                               if (inputData == null) {
+                                       /* This commands expects a payload, invalid command */
+                                       responseData = LttngAgentResponse.FAILURE_RESPONSE.getBytes();
+                                       break;
+                               }
+                               SessiondCommand enableAppCtxCmd = new SessiondEnableAppContextCommand(inputData);
+                               LttngAgentResponse response = enableAppCtxCmd.execute(logAgent);
+                               responseData = response.getBytes();
+                               break;
+                       }
+                       case CMD_APP_CTX_DISABLE:
+                       {
+                               if (inputData == null) {
+                                       /* This commands expects a payload, invalid command */
+                                       responseData = LttngAgentResponse.FAILURE_RESPONSE.getBytes();
+                                       break;
+                               }
+                               SessiondCommand disableAppCtxCmd = new SessiondDisableAppContextCommand(inputData);
+                               LttngAgentResponse response = disableAppCtxCmd.execute(logAgent);
                                responseData = response.getBytes();
                                break;
                        }
index ee191da19eae64edb311ea028188c4a9cf65fa70..fd5bb1de89030579734d158b7e577acb028c6aa7 100644 (file)
@@ -30,15 +30,18 @@ import java.nio.ByteBuffer;
 abstract class SessiondCommand {
 
        enum CommandType {
-
                /** List logger(s). */
                CMD_LIST(1),
                /** Enable logger by name. */
-               CMD_ENABLE(2),
+               CMD_EVENT_ENABLE(2),
                /** Disable logger by name. */
-               CMD_DISABLE(3),
+               CMD_EVENT_DISABLE(3),
                /** Registration done */
-               CMD_REG_DONE(4);
+               CMD_REG_DONE(4),
+               /** Enable application context */
+               CMD_APP_CTX_ENABLE(5),
+               /** Disable application context */
+               CMD_APP_CTX_DISABLE(6);
 
                private int code;
 
diff --git a/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondDisableAppContextCommand.java b/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondDisableAppContextCommand.java
new file mode 100644 (file)
index 0000000..157ad75
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2016 - 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.client;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * Session daemon command indicating to the Java agent that an
+ * application-specific context was disabled in the tracing session.
+ *
+ * @author Alexandre Montplaisir
+ */
+class SessiondDisableAppContextCommand extends SessiondCommand {
+
+       private final String retrieverName;
+       private final String contextName;
+
+       private final boolean commandIsValid;
+
+       public SessiondDisableAppContextCommand(byte[] data) {
+               if (data == null) {
+                       throw new IllegalArgumentException();
+               }
+               ByteBuffer buf = ByteBuffer.wrap(data);
+               buf.order(ByteOrder.BIG_ENDIAN);
+
+               /*
+                * The buffer contains the retriever name first, followed by the
+                * context's name.
+                */
+               retrieverName = readNextString(buf);
+               contextName = readNextString(buf);
+
+               /* If any of these strings were null then the command was invalid */
+               commandIsValid = ((retrieverName != null) && (contextName != null));
+       }
+
+       @Override
+       public LttngAgentResponse execute(ILttngTcpClientListener agent) {
+               if (!commandIsValid) {
+                       return LttngAgentResponse.FAILURE_RESPONSE;
+               }
+
+               boolean success = agent.appContextDisabled(retrieverName, contextName);
+               return (success ? LttngAgentResponse.SUCESS_RESPONSE : DISABLE_APP_CONTEXT_FAILURE_RESPONSE);
+       }
+
+       /**
+        * Response sent when the disable-context command asks to disable an
+        * unknown context name.
+        */
+       private static final LttngAgentResponse DISABLE_APP_CONTEXT_FAILURE_RESPONSE = new LttngAgentResponse() {
+               @Override
+               public ReturnCode getReturnCode() {
+                       /* Same return code used for unknown event/logger names */
+                       return ReturnCode.CODE_UNKNOWN_LOGGER_NAME;
+               }
+       };
+}
index 920a2bf16bfc36b6b727b625c2e964e273e00ffe..4a19c22ea91d3e6743119737dc828a4672b434e9 100644 (file)
@@ -55,7 +55,7 @@ class SessiondDisableEventCommand extends SessiondCommand {
        private static final LttngAgentResponse DISABLE_EVENT_FAILURE_RESPONSE = new LttngAgentResponse() {
                @Override
                public ReturnCode getReturnCode() {
-                       return ReturnCode.CODE_UNK_LOGGER_NAME;
+                       return ReturnCode.CODE_UNKNOWN_LOGGER_NAME;
                }
        };
 }
diff --git a/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondEnableAppContextCommand.java b/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/client/SessiondEnableAppContextCommand.java
new file mode 100644 (file)
index 0000000..a06db88
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2016 - 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.client;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * Session daemon command indicating to the Java agent that an
+ * application-specific context was enabled in the tracing session.
+ *
+ * @author Alexandre Montplaisir
+ */
+class SessiondEnableAppContextCommand extends SessiondCommand {
+
+       private final String retrieverName;
+       private final String contextName;
+
+       private final boolean commandIsValid;
+
+       public SessiondEnableAppContextCommand(byte[] data) {
+               if (data == null) {
+                       throw new IllegalArgumentException();
+               }
+               ByteBuffer buf = ByteBuffer.wrap(data);
+               buf.order(ByteOrder.BIG_ENDIAN);
+
+               /*
+                * The buffer contains the retriever name first, followed by the
+                * context's name.
+                */
+               retrieverName = readNextString(buf);
+               contextName = readNextString(buf);
+
+               /* If any of these strings were null then the command was invalid */
+               commandIsValid = ((retrieverName != null) && (contextName != null));
+       }
+
+       @Override
+       public LttngAgentResponse execute(ILttngTcpClientListener agent) {
+               if (!commandIsValid) {
+                       return LttngAgentResponse.FAILURE_RESPONSE;
+               }
+
+               boolean success = agent.appContextEnabled(retrieverName, contextName);
+               return (success ? LttngAgentResponse.SUCESS_RESPONSE : LttngAgentResponse.FAILURE_RESPONSE);
+       }
+}
index 90a79acc646a43e2135589f756e368b11da33999..c3999b5d83883637be881352e9359a898b7fbcee 100644 (file)
 
 package org.lttng.ust.agent.context;
 
-import java.util.Set;
-import java.util.concurrent.CopyOnWriteArraySet;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 
 /**
  * The singleton manager of {@link IContextInfoRetriever} objects.
@@ -27,9 +29,14 @@ import java.util.concurrent.CopyOnWriteArraySet;
  */
 public final class ContextInfoManager {
 
-       private static final ContextInfoManager INSTANCE = new ContextInfoManager();
+       private static final String SHARED_LIBRARY_NAME = "lttng-ust-context-jni";
 
-       private final Set<IContextInfoRetriever> cirs = new CopyOnWriteArraySet<IContextInfoRetriever>();
+       private static ContextInfoManager instance;
+
+       private final Map<String, IContextInfoRetriever> contextInfoRetrievers = new ConcurrentHashMap<String, IContextInfoRetriever>();
+       private final Map<String, Long> contextInforRetrieverRefs = new HashMap<String, Long>();
+
+       private final Object retrieverLock = new Object();
 
        /** Singleton class, constructor should not be accessed directly */
        private ContextInfoManager() {
@@ -38,25 +45,77 @@ public final class ContextInfoManager {
        /**
         * Get the singleton instance.
         *
+        * <p>
+        * Usage of this class requires the "liblttng-ust-context-jni.so" native
+        * library to be present on the system and available (passing
+        * -Djava.library.path=path to the JVM may be needed).
+        * </p>
+        *
         * @return The singleton instance
-        * @deprecated The context-retrieving facilities are not yet implemented.
+        * @throws IOException
+        *             If the shared library cannot be found.
+        * @throws SecurityException
+        *             We will forward any SecurityExcepion that may be thrown when
+        *             trying to load the JNI library.
         */
-       @Deprecated
-       public static ContextInfoManager getInstance() {
-               return INSTANCE;
+       public static synchronized ContextInfoManager getInstance() throws IOException, SecurityException {
+               if (instance == null) {
+                       try {
+                               System.loadLibrary(SHARED_LIBRARY_NAME);
+                       } catch (UnsatisfiedLinkError e) {
+                               throw new IOException(e);
+                       }
+                       instance = new ContextInfoManager();
+               }
+               return instance;
        }
 
        /**
         * Register a new context info retriever.
         *
-        * This method has no effect if the exact same retriever is already
-        * registered.
+        * <p>
+        * Each context info retriever is registered with a given "retriever name",
+        * which specifies the namespace of the context elements. This name is
+        * specified separately from the retriever objects, which would allow
+        * register the same retriever under different namespaces for example.
+        * </p>
+        *
+        * <p>
+        * If the method returns false (indicating registration failure), then the
+        * retriever object will *not* be used for context information.
+        * </p>
         *
-        * @param cir
+        * @param retrieverName
+        *            The name to register to the context retriever object with.
+        * @param contextInfoRetriever
         *            The context info retriever to register
+        * @return True if the retriever was successfully registered, false if there
+        *         was an error, for example if a retriever is already registered
+        *         with that name.
         */
-       public void addContextInfoRetriever(IContextInfoRetriever cir) {
-               cirs.add(cir);
+       public boolean registerContextInfoRetriever(String retrieverName, IContextInfoRetriever contextInfoRetriever) {
+               synchronized (retrieverLock) {
+                       if (contextInfoRetrievers.containsKey(retrieverName)) {
+                               /*
+                                * There is already a retriever registered with that name,
+                                * refuse the new registration.
+                                */
+                               return false;
+                       }
+                       /*
+                        * Inform LTTng-UST of the new retriever. The names have to start
+                        * with "$app." on the UST side!
+                        */
+                       long ref = LttngContextApi.registerProvider("$app." + retrieverName);
+                       if (ref == 0) {
+                               return false;
+                       }
+
+                       contextInfoRetrievers.put(retrieverName, contextInfoRetriever);
+                       contextInforRetrieverRefs.put(retrieverName, Long.valueOf(ref));
+
+                       return true;
+               }
        }
 
        /**
@@ -64,21 +123,38 @@ public final class ContextInfoManager {
         *
         * This method has no effect if the retriever was not already registered.
         *
-        * @param cir
+        * @param retrieverName
         *            The context info retriever to unregister
+        * @return True if unregistration was successful, false if there was an
+        *         error
         */
-       public void removeContextInfoRetriever(IContextInfoRetriever cir) {
-               cirs.remove(cir);
+       public boolean unregisterContextInfoRetriever(String retrieverName) {
+               synchronized (retrieverLock) {
+                       if (!contextInfoRetrievers.containsKey(retrieverName)) {
+                               /*
+                                * There was no retriever registered with that name.
+                                */
+                               return false;
+                       }
+                       contextInfoRetrievers.remove(retrieverName);
+                       long ref = contextInforRetrieverRefs.remove(retrieverName).longValue();
+
+                       /* Unregister the retriever on the UST side too */
+                       LttngContextApi.unregisterProvider(ref);
+
+                       return true;
+               }
        }
 
        /**
-        * Return a read-only view (does not support
-        * {@link java.util.Iterator#remove}) of the currently registered context
-        * info retrievers.
+        * Return the context info retriever object registered with the given name.
         *
-        * @return The current context info retrievers
+        * @param retrieverName
+        *            The retriever name to look for
+        * @return The corresponding retriever object, or <code>null</code> if there
+        *         was none
         */
-       public Iterable<IContextInfoRetriever> getContextInfoRetrievers() {
-               return cirs;
+       public IContextInfoRetriever getContextInfoRetriever(String retrieverName) {
+               return contextInfoRetrievers.get(retrieverName);
        }
 }
diff --git a/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/context/ContextInfoSerializer.java b/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/context/ContextInfoSerializer.java
new file mode 100644 (file)
index 0000000..57382bd
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2016 - 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.context;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.charset.Charset;
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * This class is used to serialize the list of "context info" objects to pass
+ * through JNI.
+ *
+ * The protocol expects a single byte array parameter. This byte array consists
+ * of a series of fixed-size entries, where each entry contains the following
+ * elements (with their size in bytes in parenthesis):
+ *
+ * <ul>
+ * <li>The full context name, like "$app.myprovider:mycontext" (256)</li>
+ * <li>The context value type (1)</li>
+ * <li>The context value itself(256)</li>
+ * </ul>
+ *
+ * So the total size of each entry is 513 bytes. All unused bytes will be
+ * zero'ed.
+ *
+ * @author Alexandre Montplaisir
+ */
+public class ContextInfoSerializer {
+
+       private enum DataType {
+               NULL(0),
+               INTEGER(1),
+               LONG(2),
+               DOUBLE(3),
+               FLOAT(4),
+               BYTE(5),
+               SHORT(6),
+               BOOLEAN(7),
+               STRING(8);
+
+               private final byte value;
+
+               private DataType(int value) {
+                       this.value = (byte) value;
+               }
+
+               public byte getValue() {
+                       return value;
+               }
+       }
+
+       private static final String UST_APP_CTX_PREFIX = "$app.";
+       private static final int ELEMENT_LENGTH = 256;
+       private static final int ENTRY_LENGTH = 513;
+       private static final ByteOrder NATIVE_ORDER = ByteOrder.nativeOrder();
+       private static final Charset UTF8_CHARSET = Charset.forName("UTF-8");
+       private static final byte[] EMPTY_ARRAY = new byte[0];
+
+       /**
+        * From the list of requested contexts in the tracing session, look them up
+        * in the {@link ContextInfoManager}, retrieve the available ones, and
+        * serialize them into a byte array.
+        *
+        * @param enabledContexts
+        *            The contexts that are enabled in the tracing session (indexed
+        *            first by retriever name, then by index names). Should come
+        *            from the LTTng Agent.
+        * @return The byte array representing the intersection of the requested and
+        *         available contexts.
+        */
+       public static byte[] queryAndSerializeRequestedContexts(Collection<Map.Entry<String, Map<String, Integer>>> enabledContexts) {
+               if (enabledContexts.isEmpty()) {
+                       /* Early return if there is no requested context information */
+                       return EMPTY_ARRAY;
+               }
+
+               /* Compute the total number of contexts (flatten the map) */
+               int totalArraySize = 0;
+               for (Map.Entry<String, Map<String, Integer>> contexts : enabledContexts) {
+                       totalArraySize += contexts.getValue().size() * ENTRY_LENGTH;
+               }
+
+               ContextInfoManager contextManager;
+               try {
+                       contextManager = ContextInfoManager.getInstance();
+               } catch (IOException e) {
+                       /*
+                        * The JNI library is not available, do not send any context
+                        * information. No retriever could have been defined anyways.
+                        */
+                       return EMPTY_ARRAY;
+               }
+
+               ByteBuffer buffer = ByteBuffer.allocate(totalArraySize);
+               buffer.order(NATIVE_ORDER);
+               buffer.clear();
+
+               for (Map.Entry<String, Map<String, Integer>> entry : enabledContexts) {
+                       String requestedRetrieverName = entry.getKey();
+                       Map<String, Integer> requestedContexts = entry.getValue();
+
+                       IContextInfoRetriever retriever = contextManager.getContextInfoRetriever(requestedRetrieverName);
+
+                       for (String requestedContext : requestedContexts.keySet()) {
+                               Object contextInfo;
+                               if (retriever == null) {
+                                       contextInfo = null;
+                               } else {
+                                       contextInfo = retriever.retrieveContextInfo(requestedContext);
+                                       /*
+                                        * 'contextInfo' can still be null here, which would
+                                        * indicate the retriever does not supply this context. We
+                                        * will still write this information so that the tracer can
+                                        * know about it.
+                                        */
+                               }
+
+                               /* Serialize the result to the buffer */
+                               // FIXME Eventually pass the retriever name only once?
+                               String fullContextName = (UST_APP_CTX_PREFIX + requestedRetrieverName + ':' + requestedContext);
+                               byte[] strArray = fullContextName.getBytes(UTF8_CHARSET);
+                               int remainingBytes = ELEMENT_LENGTH - strArray.length;
+                               // FIXME Handle case where name is too long...
+                               buffer.put(strArray);
+                               buffer.position(buffer.position() + remainingBytes);
+
+                               serializeContextInfo(buffer, contextInfo);
+                       }
+               }
+               return buffer.array();
+       }
+
+       private static void serializeContextInfo(ByteBuffer buffer, Object contextInfo) {
+               int remainingBytes;
+               if (contextInfo == null) {
+                       buffer.put(DataType.NULL.getValue());
+                       remainingBytes = ELEMENT_LENGTH;
+
+               } else if (contextInfo instanceof Integer) {
+                       buffer.put(DataType.INTEGER.getValue());
+                       buffer.putInt(((Integer) contextInfo).intValue());
+                       remainingBytes = ELEMENT_LENGTH - 4;
+
+               } else if (contextInfo instanceof Long) {
+                       buffer.put(DataType.LONG.getValue());
+                       buffer.putLong(((Long) contextInfo).longValue());
+                       remainingBytes = ELEMENT_LENGTH - 8;
+
+               } else if (contextInfo instanceof Double) {
+                       buffer.put(DataType.DOUBLE.getValue());
+                       buffer.putDouble(((Double) contextInfo).doubleValue());
+                       remainingBytes = ELEMENT_LENGTH - 8;
+
+               } else if (contextInfo instanceof Float) {
+                       buffer.put(DataType.FLOAT.getValue());
+                       buffer.putFloat(((Float) contextInfo).floatValue());
+                       remainingBytes = ELEMENT_LENGTH - 4;
+
+               } else if (contextInfo instanceof Byte) {
+                       buffer.put(DataType.BYTE.getValue());
+                       buffer.put(((Byte) contextInfo).byteValue());
+                       remainingBytes = ELEMENT_LENGTH - 1;
+
+               } else if (contextInfo instanceof Short) {
+                       buffer.put(DataType.SHORT.getValue());
+                       buffer.putShort(((Short) contextInfo).shortValue());
+                       remainingBytes = ELEMENT_LENGTH - 2;
+
+               } else if (contextInfo instanceof Boolean) {
+                       buffer.put(DataType.BOOLEAN.getValue());
+                       boolean b = ((Boolean) contextInfo).booleanValue();
+                       /* Converted to one byte, write 1 for true, 0 for false */
+                       buffer.put((byte) (b ? 1 : 0));
+                       remainingBytes = ELEMENT_LENGTH - 1;
+
+               } else {
+                       /* We'll write the object as a string. Also includes the case of Character. */
+                       String str = contextInfo.toString();
+                       byte[] strArray = str.getBytes(UTF8_CHARSET);
+
+                       buffer.put(DataType.STRING.getValue());
+                       if (strArray.length >= ELEMENT_LENGTH) {
+                               /* Trim the string to the max allowed length */
+                               buffer.put(strArray, 0, ELEMENT_LENGTH);
+                               remainingBytes = 0;
+                       } else {
+                               buffer.put(strArray);
+                               remainingBytes = ELEMENT_LENGTH - strArray.length;
+                       }
+               }
+               buffer.position(buffer.position() + remainingBytes);
+       }
+}
diff --git a/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/context/LttngContextApi.java b/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/context/LttngContextApi.java
new file mode 100644 (file)
index 0000000..15062c9
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2016 - 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.context;
+
+/**
+ * Virtual class containing the Java side of the LTTng-UST context provider
+ * registering/unregistering methods.
+ *
+ * @author Alexandre Montplaisir
+ */
+final class LttngContextApi {
+
+       private LttngContextApi() {}
+
+       /**
+        * Register a context provider to UST.
+        *
+        * The callbacks are the same for all providers, and are defined in the .c
+        * file. The only needed information is the retriever (which is called
+        * "provider" from UST'S point of view) name.
+        *
+        * @param provider_name
+        *            The name of the provider
+        * @return The pointer to the created provider object. It's useless in the
+        *         Java space, but will be needed for
+        *         {@link #unregisterProvider(long)}.
+        */
+       static native long registerProvider(String provider_name);
+
+       /**
+        * Unregister a previously-registered context provider from UST.
+        *
+        * @param provider_ref
+        *            The pointer to the provider object, obtained from
+        *            {@link #registerProvider}
+        */
+       static native void unregisterProvider(long provider_ref);
+}
+
index f8a29d6d0298524a6617dc0a264bb0cdbefba123..b1f0d0193f615983515d0bf7ad2c1604c958953e 100644 (file)
@@ -33,4 +33,13 @@ final class LttngJulApi {
                        long millis,
                        int log_level,
                        int thread_id);
+
+       static native void tracepointWithContext(String msg,
+                       String logger_name,
+                       String class_name,
+                       String method_name,
+                       long millis,
+                       int log_level,
+                       int thread_id,
+                       byte[] contextInformation);
 }
index 3e61fe957471266ad3991f9e25d40f440ac83edd..535a2a3f57fd0d54e9216891354f7fe28a373e13 100644 (file)
@@ -19,6 +19,9 @@
 package org.lttng.ust.agent.jul;
 
 import java.io.IOException;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Map.Entry;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.logging.Formatter;
 import java.util.logging.Handler;
@@ -26,6 +29,7 @@ import java.util.logging.LogRecord;
 
 import org.lttng.ust.agent.ILttngAgent;
 import org.lttng.ust.agent.ILttngHandler;
+import org.lttng.ust.agent.context.ContextInfoSerializer;
 
 /**
  * LTTng-UST JUL log handler.
@@ -117,19 +121,25 @@ public class LttngLogHandler extends Handler implements ILttngHandler {
 
                String formattedMessage = FORMATTER.formatMessage(record);
 
+               /* Retrieve all the requested context information we can find */
+               Collection<Entry<String, Map<String, Integer>>> enabledContexts = agent.getEnabledAppContexts();
+               byte[] contextInfo = ContextInfoSerializer.queryAndSerializeRequestedContexts(enabledContexts);
+
                eventCount.incrementAndGet();
+
                /*
                 * Specific tracepoint designed for JUL events. The source class of the
                 * caller is used for the event name, the raw message is taken, the
                 * loglevel of the record and the thread ID.
                 */
-               LttngJulApi.tracepoint(formattedMessage,
+               LttngJulApi.tracepointWithContext(formattedMessage,
                                record.getLoggerName(),
                                record.getSourceClassName(),
                                record.getSourceMethodName(),
                                record.getMillis(),
                                record.getLevel().intValue(),
-                               record.getThreadID());
+                               record.getThreadID(),
+                               contextInfo);
        }
 
 }
index 2521e9f02106d6c565d155ebabc0fe523ef2f156..61a041879d44a1adfc52dc53b2fbc0de7dd28b9c 100644 (file)
@@ -35,4 +35,15 @@ final class LttngLog4jApi {
                        long timestamp,
                        int loglevel,
                        String thread_name);
+
+       static native void tracepointWithContext(String msg,
+                       String logger_name,
+                       String class_name,
+                       String method_name,
+                       String file_name,
+                       int line_number,
+                       long timestamp,
+                       int loglevel,
+                       String thread_name,
+                       byte[] contextInformation);
 }
index 753a5df34fc9f5642027e16527281ec051aabe4e..5c6df4dff4e9c8e213c9fb3c2fa5a83d7827848d 100644 (file)
 package org.lttng.ust.agent.log4j;
 
 import java.io.IOException;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Map.Entry;
 import java.util.concurrent.atomic.AtomicLong;
 
 import org.apache.log4j.AppenderSkeleton;
 import org.apache.log4j.spi.LoggingEvent;
 import org.lttng.ust.agent.ILttngAgent;
 import org.lttng.ust.agent.ILttngHandler;
+import org.lttng.ust.agent.context.ContextInfoSerializer;
 
 /**
  * LTTng-UST Log4j 1.x log handler.
@@ -116,9 +120,13 @@ public class LttngLogAppender extends AppenderSkeleton implements ILttngHandler
                        line = -1;
                }
 
+               /* Retrieve all the requested context information we can find */
+               Collection<Entry<String, Map<String, Integer>>> enabledContexts = agent.getEnabledAppContexts();
+               byte[] contextInfo = ContextInfoSerializer.queryAndSerializeRequestedContexts(enabledContexts);
+
                eventCount.incrementAndGet();
 
-               LttngLog4jApi.tracepoint(event.getRenderedMessage(),
+               LttngLog4jApi.tracepointWithContext(event.getRenderedMessage(),
                                event.getLoggerName(),
                                event.getLocationInformation().getClassName(),
                                event.getLocationInformation().getMethodName(),
@@ -126,7 +134,8 @@ public class LttngLogAppender extends AppenderSkeleton implements ILttngHandler
                                line,
                                event.getTimeStamp(),
                                event.getLevel().toInt(),
-                               event.getThreadName());
+                               event.getThreadName(),
+                               contextInfo);
        }
 
 }
index 5310c339ffea4dfa1b3d4afa7c3206e90a43a7e4..dae512001de532ff49301688a7e0ce8ef6bbc5fb 100644 (file)
@@ -1,4 +1,5 @@
-SUBDIRS=
+SUBDIRS = common
+
 if BUILD_JAVA_AGENT_WITH_JUL
 SUBDIRS += jul
 endif
diff --git a/liblttng-ust-java-agent/jni/common/Makefile.am b/liblttng-ust-java-agent/jni/common/Makefile.am
new file mode 100644 (file)
index 0000000..9e440cd
--- /dev/null
@@ -0,0 +1,8 @@
+AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include
+
+lib_LTLIBRARIES = liblttng-ust-context-jni.la
+liblttng_ust_context_jni_la_SOURCES = lttng_ust_context.c
+
+nodist_liblttng_ust_context_jni_la_SOURCES = org_lttng_ust_agent_context_LttngContextApi.h
+
+liblttng_ust_context_jni_la_LIBADD = -lc -L$(top_builddir)/liblttng-ust/.libs -llttng-ust
diff --git a/liblttng-ust-java-agent/jni/common/lttng_ust_context.c b/liblttng-ust-java-agent/jni/common/lttng_ust_context.c
new file mode 100644 (file)
index 0000000..8cc4087
--- /dev/null
@@ -0,0 +1,377 @@
+/*
+ * Copyright (C) 2016 - EfficiOS Inc., Alexandre Montplaisir <alexmonthy@efficios.com>
+ *               2016 - EfficiOS Inc., Mathieu Desnoyers <mathieu.desnoyers@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 as published by the Free Software Foundation; only
+ * version 2.1 of the License.
+ *
+ * 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
+ */
+
+#include "org_lttng_ust_agent_context_LttngContextApi.h"
+
+#include <string.h>
+#include <inttypes.h>
+#include <lttng/ust-events.h>
+#include <lttng/ringbuffer-config.h>
+#include <lttng/ust-context-provider.h>
+
+#include "helper.h"
+#include "lttng_ust_context.h"
+
+#define LTTNG_UST_JNI_CONTEXT_NAME_LEN         256
+/* TODO: the value should be variable length. */
+#define LTTNG_UST_JNI_VALUE_LEN                        256
+
+enum lttng_ust_jni_type {
+       JNI_TYPE_NULL = 0,
+       JNI_TYPE_INTEGER = 1,
+       JNI_TYPE_LONG = 2,
+       JNI_TYPE_DOUBLE = 3,
+       JNI_TYPE_FLOAT = 4,
+       JNI_TYPE_BYTE = 5,
+       JNI_TYPE_SHORT = 6,
+       JNI_TYPE_BOOLEAN = 7,
+       JNI_TYPE_STRING = 8,
+};
+
+struct lttng_ust_jni_ctx {
+       char context_name[LTTNG_UST_JNI_CONTEXT_NAME_LEN];
+       char type;      /* enum lttng_ust_jni_type */
+       union {
+               int32_t _integer;
+               int64_t _long;
+               double _double;
+               float _float;
+               signed char _byte;
+               int16_t _short;
+               signed char _boolean;
+               char _string[LTTNG_UST_JNI_VALUE_LEN];
+       } value;
+} __attribute__((packed));
+
+/* TLS passing context info from JNI to callbacks. */
+__thread struct lttng_ust_jni_tls lttng_ust_context_info_tls;
+
+static struct lttng_ust_jni_ctx *lookup_ctx_by_name(const char *ctx_name)
+{
+       struct lttng_ust_jni_ctx *ctx_array = lttng_ust_context_info_tls.ctx;
+       int i, len = lttng_ust_context_info_tls.len / sizeof(struct lttng_ust_jni_ctx);
+
+       for (i = 0; i < len; i++) {
+               if (strcmp(ctx_array[i].context_name, ctx_name) == 0)
+                       return &ctx_array[i];
+       }
+       return NULL;
+
+}
+
+static size_t get_size_cb(struct lttng_ctx_field *field, size_t offset)
+{
+       struct lttng_ust_jni_ctx *jctx;
+       size_t size = 0;
+       const char *ctx_name = field->event_field.name;
+       enum lttng_ust_jni_type jni_type;
+
+       size += lib_ring_buffer_align(offset, lttng_alignof(char));
+       size += sizeof(char);           /* tag */
+       jctx = lookup_ctx_by_name(ctx_name);
+       if (!jctx) {
+               jni_type = JNI_TYPE_NULL;
+       } else {
+               jni_type = jctx->type;
+       }
+       switch (jni_type) {
+       case JNI_TYPE_NULL:
+               break;
+       case JNI_TYPE_INTEGER:
+               size += lib_ring_buffer_align(offset, lttng_alignof(int32_t));
+               size += sizeof(int32_t);        /* variant */
+               break;
+       case JNI_TYPE_LONG:
+               size += lib_ring_buffer_align(offset, lttng_alignof(int64_t));
+               size += sizeof(int64_t);        /* variant */
+               break;
+       case JNI_TYPE_DOUBLE:
+               size += lib_ring_buffer_align(offset, lttng_alignof(double));
+               size += sizeof(double);         /* variant */
+               break;
+       case JNI_TYPE_FLOAT:
+               size += lib_ring_buffer_align(offset, lttng_alignof(float));
+               size += sizeof(float);          /* variant */
+               break;
+       case JNI_TYPE_SHORT:
+               size += lib_ring_buffer_align(offset, lttng_alignof(int16_t));
+               size += sizeof(int16_t);        /* variant */
+               break;
+       case JNI_TYPE_BYTE:             /* Fall-through. */
+       case JNI_TYPE_BOOLEAN:
+               size += lib_ring_buffer_align(offset, lttng_alignof(char));
+               size += sizeof(char);           /* variant */
+               break;
+       case JNI_TYPE_STRING:
+               size += strlen(jctx->value._string) + 1;
+               break;
+       default:
+               abort();
+       }
+       return size;
+
+}
+
+static void record_cb(struct lttng_ctx_field *field,
+                struct lttng_ust_lib_ring_buffer_ctx *ctx,
+                struct lttng_channel *chan)
+{
+       struct lttng_ust_jni_ctx *jctx;
+       const char *ctx_name = field->event_field.name;
+       enum lttng_ust_jni_type jni_type;
+       char sel_char;
+
+       jctx = lookup_ctx_by_name(ctx_name);
+       if (!jctx) {
+               jni_type = JNI_TYPE_NULL;
+       } else {
+               jni_type = jctx->type;
+       }
+
+       switch (jni_type) {
+       case JNI_TYPE_NULL:
+               sel_char = LTTNG_UST_DYNAMIC_TYPE_NONE;
+               lib_ring_buffer_align_ctx(ctx, lttng_alignof(char));
+               chan->ops->event_write(ctx, &sel_char, sizeof(sel_char));
+               break;
+       case JNI_TYPE_INTEGER:
+       {
+               int32_t v = jctx->value._integer;
+
+               sel_char = LTTNG_UST_DYNAMIC_TYPE_S32;
+               lib_ring_buffer_align_ctx(ctx, lttng_alignof(char));
+               chan->ops->event_write(ctx, &sel_char, sizeof(sel_char));
+               lib_ring_buffer_align_ctx(ctx, lttng_alignof(v));
+               chan->ops->event_write(ctx, &v, sizeof(v));
+               break;
+       }
+       case JNI_TYPE_LONG:
+       {
+               int64_t v = jctx->value._long;
+
+               sel_char = LTTNG_UST_DYNAMIC_TYPE_S64;
+               lib_ring_buffer_align_ctx(ctx, lttng_alignof(char));
+               chan->ops->event_write(ctx, &sel_char, sizeof(sel_char));
+               lib_ring_buffer_align_ctx(ctx, lttng_alignof(v));
+               chan->ops->event_write(ctx, &v, sizeof(v));
+               break;
+       }
+       case JNI_TYPE_DOUBLE:
+       {
+               double v = jctx->value._double;
+
+               sel_char = LTTNG_UST_DYNAMIC_TYPE_DOUBLE;
+               lib_ring_buffer_align_ctx(ctx, lttng_alignof(char));
+               chan->ops->event_write(ctx, &sel_char, sizeof(sel_char));
+               lib_ring_buffer_align_ctx(ctx, lttng_alignof(v));
+               chan->ops->event_write(ctx, &v, sizeof(v));
+               break;
+       }
+       case JNI_TYPE_FLOAT:
+       {
+               float v = jctx->value._float;
+
+               sel_char = LTTNG_UST_DYNAMIC_TYPE_FLOAT;
+               lib_ring_buffer_align_ctx(ctx, lttng_alignof(char));
+               chan->ops->event_write(ctx, &sel_char, sizeof(sel_char));
+               lib_ring_buffer_align_ctx(ctx, lttng_alignof(v));
+               chan->ops->event_write(ctx, &v, sizeof(v));
+               break;
+       }
+       case JNI_TYPE_SHORT:
+       {
+               int16_t v = jctx->value._short;
+
+               sel_char = LTTNG_UST_DYNAMIC_TYPE_S16;
+               lib_ring_buffer_align_ctx(ctx, lttng_alignof(char));
+               chan->ops->event_write(ctx, &sel_char, sizeof(sel_char));
+               lib_ring_buffer_align_ctx(ctx, lttng_alignof(v));
+               chan->ops->event_write(ctx, &v, sizeof(v));
+               break;
+       }
+       case JNI_TYPE_BYTE:
+       {
+               char v = jctx->value._byte;
+
+               sel_char = LTTNG_UST_DYNAMIC_TYPE_S8;
+               lib_ring_buffer_align_ctx(ctx, lttng_alignof(char));
+               chan->ops->event_write(ctx, &sel_char, sizeof(sel_char));
+               lib_ring_buffer_align_ctx(ctx, lttng_alignof(v));
+               chan->ops->event_write(ctx, &v, sizeof(v));
+               break;
+       }
+       case JNI_TYPE_BOOLEAN:
+       {
+               char v = jctx->value._boolean;
+
+               sel_char = LTTNG_UST_DYNAMIC_TYPE_S8;
+               lib_ring_buffer_align_ctx(ctx, lttng_alignof(char));
+               chan->ops->event_write(ctx, &sel_char, sizeof(sel_char));
+               lib_ring_buffer_align_ctx(ctx, lttng_alignof(v));
+               chan->ops->event_write(ctx, &v, sizeof(v));
+               break;
+       }
+       case JNI_TYPE_STRING:
+       {
+                       const char *str = jctx->value._string;
+
+                       sel_char = LTTNG_UST_DYNAMIC_TYPE_STRING;
+                       lib_ring_buffer_align_ctx(ctx, lttng_alignof(char));
+                       chan->ops->event_write(ctx, &sel_char, sizeof(sel_char));
+                       chan->ops->event_write(ctx, str, strlen(str) + 1);
+                       break;
+       }
+       default:
+               abort();
+       }
+}
+
+static void get_value_cb(struct lttng_ctx_field *field,
+               struct lttng_ctx_value *value)
+{
+       struct lttng_ust_jni_ctx *jctx;
+       const char *ctx_name = field->event_field.name;
+       enum lttng_ust_jni_type jni_type;
+
+       jctx = lookup_ctx_by_name(ctx_name);
+       if (!jctx) {
+               jni_type = JNI_TYPE_NULL;
+       } else {
+               jni_type = jctx->type;
+       }
+
+       switch (jni_type) {
+       case JNI_TYPE_NULL:
+               value->sel = LTTNG_UST_DYNAMIC_TYPE_NONE;
+               break;
+       case JNI_TYPE_INTEGER:
+               value->sel = LTTNG_UST_DYNAMIC_TYPE_S64;
+               value->u.s64 = (int64_t) jctx->value._integer;
+               break;
+       case JNI_TYPE_LONG:
+               value->sel = LTTNG_UST_DYNAMIC_TYPE_S64;
+               value->u.s64 = jctx->value._long;
+               break;
+       case JNI_TYPE_DOUBLE:
+               value->sel = LTTNG_UST_DYNAMIC_TYPE_DOUBLE;
+               value->u.d = jctx->value._double;
+               break;
+       case JNI_TYPE_FLOAT:
+               value->sel = LTTNG_UST_DYNAMIC_TYPE_DOUBLE;
+               value->u.d = (double) jctx->value._float;
+               break;
+       case JNI_TYPE_SHORT:
+               value->sel = LTTNG_UST_DYNAMIC_TYPE_S64;
+               value->u.s64 = (int64_t) jctx->value._short;
+               break;
+       case JNI_TYPE_BYTE:
+               value->sel = LTTNG_UST_DYNAMIC_TYPE_S64;
+               value->u.s64 = (int64_t) jctx->value._byte;
+               break;
+       case JNI_TYPE_BOOLEAN:
+               value->sel = LTTNG_UST_DYNAMIC_TYPE_S64;
+               value->u.s64 = (int64_t) jctx->value._boolean;
+               break;
+       case JNI_TYPE_STRING:
+               value->sel = LTTNG_UST_DYNAMIC_TYPE_STRING;
+               value->u.str = jctx->value._string;
+               break;
+       default:
+               abort();
+       }
+}
+
+/*
+ * Register a context provider to UST.
+ *
+ * Called from the Java side when an application registers a context retriever,
+ * so we create and register a corresponding provider on the C side.
+ */
+JNIEXPORT jlong JNICALL Java_org_lttng_ust_agent_context_LttngContextApi_registerProvider(JNIEnv *env,
+                                               jobject jobj,
+                                               jstring provider_name)
+{
+       jboolean iscopy;
+       const char *provider_name_jstr;
+       char *provider_name_cstr;
+       struct lttng_ust_context_provider *provider;
+       /*
+        * Note: a "jlong" is 8 bytes on all architectures, whereas a
+        * C "long" varies.
+        */
+       jlong provider_ref;
+
+       provider_name_jstr = (*env)->GetStringUTFChars(env, provider_name, &iscopy);
+       if (!provider_name_jstr) {
+               goto error_jstr;
+       }
+       /* Keep our own copy of the string so UST can use it. */
+       provider_name_cstr = strdup(provider_name_jstr);
+       (*env)->ReleaseStringUTFChars(env, provider_name, provider_name_jstr);
+       if (!provider_name_cstr) {
+               goto error_strdup;
+       }
+       provider = zmalloc(sizeof(*provider));
+       if (!provider) {
+               goto error_provider;
+       }
+       provider->name = provider_name_cstr;
+       provider->get_size = get_size_cb;
+       provider->record = record_cb;
+       provider->get_value = get_value_cb;
+
+       if (lttng_ust_context_provider_register(provider)) {
+               goto error_register;
+       }
+
+       provider_ref = (jlong) provider;
+       return provider_ref;
+
+       /* Error handling. */
+error_register:
+       free(provider);
+error_provider:
+       free(provider_name_cstr);
+error_strdup:
+error_jstr:
+       return 0;
+}
+
+/*
+ * Unregister a previously-registered context provider.
+ *
+ * Called from the Java side when an application unregisters a context retriever,
+ * so we unregister and delete the corresponding provider on the C side.
+ */
+JNIEXPORT void JNICALL Java_org_lttng_ust_agent_context_LttngContextApi_unregisterProvider(JNIEnv *env,
+                                               jobject jobj,
+                                               jlong provider_ref)
+{
+       struct lttng_ust_context_provider *provider =
+                       (struct lttng_ust_context_provider*) (unsigned long) provider_ref;
+
+       if (!provider) {
+               return;
+       }
+
+       lttng_ust_context_provider_unregister(provider);
+
+       free(provider->name);
+       free(provider);
+}
diff --git a/liblttng-ust-java-agent/jni/common/lttng_ust_context.h b/liblttng-ust-java-agent/jni/common/lttng_ust_context.h
new file mode 100644 (file)
index 0000000..2bdef3a
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2016 - 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 as published by the Free Software Foundation; only
+ * version 2.1 of the License.
+ *
+ * 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
+ */
+
+#ifndef LIBLTTNG_UST_JAVA_AGENT_JNI_COMMON_LTTNG_UST_CONTEXT_H_
+#define LIBLTTNG_UST_JAVA_AGENT_JNI_COMMON_LTTNG_UST_CONTEXT_H_
+
+struct lttng_ust_jni_ctx;
+
+struct lttng_ust_jni_tls {
+       struct lttng_ust_jni_ctx *ctx;
+       int32_t len;
+};
+
+extern __thread struct lttng_ust_jni_tls lttng_ust_context_info_tls;
+
+#endif /* LIBLTTNG_UST_JAVA_AGENT_JNI_COMMON_LTTNG_UST_CONTEXT_H_ */
index cd0b7dc3ea01c85a19c26491fb3d6f069d4e19bf..111c55956cef5ba2d54847a9b5699a40a721d7a6 100644 (file)
@@ -6,4 +6,8 @@ liblttng_ust_jul_jni_la_SOURCES = lttng_ust_jul.c \
 
 nodist_liblttng_ust_jul_jni_la_SOURCES = org_lttng_ust_agent_jul_LttngJulApi.h
 
-liblttng_ust_jul_jni_la_LIBADD = -lc -L$(top_builddir)/liblttng-ust/.libs -llttng-ust
+liblttng_ust_jul_jni_la_LIBADD = -lc \
+                                                                -L$(top_builddir)/liblttng-ust/.libs \
+                                                                -L$(top_builddir)/liblttng-ust-java-agent/jni/common/.libs \
+                                                                -llttng-ust-context-jni
+                                                                -llttng-ust
index a0e893e5f2eca5d641b4b7251b8e29c4a4a2cd6a..62d820b2e3ed45466eeb330b19da1c2812ade159 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2016 - EfficiOS Inc., Alexandre Montplaisir <alexmonthy@efficios.com>
  * Copyright (C) 2011-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
  *
  * This library is free software; you can redistribute it and/or
 #define TRACEPOINT_DEFINE
 #define TRACEPOINT_CREATE_PROBES
 #include "lttng_ust_jul.h"
+#include "../common/lttng_ust_context.h"
 
 /*
- * Tracepoint used by Java applications using the JUL handler.
+ * Deprecated function from before the context information was passed.
  */
 JNIEXPORT void JNICALL Java_org_lttng_ust_agent_jul_LttngJulApi_tracepoint(JNIEnv *env,
                                                jobject jobj,
@@ -49,3 +51,44 @@ JNIEXPORT void JNICALL Java_org_lttng_ust_agent_jul_LttngJulApi_tracepoint(JNIEn
        (*env)->ReleaseStringUTFChars(env, class_name, class_name_cstr);
        (*env)->ReleaseStringUTFChars(env, method_name, method_name_cstr);
 }
+
+/*
+ * Tracepoint used by Java applications using the JUL handler.
+ */
+JNIEXPORT void JNICALL Java_org_lttng_ust_agent_jul_LttngJulApi_tracepointWithContext(JNIEnv *env,
+                                               jobject jobj,
+                                               jstring msg,
+                                               jstring logger_name,
+                                               jstring class_name,
+                                               jstring method_name,
+                                               jlong millis,
+                                               jint log_level,
+                                               jint thread_id,
+                                               jbyteArray context_info)
+{
+       jboolean iscopy;
+       const char *msg_cstr = (*env)->GetStringUTFChars(env, msg, &iscopy);
+       const char *logger_name_cstr = (*env)->GetStringUTFChars(env, logger_name, &iscopy);
+       const char *class_name_cstr = (*env)->GetStringUTFChars(env, class_name, &iscopy);
+       const char *method_name_cstr = (*env)->GetStringUTFChars(env, method_name, &iscopy);
+       signed char *context_info_array;
+
+       /*
+        * Write these to the TLS variables, so that the UST callbacks in
+        * lttng_ust_context.c can access them.
+        */
+       context_info_array = (*env)->GetByteArrayElements(env, context_info, &iscopy);
+       lttng_ust_context_info_tls.ctx = (struct lttng_ust_jni_ctx *) context_info_array;
+       lttng_ust_context_info_tls.len = (*env)->GetArrayLength(env, context_info);
+
+       tracepoint(lttng_jul, event, msg_cstr, logger_name_cstr,
+                       class_name_cstr, method_name_cstr, millis, log_level, thread_id);
+
+       lttng_ust_context_info_tls.ctx = NULL;
+       lttng_ust_context_info_tls.len = 0;
+       (*env)->ReleaseStringUTFChars(env, msg, msg_cstr);
+       (*env)->ReleaseStringUTFChars(env, logger_name, logger_name_cstr);
+       (*env)->ReleaseStringUTFChars(env, class_name, class_name_cstr);
+       (*env)->ReleaseStringUTFChars(env, method_name, method_name_cstr);
+       (*env)->ReleaseByteArrayElements(env, context_info, context_info_array, 0);
+}
index 5030a03f7d1c459ecf3192d2f70369159b5d0d62..a94479c5be811a197c2e121cdca22e1734fa219a 100644 (file)
@@ -1,8 +1,13 @@
 AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include
+
 lib_LTLIBRARIES = liblttng-ust-log4j-jni.la
 liblttng_ust_log4j_jni_la_SOURCES = lttng_ust_log4j.c \
                                  lttng_ust_log4j.h
 
 nodist_liblttng_ust_log4j_jni_la_SOURCES = org_lttng_ust_agent_log4j_LttngLog4jApi.h
 
-liblttng_ust_log4j_jni_la_LIBADD = -lc -L$(top_builddir)/liblttng-ust/.libs -llttng-ust
+liblttng_ust_log4j_jni_la_LIBADD = -lc \
+                                                                  -L$(top_builddir)/liblttng-ust/.libs \
+                                                                  -L$(top_builddir)/liblttng-ust-java-agent/jni/common/.libs \
+                                                                  -llttng-ust-context-jni
+                                                                  -llttng-ust
index 3b78c8e5911f6845b4836ed1cb1e5b38354c8812..b80312e2d3c72f6379d9d60d82ed8407fceeb9b4 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2016 - EfficiOS Inc., Alexandre Montplaisir <alexmonthy@efficios.com>
  * Copyright (C) 2011-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
  *
  * This library is free software; you can redistribute it and/or
 #define TRACEPOINT_DEFINE
 #define TRACEPOINT_CREATE_PROBES
 #include "lttng_ust_log4j.h"
+#include "../common/lttng_ust_context.h"
 
 /*
- * System tracepoint meaning only root agent will fire this.
+ * Deprecated function from before the context information was passed.
  */
 JNIEXPORT void JNICALL Java_org_lttng_ust_agent_log4j_LttngLog4jApi_tracepoint(JNIEnv *env,
                                                jobject jobj,
@@ -57,3 +59,50 @@ JNIEXPORT void JNICALL Java_org_lttng_ust_agent_log4j_LttngLog4jApi_tracepoint(J
        (*env)->ReleaseStringUTFChars(env, thread_name, thread_name_cstr);
 }
 
+/*
+ * Tracepoint used by Java applications using the log4j handler.
+ */
+JNIEXPORT void JNICALL Java_org_lttng_ust_agent_log4j_LttngLog4jApi_tracepointWithContext(JNIEnv *env,
+                                               jobject jobj,
+                                               jstring msg,
+                                               jstring logger_name,
+                                               jstring class_name,
+                                               jstring method_name,
+                                               jstring file_name,
+                                               jint line_number,
+                                               jlong timestamp,
+                                               jint loglevel,
+                                               jstring thread_name,
+                                               jbyteArray context_info)
+{
+       jboolean iscopy;
+       const char *msg_cstr = (*env)->GetStringUTFChars(env, msg, &iscopy);
+       const char *logger_name_cstr = (*env)->GetStringUTFChars(env, logger_name, &iscopy);
+       const char *class_name_cstr = (*env)->GetStringUTFChars(env, class_name, &iscopy);
+       const char *method_name_cstr = (*env)->GetStringUTFChars(env, method_name, &iscopy);
+       const char *file_name_cstr = (*env)->GetStringUTFChars(env, file_name, &iscopy);
+       const char *thread_name_cstr = (*env)->GetStringUTFChars(env, thread_name, &iscopy);
+       signed char *context_info_array;
+
+       /*
+        * Write these to the TLS variables, so that the UST callbacks in
+        * lttng_ust_context.c can access them.
+        */
+       context_info_array = (*env)->GetByteArrayElements(env, context_info, &iscopy);
+       lttng_ust_context_info_tls.ctx = (struct lttng_ust_jni_ctx *) context_info_array;
+       lttng_ust_context_info_tls.len = (*env)->GetArrayLength(env, context_info);
+
+       tracepoint(lttng_log4j, event, msg_cstr, logger_name_cstr,
+                  class_name_cstr, method_name_cstr, file_name_cstr,
+                  line_number, timestamp, loglevel, thread_name_cstr);
+
+       lttng_ust_context_info_tls.ctx = NULL;
+       lttng_ust_context_info_tls.len = 0;
+       (*env)->ReleaseStringUTFChars(env, msg, msg_cstr);
+       (*env)->ReleaseStringUTFChars(env, logger_name, logger_name_cstr);
+       (*env)->ReleaseStringUTFChars(env, class_name, class_name_cstr);
+       (*env)->ReleaseStringUTFChars(env, method_name, method_name_cstr);
+       (*env)->ReleaseStringUTFChars(env, file_name, file_name_cstr);
+       (*env)->ReleaseStringUTFChars(env, thread_name, thread_name_cstr);
+       (*env)->ReleaseByteArrayElements(env, context_info, context_info_array, 0);
+}
This page took 0.05098 seconds and 4 git commands to generate.