1 package org
.argeo
.cms
.internal
.osgi
;
3 import java
.security
.SignatureException
;
4 import java
.util
.Enumeration
;
6 import org
.argeo
.api
.cms
.CmsConstants
;
7 import org
.argeo
.api
.cms
.CmsLog
;
8 import org
.argeo
.cms
.runtime
.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
;
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";
23 private LogReaderService logReaderService
;
25 // /** Internal debug for development purposes. */
26 // private static Boolean debug = false;
28 // private Boolean disabled = false;
30 // private String level = null;
32 // private Level log4jLevel = null;
34 // private Properties configuration;
36 // private AppenderImpl appender;
38 // private BlockingQueue<LogEvent> events;
39 // private LogDispatcherThread logDispatcherThread = new LogDispatcherThread();
41 // private Integer maxLastEventsCount = 10 * 1000;
43 // /** Marker to prevent stack overflow */
44 // private ThreadLocal<Boolean> dispatching = new ThreadLocal<Boolean>() {
47 // protected Boolean initialValue() {
52 // public CmsOsgiLogger(LogReaderService lrs) {
56 if (logReaderService
!= null) {
57 Enumeration
<LogEntry
> logEntries
= logReaderService
.getLog();
58 while (logEntries
.hasMoreElements())
59 logged(logEntries
.nextElement());
60 logReaderService
.addLogListener(this);
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());
72 // Path log4jconfigPath;
73 // if (log4jConfiguration.startsWith("file:"))
74 // log4jconfigPath = Paths.get(new URI(log4jConfiguration));
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());
85 //// events = new LinkedBlockingQueue<LogEvent>();
87 //// // if (layout != null)
88 //// // setLayout(layout);
90 //// // setLayout(new PatternLayout(pattern));
91 ////// appender = new AppenderImpl();
92 //// reloadConfiguration();
93 ////// Logger.getRootLogger().addAppender(appender);
95 //// logDispatcherThread = new LogDispatcherThread();
96 //// logDispatcherThread.start();
97 // } catch (Exception e) {
98 // throw new IllegalStateException("Cannot initialize log4j");
102 public void stop() throws Exception
{
105 // logDispatcherThread.interrupt();
106 logReaderService
.removeLogListener(this);
109 public String
toString() {
110 return "Node Logger";
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
)
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
));
131 pluginLog
.warn(msg(status
), status
.getException());
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());
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() + "'");
148 ServiceReference
<?
> sr
= status
.getServiceReference();
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
);
158 sb
.append(arrayToString(objectClasses
));
160 Object cn
= sr
.getProperty(CmsConstants
.CN
);
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
);
167 // Object servicePid = sr.getProperty(Constants.SERVICE_PID);
168 // if (servicePid != null)
169 // sb.append(" " + Constants.SERVICE_PID + ": " + servicePid);
172 Object whiteBoardPattern
= sr
.getProperty(WHITEBOARD_PATTERN_PROP
);
173 if (whiteBoardPattern
!= null) {
174 if (whiteBoardPattern
instanceof String
) {
175 sb
.append(" " + WHITEBOARD_PATTERN_PROP
+ ": " + whiteBoardPattern
);
177 sb
.append(" " + WHITEBOARD_PATTERN_PROP
+ ": " + arrayToString((String
[]) whiteBoardPattern
));
181 Object contextName
= sr
.getProperty(CONTEXT_NAME_PROP
);
182 if (contextName
!= null)
183 sb
.append(" " + CONTEXT_NAME_PROP
+ ": " + contextName
);
186 Object baseDn
= sr
.getProperty(DirectoryConf
.baseDn
.name());
188 sb
.append(" " + DirectoryConf
.baseDn
.name() + ": " + baseDn
);
191 return sb
.toString();
194 private String
arrayToString(Object
[] arr
) {
195 StringBuilder sb
= new StringBuilder();
197 for (int i
= 0; i
< arr
.length
; i
++) {
203 return sb
.toString();
206 private boolean isSpringApplicationContext(String
[] objectClasses
) {
207 for (String clss
: objectClasses
) {
208 if (clss
.equals("org.eclipse.gemini.blueprint.context.DelegatedExecutionOsgiBundleApplicationContext")) {
215 public void setLogReaderService(LogReaderService logReaderService
) {
216 this.logReaderService
= logReaderService
;
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");
229 // if (!userListeners.containsKey(username)) {
230 // List<ArgeoLogListener> lst = Collections.synchronizedList(new ArrayList<ArgeoLogListener>());
231 // userListeners.put(username, lst);
233 // userListeners.get(username).add(listener);
234 // List<LogEvent> lastEvents = logDispatcherThread.getLastEvents(username, numberOfPreviousEvents);
235 // for (LogEvent evt : lastEvents)
236 // dispatchEvent(listener, evt);
239 // public synchronized void registerForAll(ArgeoLogListener listener, Integer numberOfPreviousEvents,
240 // boolean everything) {
242 // everythingListeners.add(listener);
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);
251 // public synchronized void unregister(ArgeoLogListener listener) {
252 // String username = CurrentUser.getUsername();
253 // if (username == null)// FIXME
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);
265 // public synchronized void unregisterForAll(ArgeoLogListener listener) {
266 // everythingListeners.remove(listener);
267 // allUsersListeners.remove(listener);
270 // /** For development purpose, since using regular logging is not easy here */
271 // private static void stdOut(Object obj) {
272 // System.out.println(obj);
275 // private static void stdErr(Object obj) {
276 // System.err.println(obj);
279 // private static void debug(Object obj) {
281 // System.out.println(obj);
284 // private static boolean isInternalDebugEnabled() {
288 // public void setPattern(String pattern) {
289 // this.pattern = pattern;
292 // public void setDisabled(Boolean disabled) {
293 // this.disabled = disabled;
296 // public void setLevel(String level) {
297 // this.level = level;
300 // public void setConfiguration(Properties configuration) {
301 // this.configuration = configuration;
304 // public void updateConfiguration(Properties configuration) {
305 // setConfiguration(configuration);
306 // reloadConfiguration();
309 // public Properties getConfiguration() {
310 // return configuration;
314 // * Reloads configuration (if the configuration {@link Properties} is set)
316 // protected void reloadConfiguration() {
317 // if (configuration != null) {
318 //// LogManager.resetConfiguration();
319 //// PropertyConfigurator.configure(configuration);
323 // protected synchronized void processLoggingEvent(LogEvent event) {
327 // if (dispatching.get())
330 // if (level != null && !level.trim().equals("")) {
331 //// if (log4jLevel == null || !log4jLevel.toString().equals(level))
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();
340 //// if (log4jLevel != null && !event.getLoggingEvent().getLevel().isGreaterOrEqual(log4jLevel)) {
346 //// // admin listeners
347 //// Iterator<ArgeoLogListener> everythingIt = everythingListeners.iterator();
348 //// while (everythingIt.hasNext())
349 //// dispatchEvent(everythingIt.next(), event);
351 //// if (event.getUsername() != null) {
352 //// Iterator<ArgeoLogListener> allUsersIt = allUsersListeners.iterator();
353 //// while (allUsersIt.hasNext())
354 //// dispatchEvent(allUsersIt.next(), event);
356 //// if (userListeners.containsKey(event.getUsername())) {
357 //// Iterator<ArgeoLogListener> userIt = userListeners.get(event.getUsername()).iterator();
358 //// while (userIt.hasNext())
359 //// dispatchEvent(userIt.next(), event);
362 //// } catch (Exception e) {
363 //// stdOut("Cannot process logging event");
364 //// e.printStackTrace();
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());
374 // private class AppenderImpl { // extends AppenderSkeleton {
375 // public boolean requiresLayout() {
379 // public void close() {
383 //// protected void append(LoggingEvent event) {
384 //// if (events != null) {
386 //// String username = CurrentUser.getUsername();
387 //// events.put(new LogEvent(username, event));
388 //// } catch (InterruptedException e) {
396 // private class LogDispatcherThread extends Thread {
397 // /** encapsulated in order to simplify concurrency management */
398 // private LinkedList<LogEvent> lastEvents = new LinkedList<LogEvent>();
400 // public LogDispatcherThread() {
401 // super("Argeo Logging Dispatcher Thread");
404 // public void run() {
405 // while (events != null) {
407 // LogEvent loggingEvent = events.take();
408 // processLoggingEvent(loggingEvent);
409 // addLastEvent(loggingEvent);
410 // } catch (InterruptedException e) {
411 // if (events == null)
417 // protected synchronized void addLastEvent(LogEvent loggingEvent) {
418 // if (lastEvents.size() >= maxLastEventsCount)
419 // lastEvents.poll();
420 // lastEvents.add(loggingEvent);
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());
427 // while (it.hasPrevious() && (count < maxCount)) {
428 // LogEvent evt = it.previous();
429 // if (username == null || username.equals(evt.getUsername())) {
438 // private class LogEvent {
439 // private final String username;
440 //// private final LoggingEvent loggingEvent;
442 // public LogEvent(String username) {
444 // this.username = username;
445 //// this.loggingEvent = loggingEvent;
449 //// public int hashCode() {
450 //// return loggingEvent.hashCode();
454 //// public boolean equals(Object obj) {
455 //// return loggingEvent.equals(obj);
459 //// public String toString() {
460 //// return username + "@ " + loggingEvent.toString();
463 // public String getUsername() {
467 //// public LoggingEvent getLoggingEvent() {
468 //// return loggingEvent;
473 // private class Log4jConfWatcherThread extends Thread {
474 // private Path log4jConfigurationPath;
476 // public Log4jConfWatcherThread(Path log4jConfigurationPath) {
477 // super("Log4j Configuration Watcher");
479 // this.log4jConfigurationPath = log4jConfigurationPath.toRealPath();
480 // } catch (IOException e) {
481 // this.log4jConfigurationPath = log4jConfigurationPath.toAbsolutePath();
482 // stdOut("Cannot determine real path for " + log4jConfigurationPath + ": " + e.getMessage());
486 // public void run() {
487 // Path parentDir = log4jConfigurationPath.getParent();
488 // try (final WatchService watchService = FileSystems.getDefault().newWatchService()) {
489 // parentDir.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY);
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());
501 // boolean valid = wk.reset();
506 // } catch (IOException | InterruptedException e) {
507 // stdErr("Log4j configuration watcher failed: " + e.getMessage());