X-Git-Url: https://git.lttng.org/?a=blobdiff_plain;f=liblttng-ust-jul%2Forg%2Flttng%2Fust%2Fjul%2FLTTngTCPSessiondClient.java;h=f3ac80dc6e78860ae8ae4fb72cfb182da65a445d;hb=3c3a0129d36e41b4c007ab008f603813efbb66ac;hp=b89deb818c4702514d86842570abf9a9aac16dcd;hpb=43e5396b3b2247a3f57a8a797239359df3ff083f;p=lttng-ust.git diff --git a/liblttng-ust-jul/org/lttng/ust/jul/LTTngTCPSessiondClient.java b/liblttng-ust-jul/org/lttng/ust/jul/LTTngTCPSessiondClient.java index b89deb81..f3ac80dc 100644 --- a/liblttng-ust-jul/org/lttng/ust/jul/LTTngTCPSessiondClient.java +++ b/liblttng-ust-jul/org/lttng/ust/jul/LTTngTCPSessiondClient.java @@ -23,15 +23,24 @@ import java.nio.ByteOrder; import java.lang.Integer; import java.io.IOException; import java.io.BufferedOutputStream; +import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.DataInputStream; +import java.io.FileReader; +import java.io.FileNotFoundException; import java.net.*; import java.lang.management.ManagementFactory; import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; import java.util.List; +import java.util.Set; import java.util.Timer; import java.util.TimerTask; +import java.util.logging.Logger; +import java.util.Collections; class USTRegisterMsg { public static int pid; @@ -43,7 +52,6 @@ public class LTTngTCPSessiondClient { new LTTngSessiondCmd2_4.sessiond_hdr(); private final String sessiondHost; - private final int sessiondPort; private Socket sessiondSock; private boolean quit = false; @@ -55,14 +63,24 @@ public class LTTngTCPSessiondClient { private Semaphore registerSem; private Timer eventTimer; - private List enabledEventList = new ArrayList(); + private Set enabledEventSet = + Collections.synchronizedSet(new HashSet()); + /* + * Map of Logger objects that have been enabled. They are indexed by name. + */ + private HashMap enabledLoggers = new HashMap(); /* Timer delay at each 5 seconds. */ private final static long timerDelay = 5 * 1000; private static boolean timerInitialized; - public LTTngTCPSessiondClient(String host, int port, Semaphore sem) { + private static final String rootPortFile = "/var/run/lttng/jul.port"; + private static final String userPortFile = "/.lttng/jul.port"; + + /* Indicate if we've already release the semaphore. */ + private boolean sem_posted = false; + + public LTTngTCPSessiondClient(String host, Semaphore sem) { this.sessiondHost = host; - this.sessiondPort = port; this.registerSem = sem; this.eventTimer = new Timer(); this.timerInitialized = false; @@ -76,26 +94,98 @@ public class LTTngTCPSessiondClient { this.eventTimer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { - /* - * We have to make a copy here since it is possible that the - * enabled event list is changed during an iteration on it. - */ - List tmpList = new ArrayList(enabledEventList); - - LTTngSessiondCmd2_4.sessiond_enable_handler enableCmd = new - LTTngSessiondCmd2_4.sessiond_enable_handler(); - for (String strEventName: tmpList) { - enableCmd.name = strEventName; - if (enableCmd.execute(handler) == null) { - enabledEventList.remove(strEventName); + synchronized (enabledEventSet) { + LTTngSessiondCmd2_4.sessiond_enable_handler enableCmd = new + LTTngSessiondCmd2_4.sessiond_enable_handler(); + /* + * 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. + */ + Set modifiedEvents = new HashSet(); + Iterator it = enabledEventSet.iterator(); + + while (it.hasNext()) { + int ret; + Logger logger; + LTTngEvent event = it.next(); + + /* + * 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) { + 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); + } + + /* + * 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("*")) { + 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; + } + + 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(); + } + } } + enabledEventSet.addAll(modifiedEvents); } + } }, this.timerDelay, this.timerDelay); this.timerInitialized = true; } + /* + * Try to release the registerSem if it's not already done. + */ + private void tryReleaseSem() + { + /* Release semaphore so we unblock the agent. */ + if (!this.sem_posted) { + this.registerSem.release(); + this.sem_posted = true; + } + } + public void init(LTTngLogHandler handler) throws InterruptedException { this.handler = handler; @@ -116,7 +206,6 @@ public class LTTngTCPSessiondClient { * UST application. */ registerToSessiond(); - this.registerSem.release(); setupEventTimer(); @@ -127,13 +216,13 @@ public class LTTngTCPSessiondClient { */ handleSessiondCmd(); } catch (UnknownHostException uhe) { - this.registerSem.release(); + tryReleaseSem(); System.out.println(uhe); } catch (IOException ioe) { - this.registerSem.release(); + tryReleaseSem(); Thread.sleep(3000); } catch (Exception e) { - this.registerSem.release(); + tryReleaseSem(); e.printStackTrace(); } } @@ -202,6 +291,19 @@ public class LTTngTCPSessiondClient { } switch (headerCmd.cmd) { + case CMD_REG_DONE: + { + /* + * Release semaphore so meaning registration is done and we + * can proceed to continue tracing. + */ + tryReleaseSem(); + /* + * We don't send any reply to the registration done command. + * This just marks the end of the initial session setup. + */ + continue; + } case CMD_LIST: { LTTngSessiondCmd2_4.sessiond_list_logger listLoggerCmd = @@ -212,7 +314,7 @@ public class LTTngTCPSessiondClient { } case CMD_ENABLE: { - String event_name; + LTTngEvent event; LTTngSessiondCmd2_4.sessiond_enable_handler enableCmd = new LTTngSessiondCmd2_4.sessiond_enable_handler(); if (data == null) { @@ -220,13 +322,13 @@ public class LTTngTCPSessiondClient { break; } enableCmd.populate(data); - event_name = enableCmd.execute(this.handler); - if (event_name != null) { + event = enableCmd.execute(this.handler, this.enabledLoggers); + if (event != null) { /* - * Add the event to the list so it can be enabled if + * Add the event to the set so it can be enabled if * the logger appears at some point in time. */ - enabledEventList.add(event_name); + enabledEventSet.add(event); } data = enableCmd.getBytes(); break; @@ -262,8 +364,54 @@ public class LTTngTCPSessiondClient { } } + private String getHomePath() { + return System.getProperty("user.home"); + } + + /** + * Read port number from file created by the session daemon. + * + * @return port value if found else 0. + */ + private int getPortFromFile(String path) throws IOException { + int port; + BufferedReader br; + + try { + br = new BufferedReader(new FileReader(path)); + String line = br.readLine(); + port = Integer.parseInt(line, 10); + if (port < 0 || port > 65535) { + /* Invalid value. Ignore. */ + port = 0; + } + br.close(); + } catch (FileNotFoundException e) { + /* No port available. */ + port = 0; + } + + return port; + } + private void connectToSessiond() throws Exception { - this.sessiondSock = new Socket(this.sessiondHost, this.sessiondPort); + int port; + + if (this.handler.is_root == 1) { + port = getPortFromFile(rootPortFile); + if (port == 0) { + /* No session daemon available. Stop and retry later. */ + throw new IOException(); + } + } else { + port = getPortFromFile(getHomePath() + userPortFile); + if (port == 0) { + /* No session daemon available. Stop and retry later. */ + throw new IOException(); + } + } + + this.sessiondSock = new Socket(this.sessiondHost, port); this.inFromSessiond = new DataInputStream( sessiondSock.getInputStream()); this.outToSessiond = new DataOutputStream(