package org.lttng.ust.jul;
-import java.util.ArrayList;
import java.lang.String;
import org.lttng.ust.jul.LTTngUst;
public class LTTngEvent {
/* Name of the event. */
public String name;
- public ArrayList<LTTngLogLevel> logLevels = new ArrayList<LTTngLogLevel>();
-
- public void addLogLevel(int loglevel, int loglevel_type) {
- this.logLevels.add(new LTTngLogLevel(loglevel, loglevel_type));
- }
+ public LTTngLogLevel logLevel;
public LTTngEvent(String name, int loglevel, int loglevel_type) {
this.name = name;
- this.addLogLevel(loglevel, loglevel_type);
+ this.logLevel = new LTTngLogLevel(loglevel, loglevel_type);
}
}
import java.util.logging.LogRecord;
import java.util.logging.LogManager;
import java.util.logging.Level;
-import java.util.ArrayList;
+import java.util.logging.Logger;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.Map;
import org.lttng.ust.jul.LTTngUst;
-/* Note: This is taken from the LTTng tools ABI. */
-class LTTngLogLevelABI {
- /* Loglevel type. */
- public static final int LOGLEVEL_TYPE_ALL = 0;
- public static final int LOGLEVEL_TYPE_RANGE = 1;
- public static final int LOGLEVEL_TYPE_SINGLE = 2;
-}
-
-public class LTTngLogHandler extends Handler {
+class LTTngLogger {
/*
- * Indicate if the enable all event has been seen and if yes logger that we
- * enabled should use the loglevel/type below.
+ * The log handler is attached to the logger when the reference count is
+ * nonzero. Each event referring to a logger holds a reference to that
+ * logger. If down to 0, this object is removed from the handler.
*/
- public int logLevelUseAll = 0;
- public ArrayList<LTTngLogLevel> logLevelsAll =
- new ArrayList<LTTngLogLevel>();
+ public int refcount;
+ public String name;
+ Logger logger;
+
+ public LTTngLogger(String name, Logger logger) {
+ this.name = name;
+ this.refcount = 0;
+ this.logger = logger;
+ }
+ public void attach(LTTngLogHandler handler) {
+ this.logger.addHandler(handler);
+ }
+
+ public void detach(LTTngLogHandler handler) {
+ this.logger.removeHandler(handler);
+ }
+}
+
+public class LTTngLogHandler extends Handler {
/* Am I a root Log Handler. */
public int is_root = 0;
public LogManager logManager;
- /* Indexed by name and corresponding LTTngEvent. */
- private HashMap<String, LTTngEvent> eventMap =
- new HashMap<String, LTTngEvent>();
+ /* Logger object attached to this handler that can trigger a tracepoint. */
+ private Map<String, LTTngLogger> loggerMap =
+ Collections.synchronizedMap(new HashMap<String, LTTngLogger>());
+ /* Constructor */
public LTTngLogHandler(LogManager logManager) {
super();
LTTngUst.init();
}
- /**
- * Add event to handler hash map if new.
- *
- * @return 0 if it did not exist else 1.
+ /*
+ * Return true if the logger is enabled and attached. Else, if not found,
+ * return false.
+ */
+ public boolean exists(String name) {
+ if (loggerMap.get(name) != null) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /*
+ * Attach an event to this handler. If no logger object exists, one is
+ * created else the refcount is incremented.
*/
- public int setEvent(LTTngEvent new_event) {
- LTTngEvent event;
-
- event = eventMap.get(new_event.name);
- if (event == null) {
- eventMap.put(new_event.name, new_event);
- /* Did not exists. */
- return 0;
+ public void attachEvent(LTTngEvent event) {
+ Logger logger;
+ LTTngLogger lttngLogger;
+
+ /* Does the logger actually exist. */
+ logger = this.logManager.getLogger(event.name);
+ if (logger == null) {
+ /* Stop attach right now. */
+ return;
+ }
+
+ lttngLogger = loggerMap.get(event.name);
+ if (lttngLogger == null) {
+ lttngLogger = new LTTngLogger(event.name, logger);
+
+ /* Attach the handler to the logger and add is to the map. */
+ lttngLogger.attach(this);
+ lttngLogger.refcount = 1;
+ loggerMap.put(lttngLogger.name, lttngLogger);
} else {
- /* Add new event loglevel to existing event. */
- event.logLevels.addAll(new_event.logLevels);
- /* Already exists. */
- return 1;
+ lttngLogger.refcount += 1;
+ }
+ }
+
+ /*
+ * Dettach an event from this handler. If the refcount goes down to 0, the
+ * logger object is removed thus not attached anymore.
+ */
+ public void detachEvent(LTTngEvent event) {
+ LTTngLogger logger;
+
+ logger = loggerMap.get(event.name);
+ if (logger != null) {
+ logger.refcount -= 1;
+ if (logger.refcount == 0) {
+ /* Dettach from handler since no more event is associated. */
+ logger.detach(this);
+ loggerMap.remove(logger);
+ }
}
}
* Cleanup this handler state meaning put it back to a vanilla state.
*/
public void clear() {
- this.eventMap.clear();
- this.logLevelsAll.clear();
+ this.loggerMap.clear();
}
@Override
@Override
public void publish(LogRecord record) {
- int fire_tp = 0, rec_log_level, ev_type, ev_log_level;
- LTTngEvent event;
- LTTngLogLevel lttngLogLevel;
- String logger_name = record.getLoggerName();
-
- /* Get back the event if any and check for loglevel. */
- event = eventMap.get(logger_name);
- if (event != null) {
- for (LTTngLogLevel ev_log : event.logLevels) {
- /* Get record and event log level. */
- rec_log_level = record.getLevel().intValue();
- ev_log_level = ev_log.level;
-
- switch (ev_log.type) {
- case LTTngLogLevelABI.LOGLEVEL_TYPE_RANGE:
- if (ev_log_level <= rec_log_level) {
- fire_tp = 1;
- }
- break;
- case LTTngLogLevelABI.LOGLEVEL_TYPE_SINGLE:
- if (ev_log_level == rec_log_level) {
- fire_tp = 1;
- }
- break;
- case LTTngLogLevelABI.LOGLEVEL_TYPE_ALL:
- fire_tp = 1;
- break;
- }
-
- /*
- * If we match, stop right now else continue to the next
- * loglevel contained in the event.
- */
- if (fire_tp == 1) {
- break;
- }
- }
- } else {
- /* No loglevel attached thus fire tracepoint. */
- fire_tp = 1;
- }
+ LTTngLogger logger;
- if (fire_tp == 0) {
+ logger = loggerMap.get(record.getLoggerName());
+ if (logger == null) {
+ /* Ignore and don't fire TP. */
return;
}
import java.util.logging.Logger;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.Map;
import java.util.List;
+import java.util.Set;
import java.util.Enumeration;
public interface LTTngSessiondCmd2_4 {
return data;
}
- /*
- * Enable a logger meaning add our handler to it using an exiting
- * event. If successful, the logger is added to the given enabled
- * Loggers hashmap.
- *
- * @return 0 if NO logger is found else 1 if added.
- */
- public int enableLogger(LTTngLogHandler handler, LTTngEvent event,
- HashMap enabledLoggers) {
- int ret;
- Logger logger;
-
- logger = handler.logManager.getLogger(event.name);
- if (logger == null) {
- return 0;
- }
-
- ret = handler.setEvent(event);
- if (ret == 0) {
- /* Newly created event, add the handler. */
- logger.addHandler(handler);
- enabledLoggers.put(event.name, logger);
- }
-
- return 1;
- }
-
/**
* Execute enable handler action which is to enable the given handler
* to the received name.
* @return Event name as a string if the event is NOT found thus was
* not enabled.
*/
- public LTTngEvent execute(LTTngLogHandler handler, HashMap enabledLoggers) {
- int ret;
- Logger logger;
- LTTngEvent event = null;
+ public void execute(LTTngLogHandler handler,
+ Map<String, ArrayList<LTTngEvent>> eventMap, Set wildCardSet) {
+ ArrayList<LTTngEvent> bucket;
+ LTTngEvent event;
if (name == null) {
this.code = lttng_jul_ret_code.CODE_INVALID_CMD;
- return null;
+ return;
}
/* Wild card to enable ALL logger. */
String loggerName;
Enumeration loggers = handler.logManager.getLoggerNames();
+ /* Add event to the wildcard set. */
+ wildCardSet.add(new LTTngEvent(name.trim(), lttngLogLevel,
+ lttngLogLevelType));
+
/*
- * Keep the loglevel value for all events in case an event
- * appears later on.
+ * Create an event for each logger found and attach it to the
+ * handler.
*/
- if (lttngLogLevel != -1) {
- handler.logLevelUseAll = 1;
- handler.logLevelsAll.add(new LTTngLogLevel(lttngLogLevel,
- lttngLogLevelType));
- }
-
while (loggers.hasMoreElements()) {
loggerName = loggers.nextElement().toString();
/* Somehow there is always an empty string at the end. */
continue;
}
+ event = new LTTngEvent(loggerName, lttngLogLevel,
+ lttngLogLevelType);
+ /* Attach event to Log handler to it can be traced. */
+ handler.attachEvent(event);
+
/*
- * Create new event object and set it in the log handler so
- * we can process the record entry with the right
- * attributes like the loglevels.
+ * The agent timer call this function with eventMap set to
+ * null because it already has a reference to an existing
+ * event so is should not try to add a new one here.
*/
- event = new LTTngEvent(loggerName, 0, 0);
- /* Clean up loglevel and merge the the ones from all events. */
- event.logLevels.clear();
- event.logLevels.addAll(handler.logLevelsAll);
- enableLogger(handler, event, enabledLoggers);
+ if (eventMap != null) {
+ bucket = eventMap.get(loggerName);
+ if (bucket == null) {
+ bucket = new ArrayList<LTTngEvent>();
+ eventMap.put(loggerName, bucket);
+ }
+ bucket.add(event);
+ }
}
- this.code = lttng_jul_ret_code.CODE_SUCCESS_CMD;
+ } else {
+ event = new LTTngEvent(name.trim(), lttngLogLevel,
+ lttngLogLevelType);
+ /* Attach event to Log handler to it can be traced. */
+ handler.attachEvent(event);
/*
- * Only return an event if this is a newly created event
- * meaning the loglevel is valid.
+ * The agent timer call this function with eventMap set to
+ * null because it already has a reference to an existing
+ * event so is should not try to add a new one here.
*/
- if (lttngLogLevel != -1) {
- event = new LTTngEvent("*", lttngLogLevel, lttngLogLevelType);
+ if (eventMap != null) {
+ bucket = eventMap.get(name.trim());
+ if (bucket == null) {
+ bucket = new ArrayList<LTTngEvent>();
+ eventMap.put(name.trim(), bucket);
+ }
+ bucket.add(event);
}
- return event;
}
this.code = lttng_jul_ret_code.CODE_SUCCESS_CMD;
-
- /*
- * Create new event object and set it in the log handler so we can
- * process the record entry with the right attributes like the
- * loglevels.
- */
- event = new LTTngEvent(name.trim(), lttngLogLevel,
- lttngLogLevelType);
- ret = enableLogger(handler, event, enabledLoggers);
- if (ret == 1) {
- return null;
- }
- return event;
+ return;
}
}
public class sessiond_disable_handler implements SessiondResponse, SessiondCommand {
private final static int SIZE = 4;
public String name;
+ public int lttngLogLevel;
+ public int lttngLogLevelType;
/** Return status code to the session daemon. */
public lttng_jul_ret_code code;
@Override
public void populate(byte[] data) {
+ int data_offset = INT_SIZE * 2;
+
ByteBuffer buf = ByteBuffer.wrap(data);
- buf.order(ByteOrder.BIG_ENDIAN);
- name = new String(data, 0, data.length);
+ buf.order(ByteOrder.LITTLE_ENDIAN);
+ lttngLogLevel = buf.getInt();
+ lttngLogLevelType = buf.getInt();
+ name = new String(data, data_offset, data.length - data_offset);
}
@Override
* Execute disable handler action which is to disable the given handler
* to the received name.
*/
- public void execute(LTTngLogHandler handler) {
- Logger logger;
+ public void execute(LTTngLogHandler handler,
+ Map<String, ArrayList<LTTngEvent>> eventMap, Set wildCardSet) {
+ ArrayList<LTTngEvent> bucket;
+ LTTngEvent event;
if (name == null) {
this.code = lttng_jul_ret_code.CODE_INVALID_CMD;
if (name.trim().equals("*")) {
String loggerName;
Enumeration loggers = handler.logManager.getLoggerNames();
+
+ /* Remove event from the wildcard set. */
+ wildCardSet.remove(new LTTngEvent(name.trim(), lttngLogLevel,
+ lttngLogLevelType));
+
while (loggers.hasMoreElements()) {
loggerName = loggers.nextElement().toString();
/* Somehow there is always an empty string at the end. */
continue;
}
- logger = handler.logManager.getLogger(loggerName);
- logger.removeHandler(handler);
+ event = new LTTngEvent(loggerName, lttngLogLevel,
+ lttngLogLevelType);
+
+ bucket = eventMap.get(loggerName);
+ if (bucket != null) {
+ handler.detachEvent(event);
+ bucket.remove(event);
+ if (bucket.isEmpty() == true) {
+ eventMap.remove(bucket);
+ }
+ }
}
this.code = lttng_jul_ret_code.CODE_SUCCESS_CMD;
- return;
- }
-
- logger = handler.logManager.getLogger(name.trim());
- if (logger == null) {
- this.code = lttng_jul_ret_code.CODE_UNK_LOGGER_NAME;
} else {
- logger.removeHandler(handler);
- this.code = lttng_jul_ret_code.CODE_SUCCESS_CMD;
+ event = new LTTngEvent(this.name, lttngLogLevel,
+ lttngLogLevelType);
+
+ bucket = eventMap.get(this.name);
+ if (bucket != null) {
+ handler.detachEvent(event);
+ bucket.remove(event);
+ if (bucket.isEmpty() == true) {
+ eventMap.remove(bucket);
+ }
+ this.code = lttng_jul_ret_code.CODE_SUCCESS_CMD;
+ } else {
+ this.code = lttng_jul_ret_code.CODE_UNK_LOGGER_NAME;
+ }
}
+
+ return;
}
}
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Map;
import java.util.Iterator;
import java.util.List;
+import java.util.Enumeration;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
private Semaphore registerSem;
private Timer eventTimer;
- private Set<LTTngEvent> enabledEventSet =
- Collections.synchronizedSet(new HashSet<LTTngEvent>());
+
/*
- * Map of Logger objects that have been enabled. They are indexed by name.
+ * Indexed by event name but can contains duplicates since multiple
+ * sessions can enable the same event with or without different loglevels.
*/
- private HashMap<String, Logger> enabledLoggers = new HashMap<String, Logger>();
+ private Map<String, ArrayList<LTTngEvent>> eventMap =
+ Collections.synchronizedMap(
+ new HashMap<String, ArrayList<LTTngEvent>>());
+
+ private Set<LTTngEvent> wildCardSet =
+ Collections.synchronizedSet(new HashSet<LTTngEvent>());
+
/* Timer delay at each 5 seconds. */
private final static long timerDelay = 5 * 1000;
private static boolean timerInitialized;
this.eventTimer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
- synchronized (enabledEventSet) {
- LTTngSessiondCmd2_4.sessiond_enable_handler enableCmd = new
- LTTngSessiondCmd2_4.sessiond_enable_handler();
+ LTTngSessiondCmd2_4.sessiond_enable_handler enableCmd = new
+ LTTngSessiondCmd2_4.sessiond_enable_handler();
+
+ synchronized (eventMap) {
+ String loggerName;
+ Enumeration loggers = handler.logManager.getLoggerNames();
+
/*
- * Modifying events in a Set will raise a
- * ConcurrentModificationException. Thus, we remove an event
- * and add its modified version to modifiedEvents when a
- * modification is necessary.
+ * Create an event for each logger found and attach it to the
+ * handler.
*/
- Set<LTTngEvent> modifiedEvents = new HashSet<LTTngEvent>();
- Iterator<LTTngEvent> it = enabledEventSet.iterator();
+ while (loggers.hasMoreElements()) {
+ ArrayList<LTTngEvent> bucket;
- while (it.hasNext()) {
- int ret;
- Logger logger;
- LTTngEvent event = it.next();
+ loggerName = loggers.nextElement().toString();
- /*
- * Check if this Logger name has been enabled already. Note
- * that in the case of "*", it's never added in that hash
- * table thus the enable command does a lookup for each
- * logger name in that hash table for the * case in order
- * to make sure we don't enable twice the same logger
- * because JUL apparently accepts that the *same*
- * LogHandler can be added twice on a Logger object...
- * don't ask...
- */
- logger = enabledLoggers.get(event.name);
- if (logger != null) {
+ /* Logger is already enabled or end of list, skip it. */
+ if (handler.exists(loggerName) == true ||
+ loggerName.equals("")) {
continue;
}
- /*
- * Set to one means that the enable all event has been seen
- * thus event from that point on must use loglevel for all
- * events. Else the object has its own loglevel.
- */
- if (handler.logLevelUseAll == 1) {
- it.remove();
- event.logLevels.addAll(handler.logLevelsAll);
- modifiedEvents.add(event);
+ bucket = eventMap.get(loggerName);
+ if (bucket == null) {
+ /* No event(s) exist for this logger. */
+ continue;
}
- /*
- * The all event is a special case since we have to iterate
- * over every Logger to see which one was not enabled.
- */
- if (event.name.equals("*")) {
+ for (LTTngEvent event : bucket) {
enableCmd.name = event.name;
- /* Tell the command NOT to add the loglevel. */
- enableCmd.lttngLogLevel = -1;
- /*
- * The return value is irrelevant since the * event is
- * always kept in the set.
- */
- enableCmd.execute(handler, enabledLoggers);
- continue;
- }
+ enableCmd.lttngLogLevel = event.logLevel.level;
+ enableCmd.lttngLogLevelType = event.logLevel.type;
- ret = enableCmd.enableLogger(handler, event, enabledLoggers);
- if (ret == 1) {
- /* Enabled so remove the event from the set. */
- if (!modifiedEvents.remove(event)) {
- /*
- * event can only be present in one of
- * the sets.
- */
- it.remove();
- }
+ /* Event exist so pass null here. */
+ enableCmd.execute(handler, null, wildCardSet);
}
}
- enabledEventSet.addAll(modifiedEvents);
}
+ /* Handle wild cards. */
+ synchronized (wildCardSet) {
+ Map<String, ArrayList<LTTngEvent>> modifiedEvents =
+ new HashMap<String, ArrayList<LTTngEvent>>();
+ Set<LTTngEvent> tmpSet = new HashSet<LTTngEvent>();
+ Iterator<LTTngEvent> it = wildCardSet.iterator();
+
+ while (it.hasNext()) {
+ LTTngEvent event = it.next();
+
+ /* Only support * for now. */
+ if (event.name.equals("*")) {
+ enableCmd.name = event.name;
+ enableCmd.lttngLogLevel = event.logLevel.level;
+ enableCmd.lttngLogLevelType = event.logLevel.type;
+
+ /* That might create a new event so pass the map. */
+ enableCmd.execute(handler, modifiedEvents, tmpSet);
+ }
+ }
+ eventMap.putAll(modifiedEvents);
+ }
}
}, this.timerDelay, this.timerDelay);
* Cleanup Agent state.
*/
private void cleanupState() {
- enabledEventSet.clear();
- enabledLoggers.clear();
+ eventMap.clear();
+ wildCardSet.clear();
if (this.handler != null) {
this.handler.clear();
}
break;
}
enableCmd.populate(data);
- event = enableCmd.execute(this.handler, this.enabledLoggers);
- if (event != null) {
- /*
- * Add the event to the set so it can be enabled if
- * the logger appears at some point in time.
- */
- enabledEventSet.add(event);
- }
+ enableCmd.execute(this.handler, this.eventMap, this.wildCardSet);
data = enableCmd.getBytes();
break;
}
break;
}
disableCmd.populate(data);
- disableCmd.execute(this.handler);
+ disableCmd.execute(this.handler, this.eventMap, this.wildCardSet);
data = disableCmd.getBytes();
break;
}