JUL: fix enable all event for delayed Logger
[lttng-ust.git] / liblttng-ust-jul / org / lttng / ust / jul / LTTngTCPSessiondClient.java
1 /*
2 * Copyright (C) 2013 - David Goulet <dgoulet@efficios.com>
3 *
4 * This library is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License, version 2.1 only,
6 * as published by the Free Software Foundation.
7 *
8 * This library is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
11 * for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this library; if not, write to the Free Software Foundation,
15 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17
18 package org.lttng.ust.jul;
19
20 import java.util.concurrent.Semaphore;
21 import java.nio.ByteBuffer;
22 import java.nio.ByteOrder;
23 import java.lang.Integer;
24 import java.io.IOException;
25 import java.io.BufferedOutputStream;
26 import java.io.ByteArrayOutputStream;
27 import java.io.DataOutputStream;
28 import java.io.DataInputStream;
29 import java.net.*;
30 import java.lang.management.ManagementFactory;
31 import java.util.ArrayList;
32 import java.util.HashMap;
33 import java.util.List;
34 import java.util.Timer;
35 import java.util.TimerTask;
36 import java.util.logging.Logger;
37
38 class USTRegisterMsg {
39 public static int pid;
40 }
41
42 public class LTTngTCPSessiondClient {
43 /* Command header from the session deamon. */
44 private LTTngSessiondCmd2_4.sessiond_hdr headerCmd =
45 new LTTngSessiondCmd2_4.sessiond_hdr();
46
47 private final String sessiondHost;
48 private final int sessiondPort;
49 private Socket sessiondSock;
50 private boolean quit = false;
51
52 private DataInputStream inFromSessiond;
53 private DataOutputStream outToSessiond;
54
55 private LTTngLogHandler handler;
56
57 private Semaphore registerSem;
58
59 private Timer eventTimer;
60 private List<String> enabledEventList = new ArrayList<String>();
61 /*
62 * Map of Logger objects that have been enabled. They are indexed by name.
63 */
64 private HashMap<String, Logger> enabledLoggers = new HashMap<String, Logger>();
65 /* Timer delay at each 5 seconds. */
66 private final static long timerDelay = 5 * 1000;
67 private static boolean timerInitialized;
68
69 public LTTngTCPSessiondClient(String host, int port, Semaphore sem) {
70 this.sessiondHost = host;
71 this.sessiondPort = port;
72 this.registerSem = sem;
73 this.eventTimer = new Timer();
74 this.timerInitialized = false;
75 }
76
77 private void setupEventTimer() {
78 if (this.timerInitialized) {
79 return;
80 }
81
82 this.eventTimer.scheduleAtFixedRate(new TimerTask() {
83 @Override
84 public void run() {
85 /*
86 * We have to make a copy here since it is possible that the
87 * enabled event list is changed during an iteration on it.
88 */
89 List<String> tmpList = new ArrayList<String>(enabledEventList);
90
91 LTTngSessiondCmd2_4.sessiond_enable_handler enableCmd = new
92 LTTngSessiondCmd2_4.sessiond_enable_handler();
93 for (String strEventName: tmpList) {
94 /*
95 * Check if this Logger name has been enabled already. Note
96 * that in the case of "*", it's never added in that hash
97 * table thus the enable command does a lookup for each
98 * logger name in that hash table for the * case in order
99 * to make sure we don't enable twice the same logger
100 * because JUL apparently accepts that the *same*
101 * LogHandler can be added twice on a Logger object...
102 * don't ask...
103 */
104 if (enabledLoggers.get(strEventName) != null) {
105 continue;
106 }
107
108 enableCmd.name = strEventName;
109 if (enableCmd.execute(handler, enabledLoggers) == null) {
110 enabledEventList.remove(strEventName);
111 }
112 }
113 }
114 }, this.timerDelay, this.timerDelay);
115
116 this.timerInitialized = true;
117 }
118
119 public void init(LTTngLogHandler handler) throws InterruptedException {
120 this.handler = handler;
121
122 for (;;) {
123 if (this.quit) {
124 break;
125 }
126
127 try {
128
129 /*
130 * Connect to the session daemon before anything else.
131 */
132 connectToSessiond();
133
134 /*
135 * Register to the session daemon as the Java component of the
136 * UST application.
137 */
138 registerToSessiond();
139 this.registerSem.release();
140
141 setupEventTimer();
142
143 /*
144 * Block on socket receive and wait for command from the
145 * session daemon. This will return if and only if there is a
146 * fatal error or the socket closes.
147 */
148 handleSessiondCmd();
149 } catch (UnknownHostException uhe) {
150 this.registerSem.release();
151 System.out.println(uhe);
152 } catch (IOException ioe) {
153 this.registerSem.release();
154 Thread.sleep(3000);
155 } catch (Exception e) {
156 this.registerSem.release();
157 e.printStackTrace();
158 }
159 }
160 }
161
162 public void destroy() {
163 this.quit = true;
164 this.eventTimer.cancel();
165
166 try {
167 if (this.sessiondSock != null) {
168 this.sessiondSock.close();
169 }
170 } catch (Exception e) {
171 e.printStackTrace();
172 }
173 }
174
175 /*
176 * Receive header data from the session daemon using the LTTng command
177 * static buffer of the right size.
178 */
179 private void recvHeader() throws Exception {
180 int read_len;
181 byte data[] = new byte[this.headerCmd.SIZE];
182
183 read_len = this.inFromSessiond.read(data, 0, data.length);
184 if (read_len != data.length) {
185 throw new IOException();
186 }
187 this.headerCmd.populate(data);
188 }
189
190 /*
191 * Receive payload from the session daemon. This MUST be done after a
192 * recvHeader() so the header value of a command are known.
193 *
194 * The caller SHOULD use isPayload() before which returns true if a payload
195 * is expected after the header.
196 */
197 private byte[] recvPayload() throws Exception {
198 byte payload[] = new byte[(int) this.headerCmd.data_size];
199
200 /* Failsafe check so we don't waste our time reading 0 bytes. */
201 if (payload.length == 0) {
202 return null;
203 }
204
205 this.inFromSessiond.read(payload, 0, payload.length);
206 return payload;
207 }
208
209 /*
210 * Handle session command from the session daemon.
211 */
212 private void handleSessiondCmd() throws Exception {
213 int ret_code;
214 byte data[] = null;
215
216 while (true) {
217 /* Get header from session daemon. */
218 recvHeader();
219
220 if (headerCmd.data_size > 0) {
221 data = recvPayload();
222 }
223
224 switch (headerCmd.cmd) {
225 case CMD_LIST:
226 {
227 LTTngSessiondCmd2_4.sessiond_list_logger listLoggerCmd =
228 new LTTngSessiondCmd2_4.sessiond_list_logger();
229 listLoggerCmd.execute(this.handler);
230 data = listLoggerCmd.getBytes();
231 break;
232 }
233 case CMD_ENABLE:
234 {
235 String event_name;
236 LTTngSessiondCmd2_4.sessiond_enable_handler enableCmd =
237 new LTTngSessiondCmd2_4.sessiond_enable_handler();
238 if (data == null) {
239 enableCmd.code = LTTngSessiondCmd2_4.lttng_jul_ret_code.CODE_INVALID_CMD;
240 break;
241 }
242 enableCmd.populate(data);
243 event_name = enableCmd.execute(this.handler, this.enabledLoggers);
244 if (event_name != null) {
245 /*
246 * Add the event to the list so it can be enabled if
247 * the logger appears at some point in time.
248 */
249 if (enabledEventList.contains(event_name) == false) {
250 enabledEventList.add(event_name);
251 }
252 }
253 data = enableCmd.getBytes();
254 break;
255 }
256 case CMD_DISABLE:
257 {
258 LTTngSessiondCmd2_4.sessiond_disable_handler disableCmd =
259 new LTTngSessiondCmd2_4.sessiond_disable_handler();
260 if (data == null) {
261 disableCmd.code = LTTngSessiondCmd2_4.lttng_jul_ret_code.CODE_INVALID_CMD;
262 break;
263 }
264 disableCmd.populate(data);
265 disableCmd.execute(this.handler);
266 data = disableCmd.getBytes();
267 break;
268 }
269 default:
270 {
271 data = new byte[4];
272 ByteBuffer buf = ByteBuffer.wrap(data);
273 buf.order(ByteOrder.BIG_ENDIAN);
274 LTTngSessiondCmd2_4.lttng_jul_ret_code code =
275 LTTngSessiondCmd2_4.lttng_jul_ret_code.CODE_INVALID_CMD;
276 buf.putInt(code.getCode());
277 break;
278 }
279 }
280
281 /* Send payload to session daemon. */
282 this.outToSessiond.write(data, 0, data.length);
283 this.outToSessiond.flush();
284 }
285 }
286
287 private void connectToSessiond() throws Exception {
288 this.sessiondSock = new Socket(this.sessiondHost, this.sessiondPort);
289 this.inFromSessiond = new DataInputStream(
290 sessiondSock.getInputStream());
291 this.outToSessiond = new DataOutputStream(
292 sessiondSock.getOutputStream());
293 }
294
295 private void registerToSessiond() throws Exception {
296 byte data[] = new byte[4];
297 ByteBuffer buf = ByteBuffer.wrap(data);
298 String pid = ManagementFactory.getRuntimeMXBean().getName().split("@")[0];
299
300 buf.putInt(Integer.parseInt(pid));
301 this.outToSessiond.write(data, 0, data.length);
302 this.outToSessiond.flush();
303 }
304 }
This page took 0.035463 seconds and 4 git commands to generate.