-/*
- * 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.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 final static Log log = LogFactory.getLog(NodeLogger.class);
private Boolean disabled = false;
}
};
- @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() {
// 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(' ');
}
/** 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;
// }
}
}
+
+ 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());
+ }
+ }
+ }
}