]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.cms/src/org/argeo/cms/internal/osgi/CmsOsgiLogger.java
Support writing file as XML
[lgpl/argeo-commons.git] / org.argeo.cms / src / org / argeo / cms / internal / osgi / CmsOsgiLogger.java
1 package org.argeo.cms.internal.osgi;
2
3 import java.security.SignatureException;
4 import java.util.Enumeration;
5
6 import org.argeo.api.cms.CmsConstants;
7 import org.argeo.api.cms.CmsLog;
8 import org.argeo.util.directory.DirectoryConf;
9 import org.osgi.framework.Bundle;
10 import org.osgi.framework.Constants;
11 import org.osgi.framework.ServiceReference;
12 import org.osgi.service.cm.ConfigurationAdmin;
13 import org.osgi.service.log.LogEntry;
14 import org.osgi.service.log.LogLevel;
15 import org.osgi.service.log.LogListener;
16 import org.osgi.service.log.LogReaderService;
17
18 /** Logs OSGi events. */
19 public class CmsOsgiLogger implements LogListener {
20 private final static String WHITEBOARD_PATTERN_PROP = "osgi.http.whiteboard.servlet.pattern";
21 private final static String CONTEXT_NAME_PROP = "contextName";
22
23 private LogReaderService logReaderService;
24
25 // /** Internal debug for development purposes. */
26 // private static Boolean debug = false;
27
28 // private Boolean disabled = false;
29 //
30 // private String level = null;
31
32 // private Level log4jLevel = null;
33
34 // private Properties configuration;
35
36 // private AppenderImpl appender;
37
38 // private BlockingQueue<LogEvent> events;
39 // private LogDispatcherThread logDispatcherThread = new LogDispatcherThread();
40
41 // private Integer maxLastEventsCount = 10 * 1000;
42 //
43 // /** Marker to prevent stack overflow */
44 // private ThreadLocal<Boolean> dispatching = new ThreadLocal<Boolean>() {
45 //
46 // @Override
47 // protected Boolean initialValue() {
48 // return false;
49 // }
50 // };
51
52 // public CmsOsgiLogger(LogReaderService lrs) {
53 // }
54
55 public void start() {
56 if (logReaderService != null) {
57 Enumeration<LogEntry> logEntries = logReaderService.getLog();
58 while (logEntries.hasMoreElements())
59 logged(logEntries.nextElement());
60 logReaderService.addLogListener(this);
61
62 // configure log4j watcher
63 // String log4jConfiguration = KernelUtils.getFrameworkProp("log4j.configuration");
64 // if (log4jConfiguration != null && log4jConfiguration.startsWith("file:")) {
65 // if (log4jConfiguration.contains("..")) {
66 // if (log4jConfiguration.startsWith("file://"))
67 // log4jConfiguration = log4jConfiguration.substring("file://".length());
68 // else if (log4jConfiguration.startsWith("file:"))
69 // log4jConfiguration = log4jConfiguration.substring("file:".length());
70 // }
71 // try {
72 // Path log4jconfigPath;
73 // if (log4jConfiguration.startsWith("file:"))
74 // log4jconfigPath = Paths.get(new URI(log4jConfiguration));
75 // else
76 // log4jconfigPath = Paths.get(log4jConfiguration);
77 // Thread log4jConfWatcher = new Log4jConfWatcherThread(log4jconfigPath);
78 // log4jConfWatcher.start();
79 // } catch (Exception e) {
80 // stdErr("Badly formatted log4j configuration URI " + log4jConfiguration + ": " + e.getMessage());
81 // }
82 // }
83 }
84 // try {
85 //// events = new LinkedBlockingQueue<LogEvent>();
86 ////
87 //// // if (layout != null)
88 //// // setLayout(layout);
89 //// // else
90 //// // setLayout(new PatternLayout(pattern));
91 ////// appender = new AppenderImpl();
92 //// reloadConfiguration();
93 ////// Logger.getRootLogger().addAppender(appender);
94 ////
95 //// logDispatcherThread = new LogDispatcherThread();
96 //// logDispatcherThread.start();
97 // } catch (Exception e) {
98 // throw new IllegalStateException("Cannot initialize log4j");
99 // }
100 }
101
102 public void stop() throws Exception {
103 // events.clear();
104 // events = null;
105 // logDispatcherThread.interrupt();
106 logReaderService.removeLogListener(this);
107 }
108
109 public String toString() {
110 return "Node Logger";
111 }
112
113 //
114 // OSGi LOGGER
115 //
116 @Override
117 public void logged(LogEntry status) {
118 CmsLog pluginLog = CmsLog.getLog(status.getBundle().getSymbolicName());
119 LogLevel severity = status.getLogLevel();
120 if (severity.equals(LogLevel.ERROR) && pluginLog.isErrorEnabled()) {
121 // FIXME Fix Argeo TP
122 if (status.getException() instanceof SignatureException)
123 return;
124 pluginLog.error(msg(status), status.getException());
125 } else if (severity.equals(LogLevel.WARN) && pluginLog.isWarnEnabled()) {
126 if ("org.apache.felix.scr".equals(status.getBundle().getSymbolicName())
127 && (status.getException() != null && status.getException() instanceof InterruptedException)) {
128 // do not print stacktraces by Felix SCR shutdown
129 pluginLog.warn(msg(status));
130 } else {
131 pluginLog.warn(msg(status), status.getException());
132 }
133 } else if (severity.equals(LogLevel.INFO) && pluginLog.isDebugEnabled())
134 pluginLog.debug(msg(status), status.getException());
135 else if (severity.equals(LogLevel.DEBUG) && pluginLog.isTraceEnabled())
136 pluginLog.trace(msg(status), status.getException());
137 else if (severity.equals(LogLevel.TRACE) && pluginLog.isTraceEnabled())
138 pluginLog.trace(msg(status), status.getException());
139 }
140
141 private String msg(LogEntry status) {
142 StringBuilder sb = new StringBuilder();
143 sb.append(status.getMessage());
144 Bundle bundle = status.getBundle();
145 if (bundle != null) {
146 sb.append(" '" + bundle.getSymbolicName() + "'");
147 }
148 ServiceReference<?> sr = status.getServiceReference();
149 if (sr != null) {
150 sb.append(' ');
151 String[] objectClasses = (String[]) sr.getProperty(Constants.OBJECTCLASS);
152 if (isSpringApplicationContext(objectClasses)) {
153 sb.append("{org.springframework.context.ApplicationContext}");
154 Object symbolicName = sr.getProperty(Constants.BUNDLE_SYMBOLICNAME);
155 if (symbolicName != null)
156 sb.append(" " + Constants.BUNDLE_SYMBOLICNAME + ": " + symbolicName);
157 } else {
158 sb.append(arrayToString(objectClasses));
159 }
160 Object cn = sr.getProperty(CmsConstants.CN);
161 if (cn != null)
162 sb.append(" " + CmsConstants.CN + ": " + cn);
163 Object factoryPid = sr.getProperty(ConfigurationAdmin.SERVICE_FACTORYPID);
164 if (factoryPid != null)
165 sb.append(" " + ConfigurationAdmin.SERVICE_FACTORYPID + ": " + factoryPid);
166 // else {
167 // Object servicePid = sr.getProperty(Constants.SERVICE_PID);
168 // if (servicePid != null)
169 // sb.append(" " + Constants.SERVICE_PID + ": " + servicePid);
170 // }
171 // servlets
172 Object whiteBoardPattern = sr.getProperty(WHITEBOARD_PATTERN_PROP);
173 if (whiteBoardPattern != null) {
174 if (whiteBoardPattern instanceof String) {
175 sb.append(" " + WHITEBOARD_PATTERN_PROP + ": " + whiteBoardPattern);
176 } else {
177 sb.append(" " + WHITEBOARD_PATTERN_PROP + ": " + arrayToString((String[]) whiteBoardPattern));
178 }
179 }
180 // RWT
181 Object contextName = sr.getProperty(CONTEXT_NAME_PROP);
182 if (contextName != null)
183 sb.append(" " + CONTEXT_NAME_PROP + ": " + contextName);
184
185 // user directories
186 Object baseDn = sr.getProperty(DirectoryConf.baseDn.name());
187 if (baseDn != null)
188 sb.append(" " + DirectoryConf.baseDn.name() + ": " + baseDn);
189
190 }
191 return sb.toString();
192 }
193
194 private String arrayToString(Object[] arr) {
195 StringBuilder sb = new StringBuilder();
196 sb.append('[');
197 for (int i = 0; i < arr.length; i++) {
198 if (i != 0)
199 sb.append(',');
200 sb.append(arr[i]);
201 }
202 sb.append(']');
203 return sb.toString();
204 }
205
206 private boolean isSpringApplicationContext(String[] objectClasses) {
207 for (String clss : objectClasses) {
208 if (clss.equals("org.eclipse.gemini.blueprint.context.DelegatedExecutionOsgiBundleApplicationContext")) {
209 return true;
210 }
211 }
212 return false;
213 }
214
215 public void setLogReaderService(LogReaderService logReaderService) {
216 this.logReaderService = logReaderService;
217 }
218
219
220 //
221 // ARGEO LOGGER
222 //
223
224 // public synchronized void register(ArgeoLogListener listener, Integer numberOfPreviousEvents) {
225 // String username = CurrentUser.getUsername();
226 // if (username == null)
227 // throw new IllegalStateException("Only authenticated users can register a log listener");
228 //
229 // if (!userListeners.containsKey(username)) {
230 // List<ArgeoLogListener> lst = Collections.synchronizedList(new ArrayList<ArgeoLogListener>());
231 // userListeners.put(username, lst);
232 // }
233 // userListeners.get(username).add(listener);
234 // List<LogEvent> lastEvents = logDispatcherThread.getLastEvents(username, numberOfPreviousEvents);
235 // for (LogEvent evt : lastEvents)
236 // dispatchEvent(listener, evt);
237 // }
238 //
239 // public synchronized void registerForAll(ArgeoLogListener listener, Integer numberOfPreviousEvents,
240 // boolean everything) {
241 // if (everything)
242 // everythingListeners.add(listener);
243 // else
244 // allUsersListeners.add(listener);
245 // List<LogEvent> lastEvents = logDispatcherThread.getLastEvents(null, numberOfPreviousEvents);
246 // for (LogEvent evt : lastEvents)
247 // if (everything || evt.getUsername() != null)
248 // dispatchEvent(listener, evt);
249 // }
250 //
251 // public synchronized void unregister(ArgeoLogListener listener) {
252 // String username = CurrentUser.getUsername();
253 // if (username == null)// FIXME
254 // return;
255 // if (!userListeners.containsKey(username))
256 // throw new IllegalStateException("No user listeners " + listener + " registered for user " + username);
257 // if (!userListeners.get(username).contains(listener))
258 // throw new IllegalStateException("No user listeners " + listener + " registered for user " + username);
259 // userListeners.get(username).remove(listener);
260 // if (userListeners.get(username).isEmpty())
261 // userListeners.remove(username);
262 //
263 // }
264 //
265 // public synchronized void unregisterForAll(ArgeoLogListener listener) {
266 // everythingListeners.remove(listener);
267 // allUsersListeners.remove(listener);
268 // }
269
270 // /** For development purpose, since using regular logging is not easy here */
271 // private static void stdOut(Object obj) {
272 // System.out.println(obj);
273 // }
274 //
275 // private static void stdErr(Object obj) {
276 // System.err.println(obj);
277 // }
278 //
279 // private static void debug(Object obj) {
280 // if (debug)
281 // System.out.println(obj);
282 // }
283 //
284 // private static boolean isInternalDebugEnabled() {
285 // return debug;
286 // }
287
288 // public void setPattern(String pattern) {
289 // this.pattern = pattern;
290 // }
291
292 // public void setDisabled(Boolean disabled) {
293 // this.disabled = disabled;
294 // }
295 //
296 // public void setLevel(String level) {
297 // this.level = level;
298 // }
299
300 // public void setConfiguration(Properties configuration) {
301 // this.configuration = configuration;
302 // }
303 //
304 // public void updateConfiguration(Properties configuration) {
305 // setConfiguration(configuration);
306 // reloadConfiguration();
307 // }
308 //
309 // public Properties getConfiguration() {
310 // return configuration;
311 // }
312 //
313 // /**
314 // * Reloads configuration (if the configuration {@link Properties} is set)
315 // */
316 // protected void reloadConfiguration() {
317 // if (configuration != null) {
318 //// LogManager.resetConfiguration();
319 //// PropertyConfigurator.configure(configuration);
320 // }
321 // }
322
323 // protected synchronized void processLoggingEvent(LogEvent event) {
324 // if (disabled)
325 // return;
326 //
327 // if (dispatching.get())
328 // return;
329 //
330 // if (level != null && !level.trim().equals("")) {
331 //// if (log4jLevel == null || !log4jLevel.toString().equals(level))
332 //// try {
333 //// log4jLevel = Level.toLevel(level);
334 //// } catch (Exception e) {
335 //// System.err.println("Log4j level could not be set for level '" + level + "', resetting it to null.");
336 //// e.printStackTrace();
337 //// level = null;
338 //// }
339 ////
340 //// if (log4jLevel != null && !event.getLoggingEvent().getLevel().isGreaterOrEqual(log4jLevel)) {
341 //// return;
342 //// }
343 // }
344 //
345 //// try {
346 //// // admin listeners
347 //// Iterator<ArgeoLogListener> everythingIt = everythingListeners.iterator();
348 //// while (everythingIt.hasNext())
349 //// dispatchEvent(everythingIt.next(), event);
350 ////
351 //// if (event.getUsername() != null) {
352 //// Iterator<ArgeoLogListener> allUsersIt = allUsersListeners.iterator();
353 //// while (allUsersIt.hasNext())
354 //// dispatchEvent(allUsersIt.next(), event);
355 ////
356 //// if (userListeners.containsKey(event.getUsername())) {
357 //// Iterator<ArgeoLogListener> userIt = userListeners.get(event.getUsername()).iterator();
358 //// while (userIt.hasNext())
359 //// dispatchEvent(userIt.next(), event);
360 //// }
361 //// }
362 //// } catch (Exception e) {
363 //// stdOut("Cannot process logging event");
364 //// e.printStackTrace();
365 //// }
366 // }
367
368 // protected void dispatchEvent(ArgeoLogListener logListener, LogEvent evt) {
369 //// LoggingEvent event = evt.getLoggingEvent();
370 //// logListener.appendLog(evt.getUsername(), event.getTimeStamp(), event.getLevel().toString(),
371 //// event.getLoggerName(), event.getThreadName(), event.getMessage(), event.getThrowableStrRep());
372 // }
373
374 // private class AppenderImpl { // extends AppenderSkeleton {
375 // public boolean requiresLayout() {
376 // return false;
377 // }
378 //
379 // public void close() {
380 // }
381 //
382 //// @Override
383 //// protected void append(LoggingEvent event) {
384 //// if (events != null) {
385 //// try {
386 //// String username = CurrentUser.getUsername();
387 //// events.put(new LogEvent(username, event));
388 //// } catch (InterruptedException e) {
389 //// // silent
390 //// }
391 //// }
392 //// }
393 //
394 // }
395
396 // private class LogDispatcherThread extends Thread {
397 // /** encapsulated in order to simplify concurrency management */
398 // private LinkedList<LogEvent> lastEvents = new LinkedList<LogEvent>();
399 //
400 // public LogDispatcherThread() {
401 // super("Argeo Logging Dispatcher Thread");
402 // }
403 //
404 // public void run() {
405 // while (events != null) {
406 // try {
407 // LogEvent loggingEvent = events.take();
408 // processLoggingEvent(loggingEvent);
409 // addLastEvent(loggingEvent);
410 // } catch (InterruptedException e) {
411 // if (events == null)
412 // return;
413 // }
414 // }
415 // }
416 //
417 // protected synchronized void addLastEvent(LogEvent loggingEvent) {
418 // if (lastEvents.size() >= maxLastEventsCount)
419 // lastEvents.poll();
420 // lastEvents.add(loggingEvent);
421 // }
422 //
423 // public synchronized List<LogEvent> getLastEvents(String username, Integer maxCount) {
424 // LinkedList<LogEvent> evts = new LinkedList<LogEvent>();
425 // ListIterator<LogEvent> it = lastEvents.listIterator(lastEvents.size());
426 // int count = 0;
427 // while (it.hasPrevious() && (count < maxCount)) {
428 // LogEvent evt = it.previous();
429 // if (username == null || username.equals(evt.getUsername())) {
430 // evts.push(evt);
431 // count++;
432 // }
433 // }
434 // return evts;
435 // }
436 // }
437
438 // private class LogEvent {
439 // private final String username;
440 //// private final LoggingEvent loggingEvent;
441 //
442 // public LogEvent(String username) {
443 // super();
444 // this.username = username;
445 //// this.loggingEvent = loggingEvent;
446 // }
447 //
448 //// @Override
449 //// public int hashCode() {
450 //// return loggingEvent.hashCode();
451 //// }
452 ////
453 //// @Override
454 //// public boolean equals(Object obj) {
455 //// return loggingEvent.equals(obj);
456 //// }
457 ////
458 //// @Override
459 //// public String toString() {
460 //// return username + "@ " + loggingEvent.toString();
461 //// }
462 //
463 // public String getUsername() {
464 // return username;
465 // }
466 //
467 //// public LoggingEvent getLoggingEvent() {
468 //// return loggingEvent;
469 //// }
470 //
471 // }
472 //
473 // private class Log4jConfWatcherThread extends Thread {
474 // private Path log4jConfigurationPath;
475 //
476 // public Log4jConfWatcherThread(Path log4jConfigurationPath) {
477 // super("Log4j Configuration Watcher");
478 // try {
479 // this.log4jConfigurationPath = log4jConfigurationPath.toRealPath();
480 // } catch (IOException e) {
481 // this.log4jConfigurationPath = log4jConfigurationPath.toAbsolutePath();
482 // stdOut("Cannot determine real path for " + log4jConfigurationPath + ": " + e.getMessage());
483 // }
484 // }
485 //
486 // public void run() {
487 // Path parentDir = log4jConfigurationPath.getParent();
488 // try (final WatchService watchService = FileSystems.getDefault().newWatchService()) {
489 // parentDir.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY);
490 // WatchKey wk;
491 // watching: while ((wk = watchService.take()) != null) {
492 // for (WatchEvent<?> event : wk.pollEvents()) {
493 // final Path changed = (Path) event.context();
494 // if (log4jConfigurationPath.equals(parentDir.resolve(changed))) {
495 // if (isInternalDebugEnabled())
496 // debug(log4jConfigurationPath + " has changed, reloading.");
497 //// PropertyConfigurator.configure(log4jConfigurationPath.toUri().toURL());
498 // }
499 // }
500 // // reset the key
501 // boolean valid = wk.reset();
502 // if (!valid) {
503 // break watching;
504 // }
505 // }
506 // } catch (IOException | InterruptedException e) {
507 // stdErr("Log4j configuration watcher failed: " + e.getMessage());
508 // }
509 // }
510 // }
511 }