-/*
- * Copyright (C) 2007-2012 Argeo GmbH
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
package org.argeo.cms.internal.kernel;
+import java.io.IOException;
+import java.net.URI;
+import java.nio.file.FileSystems;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardWatchEventKinds;
+import java.nio.file.WatchEvent;
+import java.nio.file.WatchKey;
+import java.nio.file.WatchService;
import java.security.SignatureException;
import java.util.ArrayList;
import java.util.Collections;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.apache.log4j.AppenderSkeleton;
-import org.apache.log4j.Level;
-import org.apache.log4j.LogManager;
-import org.apache.log4j.Logger;
-import org.apache.log4j.PropertyConfigurator;
-import org.apache.log4j.spi.LoggingEvent;
+import org.argeo.api.ArgeoLogListener;
+import org.argeo.api.ArgeoLogger;
+import org.argeo.api.NodeConstants;
import org.argeo.cms.CmsException;
import org.argeo.cms.auth.CurrentUser;
-import org.argeo.node.ArgeoLogListener;
-import org.argeo.node.ArgeoLogger;
-import org.argeo.node.NodeConstants;
import org.argeo.osgi.useradmin.UserAdminConf;
+import org.osgi.framework.Bundle;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
import org.osgi.service.cm.ConfigurationAdmin;
import org.osgi.service.log.LogEntry;
+import org.osgi.service.log.LogLevel;
import org.osgi.service.log.LogListener;
import org.osgi.service.log.LogReaderService;
-import org.osgi.service.log.LogService;
/** Not meant to be used directly in standard log4j config */
class NodeLogger implements ArgeoLogger, LogListener {
+ /** Internal debug for development purposes. */
+ private static Boolean debug = false;
private Boolean disabled = false;
private String level = null;
- private Level log4jLevel = null;
- // private Layout layout;
+// private Level log4jLevel = null;
private Properties configuration;
}
};
- @SuppressWarnings("unchecked")
public NodeLogger(LogReaderService lrs) {
- Enumeration<LogEntry> logEntries = lrs.getLog();
- while (logEntries.hasMoreElements())
- logged(logEntries.nextElement());
- lrs.addLogListener(this);
+ if (lrs != null) {
+ Enumeration<LogEntry> logEntries = lrs.getLog();
+ while (logEntries.hasMoreElements())
+ logged(logEntries.nextElement());
+ lrs.addLogListener(this);
+
+ // configure log4j watcher
+ String log4jConfiguration = KernelUtils.getFrameworkProp("log4j.configuration");
+ if (log4jConfiguration != null && log4jConfiguration.startsWith("file:")) {
+ if (log4jConfiguration.contains("..")) {
+ if (log4jConfiguration.startsWith("file://"))
+ log4jConfiguration = log4jConfiguration.substring("file://".length());
+ else if (log4jConfiguration.startsWith("file:"))
+ log4jConfiguration = log4jConfiguration.substring("file:".length());
+ }
+ try {
+ Path log4jconfigPath;
+ if (log4jConfiguration.startsWith("file:"))
+ log4jconfigPath = Paths.get(new URI(log4jConfiguration));
+ else
+ log4jconfigPath = Paths.get(log4jConfiguration);
+ Thread log4jConfWatcher = new Log4jConfWatcherThread(log4jconfigPath);
+ log4jConfWatcher.start();
+ } catch (Exception e) {
+ stdErr("Badly formatted log4j configuration URI " + log4jConfiguration + ": " + e.getMessage());
+ }
+ }
+ }
}
public void init() {
// setLayout(new PatternLayout(pattern));
appender = new AppenderImpl();
reloadConfiguration();
- Logger.getRootLogger().addAppender(appender);
+// Logger.getRootLogger().addAppender(appender);
logDispatcherThread = new LogDispatcherThread();
logDispatcherThread.start();
}
public void destroy() throws Exception {
- Logger.getRootLogger().removeAppender(appender);
+// Logger.getRootLogger().removeAppender(appender);
allUsersListeners.clear();
for (List<ArgeoLogListener> lst : userListeners.values())
lst.clear();
// this.layout = layout;
// }
+ public String toString() {
+ return "Node Logger";
+ }
+
//
// OSGi LOGGER
//
@Override
public void logged(LogEntry status) {
Log pluginLog = LogFactory.getLog(status.getBundle().getSymbolicName());
- Integer severity = status.getLevel();
- if (severity == LogService.LOG_ERROR) {
+ LogLevel severity = status.getLogLevel();
+ if (severity.equals(LogLevel.ERROR) && pluginLog.isErrorEnabled()) {
// FIXME Fix Argeo TP
if (status.getException() instanceof SignatureException)
return;
pluginLog.error(msg(status), status.getException());
- } else if (severity == LogService.LOG_WARNING)
- pluginLog.warn(msg(status), status.getException());
- else if (severity == LogService.LOG_INFO && pluginLog.isDebugEnabled())
+ } else if (severity.equals(LogLevel.WARN) && pluginLog.isWarnEnabled()) {
+ if (pluginLog.isTraceEnabled())
+ pluginLog.warn(msg(status), status.getException());
+ else
+ pluginLog.warn(msg(status));
+ } else if (severity.equals(LogLevel.INFO) && pluginLog.isDebugEnabled())
pluginLog.debug(msg(status), status.getException());
- else if (severity == LogService.LOG_DEBUG && pluginLog.isTraceEnabled())
+ else if (severity.equals(LogLevel.DEBUG) && pluginLog.isTraceEnabled())
+ pluginLog.trace(msg(status), status.getException());
+ else if (severity.equals(LogLevel.TRACE) && pluginLog.isTraceEnabled())
pluginLog.trace(msg(status), status.getException());
}
private String msg(LogEntry status) {
StringBuilder sb = new StringBuilder();
sb.append(status.getMessage());
+ Bundle bundle = status.getBundle();
+ if (bundle != null) {
+ sb.append(" '" + bundle.getSymbolicName() + "'");
+ }
ServiceReference<?> sr = status.getServiceReference();
if (sr != null) {
sb.append(' ');
// }
// servlets
Object whiteBoardPattern = sr.getProperty(KernelConstants.WHITEBOARD_PATTERN_PROP);
- if (whiteBoardPattern != null)
- sb.append(" " + KernelConstants.WHITEBOARD_PATTERN_PROP + ": "
- + arrayToString((String[]) whiteBoardPattern));
+ if (whiteBoardPattern != null) {
+ if (whiteBoardPattern instanceof String) {
+ sb.append(" " + KernelConstants.WHITEBOARD_PATTERN_PROP + ": " + whiteBoardPattern);
+ } else {
+ sb.append(" " + KernelConstants.WHITEBOARD_PATTERN_PROP + ": "
+ + arrayToString((String[]) whiteBoardPattern));
+ }
+ }
// RWT
Object contextName = sr.getProperty(KernelConstants.CONTEXT_NAME_PROP);
if (contextName != null)
private String arrayToString(Object[] arr) {
StringBuilder sb = new StringBuilder();
- sb.append('{');
+ sb.append('[');
for (int i = 0; i < arr.length; i++) {
if (i != 0)
sb.append(',');
sb.append(arr[i]);
}
- sb.append('}');
+ sb.append(']');
return sb.toString();
}
}
/** For development purpose, since using regular logging is not easy here */
- static void stdOut(Object obj) {
+ private static void stdOut(Object obj) {
System.out.println(obj);
}
+ private static void stdErr(Object obj) {
+ System.err.println(obj);
+ }
+
+ private static void debug(Object obj) {
+ if (debug)
+ System.out.println(obj);
+ }
+
+ private static boolean isInternalDebugEnabled() {
+ return debug;
+ }
+
// public void setPattern(String pattern) {
// this.pattern = pattern;
// }
*/
protected void reloadConfiguration() {
if (configuration != null) {
- LogManager.resetConfiguration();
- PropertyConfigurator.configure(configuration);
+// LogManager.resetConfiguration();
+// PropertyConfigurator.configure(configuration);
}
}
return;
if (level != null && !level.trim().equals("")) {
- if (log4jLevel == null || !log4jLevel.toString().equals(level))
- try {
- log4jLevel = Level.toLevel(level);
- } catch (Exception e) {
- System.err.println("Log4j level could not be set for level '" + level + "', resetting it to null.");
- e.printStackTrace();
- level = null;
- }
-
- if (log4jLevel != null && !event.getLoggingEvent().getLevel().isGreaterOrEqual(log4jLevel)) {
- return;
- }
+// if (log4jLevel == null || !log4jLevel.toString().equals(level))
+// try {
+// log4jLevel = Level.toLevel(level);
+// } catch (Exception e) {
+// System.err.println("Log4j level could not be set for level '" + level + "', resetting it to null.");
+// e.printStackTrace();
+// level = null;
+// }
+//
+// if (log4jLevel != null && !event.getLoggingEvent().getLevel().isGreaterOrEqual(log4jLevel)) {
+// return;
+// }
}
try {
}
protected void dispatchEvent(ArgeoLogListener logListener, LogEvent evt) {
- LoggingEvent event = evt.getLoggingEvent();
- logListener.appendLog(evt.getUsername(), event.getTimeStamp(), event.getLevel().toString(),
- event.getLoggerName(), event.getThreadName(), event.getMessage(), event.getThrowableStrRep());
+// LoggingEvent event = evt.getLoggingEvent();
+// logListener.appendLog(evt.getUsername(), event.getTimeStamp(), event.getLevel().toString(),
+// event.getLoggerName(), event.getThreadName(), event.getMessage(), event.getThrowableStrRep());
}
- private class AppenderImpl extends AppenderSkeleton {
+ private class AppenderImpl { //extends AppenderSkeleton {
public boolean requiresLayout() {
return false;
}
public void close() {
}
- @Override
- protected void append(LoggingEvent event) {
- if (events != null) {
- try {
- String username = CurrentUser.getUsername();
- events.put(new LogEvent(username, event));
- } catch (InterruptedException e) {
- // silent
- }
- }
- }
+// @Override
+// protected void append(LoggingEvent event) {
+// if (events != null) {
+// try {
+// String username = CurrentUser.getUsername();
+// events.put(new LogEvent(username, event));
+// } catch (InterruptedException e) {
+// // silent
+// }
+// }
+// }
}
private class LogEvent {
private final String username;
- private final LoggingEvent loggingEvent;
+// private final LoggingEvent loggingEvent;
- public LogEvent(String username, LoggingEvent loggingEvent) {
+ public LogEvent(String username) {
super();
this.username = username;
- this.loggingEvent = loggingEvent;
+// this.loggingEvent = loggingEvent;
}
- @Override
- public int hashCode() {
- return loggingEvent.hashCode();
- }
-
- @Override
- public boolean equals(Object obj) {
- return loggingEvent.equals(obj);
- }
-
- @Override
- public String toString() {
- return username + "@ " + loggingEvent.toString();
- }
+// @Override
+// public int hashCode() {
+// return loggingEvent.hashCode();
+// }
+//
+// @Override
+// public boolean equals(Object obj) {
+// return loggingEvent.equals(obj);
+// }
+//
+// @Override
+// public String toString() {
+// return username + "@ " + loggingEvent.toString();
+// }
public String getUsername() {
return username;
}
- public LoggingEvent getLoggingEvent() {
- return loggingEvent;
+// public LoggingEvent getLoggingEvent() {
+// return loggingEvent;
+// }
+
+ }
+
+ private class Log4jConfWatcherThread extends Thread {
+ private Path log4jConfigurationPath;
+
+ public Log4jConfWatcherThread(Path log4jConfigurationPath) {
+ super("Log4j Configuration Watcher");
+ try {
+ this.log4jConfigurationPath = log4jConfigurationPath.toRealPath();
+ } catch (IOException e) {
+ this.log4jConfigurationPath = log4jConfigurationPath.toAbsolutePath();
+ stdOut("Cannot determine real path for " + log4jConfigurationPath + ": " + e.getMessage());
+ }
}
+ public void run() {
+ Path parentDir = log4jConfigurationPath.getParent();
+ try (final WatchService watchService = FileSystems.getDefault().newWatchService()) {
+ parentDir.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY);
+ WatchKey wk;
+ watching: while ((wk = watchService.take()) != null) {
+ for (WatchEvent<?> event : wk.pollEvents()) {
+ final Path changed = (Path) event.context();
+ if (log4jConfigurationPath.equals(parentDir.resolve(changed))) {
+ if (isInternalDebugEnabled())
+ debug(log4jConfigurationPath + " has changed, reloading.");
+// PropertyConfigurator.configure(log4jConfigurationPath.toUri().toURL());
+ }
+ }
+ // reset the key
+ boolean valid = wk.reset();
+ if (!valid) {
+ break watching;
+ }
+ }
+ } catch (IOException | InterruptedException e) {
+ stdErr("Log4j configuration watcher failed: " + e.getMessage());
+ }
+ }
}
}