--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.simantics.logging.ui</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
--- /dev/null
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
--- /dev/null
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Ui
+Bundle-SymbolicName: org.simantics.logging.ui;singleton:=true
+Bundle-Version: 1.0.0.qualifier
+Bundle-Activator: org.simantics.logging.ui.Activator
+Require-Bundle: javax.inject,
+ org.eclipse.osgi,
+ org.eclipse.jface,
+ org.eclipse.e4.ui.services,
+ org.eclipse.e4.core.di.annotations,
+ org.eclipse.core.runtime,
+ org.eclipse.ui.ide,
+ org.slf4j.api,
+ org.simantics.logging,
+ org.simantics.utils,
+ org.simantics.utils.ui
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Import-Package: javax.annotation;version="1.2.0"
+Bundle-ActivationPolicy: lazy
--- /dev/null
+source.. = src/
+output.. = bin/
+bin.includes = plugin.xml,\
+ META-INF/,\
+ .,\
+ icons/,\
+ fragment.e4xmi
--- /dev/null
+<?xml version="1.0" encoding="ASCII"?>
+<fragment:ModelFragments xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:commands="http://www.eclipse.org/ui/2010/UIModel/application/commands" xmlns:fragment="http://www.eclipse.org/ui/2010/UIModel/fragment" xmlns:menu="http://www.eclipse.org/ui/2010/UIModel/application/ui/menu" xmi:id="_BxaXACerEeWxCPrV0pAZQQ">
+ <fragments xsi:type="fragment:StringModelFragment" xmi:id="_QqSikIrOEeW7h_qdP9N9fw" featurename="commands" parentElementId="xpath:/">
+ <elements xsi:type="commands:Command" xmi:id="_UCYfwIrOEeW7h_qdP9N9fw" elementId="org.simantics.logging.ui.command.saveLogFiles" commandName="Save Logs" description="Save all important application log files to a ZIP-archive"/>
+ <elements xsi:type="commands:Command" xmi:id="_34UCQB3xEeiTyNdCNKIG-w" elementId="org.simantics.logging.ui.command.selectLogLevel" commandName="Select Logging Level" description="Select current logging level">
+ <parameters xmi:id="_YFD2kB3yEeiTyNdCNKIG-w" elementId="org.simantics.logging.ui.commandparameter.selectLoggingLevel" name="Logging Level" optional="false"/>
+ </elements>
+ </fragments>
+ <fragments xsi:type="fragment:StringModelFragment" xmi:id="_fW12kIrOEeW7h_qdP9N9fw" featurename="handlers" parentElementId="xpath:/">
+ <elements xsi:type="commands:Handler" xmi:id="_k2L0IIrOEeW7h_qdP9N9fw" elementId="org.simantics.logging.ui.handlers.saveLogFiles" contributionURI="bundleclass://org.simantics.logging.ui/org.simantics.logging.ui.handlers.SaveLogFilesHandler" command="_UCYfwIrOEeW7h_qdP9N9fw"/>
+ <elements xsi:type="commands:Handler" xmi:id="_60CMgB3xEeiTyNdCNKIG-w" elementId="org.simantics.logging.ui.handlers.selectLogLevel" contributionURI="bundleclass://org.simantics.logging.ui/org.simantics.logging.ui.handlers.SelectLoggingLevelHandler" command="_34UCQB3xEeiTyNdCNKIG-w"/>
+ </fragments>
+ <fragments xsi:type="fragment:StringModelFragment" xmi:id="_pVgfIIrOEeW7h_qdP9N9fw" featurename="menuContributions" parentElementId="xpath:/">
+ <elements xsi:type="menu:MenuContribution" xmi:id="_tSwX0IrOEeW7h_qdP9N9fw" elementId="org.simantics.logging.ui.menucontribution.saveLogFiles" positionInParent="after=group.main.ext" parentId="help">
+ <children xsi:type="menu:HandledMenuItem" xmi:id="_2LM_MIrOEeW7h_qdP9N9fw" elementId="org.simantics.logging.ui.saveLogFiles.handledmenuitem" label="Save Logs" iconURI="platform:/plugin/org.simantics.logging.ui/icons/page_white_compressed.png" tooltip="Save all important application log files to a ZIP-archive" command="_UCYfwIrOEeW7h_qdP9N9fw"/>
+ </elements>
+ <elements xsi:type="menu:MenuContribution" xmi:id="_fGQd4B3xEeiTyNdCNKIG-w" elementId="org.simantics.logging.ui.menucontribution.selectLoggingLevelMenu" positionInParent="after=group.main.ext" parentId="help">
+ <children xsi:type="menu:Menu" xmi:id="_jtqG0B3xEeiTyNdCNKIG-w" elementId="org.simantics.logging.ui.menucontribution.selectLoggingLevelSubMenu" label="Logging Level.." iconURI="platform:/plugin/org.simantics.logging.ui/icons/page_white_edit.png">
+ <children xsi:type="menu:HandledMenuItem" xmi:id="_PVgsgB3yEeiTyNdCNKIG-w" elementId="org.simantics.logging.ui.handledmenuitem.selectLoggingLevel.trace" label="TRACE" iconURI="platform:/plugin/org.simantics.logging.ui/icons/text_align_left.png" type="Radio" command="_34UCQB3xEeiTyNdCNKIG-w">
+ <parameters xmi:id="_XQtogB3yEeiTyNdCNKIG-w" elementId="org.simantics.logging.ui.parameter.loggingLevel.trace" name="org.simantics.logging.ui.commandparameter.selectLoggingLevel" value="TRACE"/>
+ </children>
+ <children xsi:type="menu:HandledMenuItem" xmi:id="_5bsEEB3yEeiTyNdCNKIG-w" elementId="org.simantics.logging.ui.handledmenuitem.selectLoggingLevel.debug" label="DEBUG" iconURI="platform:/plugin/org.simantics.logging.ui/icons/bug.png" type="Radio" command="_34UCQB3xEeiTyNdCNKIG-w">
+ <parameters xmi:id="_5bsEER3yEeiTyNdCNKIG-w" elementId="org.simantics.logging.ui.parameter.loggingLevel.debug" name="org.simantics.logging.ui.commandparameter.selectLoggingLevel" value="DEBUG"/>
+ </children>
+ <children xsi:type="menu:HandledMenuItem" xmi:id="_5fIZoB3yEeiTyNdCNKIG-w" elementId="org.simantics.logging.ui.handledmenuitem.selectLoggingLevel.info" label="INFO" iconURI="platform:/plugin/org.simantics.logging.ui/icons/information.png" selected="true" type="Radio" command="_34UCQB3xEeiTyNdCNKIG-w">
+ <parameters xmi:id="_5fIZoR3yEeiTyNdCNKIG-w" elementId="org.simantics.logging.ui.parameter.loggingLevel.info" name="org.simantics.logging.ui.commandparameter.selectLoggingLevel" value="INFO"/>
+ </children>
+ <children xsi:type="menu:HandledMenuItem" xmi:id="_5ihE0B3yEeiTyNdCNKIG-w" elementId="org.simantics.logging.ui.handledmenuitem.selectLoggingLevel.warn" label="WARN" iconURI="platform:/plugin/org.simantics.logging.ui/icons/warning.png" type="Radio" command="_34UCQB3xEeiTyNdCNKIG-w">
+ <parameters xmi:id="_5ihE0R3yEeiTyNdCNKIG-w" elementId="org.simantics.logging.ui.parameter.loggingLevel.warn" name="org.simantics.logging.ui.commandparameter.selectLoggingLevel" value="WARN"/>
+ </children>
+ <children xsi:type="menu:HandledMenuItem" xmi:id="_55I1EB3yEeiTyNdCNKIG-w" elementId="org.simantics.logging.ui.handledmenuitem.selectLoggingLevel.error" label="ERROR" iconURI="platform:/plugin/org.simantics.logging.ui/icons/error.png" type="Radio" command="_34UCQB3xEeiTyNdCNKIG-w">
+ <parameters xmi:id="_55I1ER3yEeiTyNdCNKIG-w" elementId="org.simantics.logging.ui.parameter.loggingLevel.error" name="org.simantics.logging.ui.commandparameter.selectLoggingLevel" value="ERROR"/>
+ </children>
+ </children>
+ </elements>
+ </fragments>
+</fragment:ModelFragments>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>
+
+ <extension
+ id="org.simantics.logging.ui.fragment"
+ point="org.eclipse.e4.workbench.model">
+ <fragment
+ apply="initial"
+ uri="fragment.e4xmi">
+ </fragment>
+ </extension>
+
+</plugin>
--- /dev/null
+package org.simantics.logging.ui;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+public class Activator implements BundleActivator {
+
+ private static BundleContext context;
+
+ static BundleContext getContext() {
+ return context;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
+ */
+ public void start(BundleContext bundleContext) throws Exception {
+ Activator.context = bundleContext;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
+ */
+ public void stop(BundleContext bundleContext) throws Exception {
+ Activator.context = null;
+ }
+
+}
--- /dev/null
+package org.simantics.logging.ui.handlers;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.inject.Named;
+
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.e4.core.di.annotations.Execute;
+import org.eclipse.e4.ui.services.IServiceConstants;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Shell;
+import org.simantics.logging.LogCollector;
+import org.simantics.utils.FileUtils;
+import org.simantics.utils.ui.ExceptionUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SaveLogFilesHandler {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(SaveLogFilesHandler.class);
+
+ private static final String[] FILTER_NAMES = { "ZIP-archive", "AllFiles (*:*)" };
+ private static final String[] FILTER_EXTENSIONS = { "*.zip", "*.*" };
+ private static final String USER_HOME = System.getProperty("user.home");
+
+ @Execute
+ public void execute(@Named(IServiceConstants.ACTIVE_SHELL) Shell shell) {
+
+ FileDialog dialog = new FileDialog(shell, SWT.SAVE);
+ dialog.setFilterNames(FILTER_NAMES);
+ dialog.setFilterExtensions(FILTER_EXTENSIONS);
+ if (USER_HOME != null) {
+ if (Files.exists(Paths.get(USER_HOME))) {
+ dialog.setFilterPath(USER_HOME);
+ }
+ }
+ StringBuilder fileName = new StringBuilder();
+ String productName = Platform.getProduct().getName();
+ if (productName != null)
+ fileName.append(productName.replaceAll(" ", "_")).append("-");
+
+ fileName.append("logs-").append(currentLocalDateTimeStamp());
+ String actualFileName = fileName.toString();
+ if (LOGGER.isDebugEnabled())
+ LOGGER.debug("Resolved log files name {}", actualFileName);
+ dialog.setFileName(actualFileName);
+
+ String destination = dialog.open();
+ if (destination != null) {
+ if (LOGGER.isDebugEnabled())
+ LOGGER.debug("Destination for saving log files is {}", destination);
+
+ try {
+ Path tempDir = Files.createTempDirectory(actualFileName);
+ Map<String, List<Path>> allLogs = LogCollector.allLogs();
+ for (Entry<String, List<Path>> logEntry : allLogs.entrySet()) {
+ Path subFolder = tempDir.resolve(logEntry.getKey());
+ Files.createDirectory(subFolder);
+ for (Path p : logEntry.getValue()) {
+ try {
+ Files.copy(p, subFolder.resolve(p.getFileName()));
+ } catch (IOException e) {
+ LOGGER.error("Could not copy {}", p.toAbsolutePath(), e);
+ }
+ }
+ }
+ FileUtils.compressZip(tempDir.toAbsolutePath().toString(), destination);
+ FileUtils.delete(tempDir);
+ } catch (Throwable t) {
+ LOGGER.error("Could not save log files to ZIP", t);
+ ExceptionUtils.logAndShowError("Could not save log files to ZIP", t);
+ }
+ } else {
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("No destination selected for saving logs");
+ }
+ }
+ }
+
+ private static String currentLocalDateTimeStamp() {
+ return LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd_HHmm"));
+ }
+
+}
--- /dev/null
+package org.simantics.logging.ui.handlers;
+
+import javax.inject.Named;
+
+import org.eclipse.e4.core.di.annotations.Execute;
+import org.simantics.logging.LogConfigurator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SelectLoggingLevelHandler {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(SelectLoggingLevelHandler.class);
+
+ @Execute
+ public void execute(@Named("org.simantics.logging.ui.commandparameter.selectLoggingLevel") String level) {
+ if (LOGGER.isDebugEnabled())
+ LOGGER.debug("Setting logging level to {}", level);
+ LogConfigurator.setLoggingLevel(level);
+ }
+
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.simantics.logging</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ds.core.builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
--- /dev/null
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
--- /dev/null
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Simantics Logging Core
+Bundle-SymbolicName: org.simantics.logging
+Bundle-Version: 1.0.0.qualifier
+Bundle-Activator: org.simantics.logging.internal.Activator
+Bundle-Vendor: Semantum Oy
+Require-Bundle: org.eclipse.core.runtime,
+ org.slf4j.api,
+ ch.qos.logback.classic,
+ ch.qos.logback.core
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Bundle-ActivationPolicy: lazy
+Service-Component: logbackLogProvider.xml,
+ dbAndMetadataLogProvider.xml
+Export-Package: org.simantics.logging
--- /dev/null
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ scl/,\
+ logbackLogProvider.xml,\
+ dbAndMetadataLogProvider.xml
+source.. = src/
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="org.simantics.logging.dbAndMetadataLogProvider">
+ <implementation class="org.simantics.logging.DBAndMetadataLogProvider"/>
+ <service>
+ <provide interface="org.simantics.logging.LogProvider"/>
+ </service>
+</scr:component>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="org.simantics.logging">
+ <implementation class="org.simantics.logging.LogbackLogProvider"/>
+ <service>
+ <provide interface="org.simantics.logging.LogProvider"/>
+ </service>
+</scr:component>
--- /dev/null
+import "Files"
+import "Map" as Map
+
+importJava "org.simantics.logging.LogConfigurator" where
+ setLoggingLevel :: String -> <Proc> ()
+ setLoggingLevelForLogger :: String -> String -> <Proc> ()
+
+importJava "org.simantics.logging.LogCollector" where
+ allLogs :: <Proc> Map.T String [Path]
\ No newline at end of file
--- /dev/null
+package org.simantics.logging;
+
+import java.lang.reflect.Field;
+import java.net.URL;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.Platform;
+import org.osgi.framework.Bundle;
+import org.slf4j.LoggerFactory;
+
+public class DBAndMetadataLogProvider implements LogProvider {
+
+ private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(DBAndMetadataLogProvider.class);
+
+ @Override
+ public List<Path> get() {
+ List<Path> logs = new ArrayList<>();
+ Path dbClientLog = getDBClientLogLocation();
+ if (dbClientLog != null)
+ logs.add(dbClientLog);
+ Path metadataLogLocation = getMetadataLogLocation();
+ if (metadataLogLocation != null)
+ logs.add(metadataLogLocation);
+ return logs;
+ }
+
+ private static Path getDBClientLogLocation() {
+ Bundle bundle = Platform.getBundle("org.simantics.db.common");
+ try {
+ Class<?> forName = bundle.loadClass("org.simantics.db.common.internal.config.InternalClientConfig");
+ Field field = forName.getField("DB_CLIENT_LOG_FILE");
+ String value = (String) field.get(null);
+ return Paths.get(value);
+ } catch (ClassNotFoundException | NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
+ LOGGER.error("Could not read db-client.log location", e);
+ }
+ return null;
+ }
+
+ private static Path getMetadataLogLocation() {
+ String prop = System.getProperty("osgi.instance.area", null);
+ if (prop != null) {
+ try {
+ URL url = new URL(prop);
+ if ("file".equals(url .getProtocol())) {
+ Path path = Paths.get(url.toURI());
+ return path.resolve(".metadata").resolve(".log");
+ } else {
+ LOGGER.warn("Unsupported protocol {}", url);
+ }
+ } catch (Throwable t) {
+ LOGGER.error("Could not get .metadata/.log", t);
+ }
+ }
+ return null;
+ }
+}
--- /dev/null
+package org.simantics.logging;
+
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.simantics.logging.internal.Activator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class LogCollector {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(LogCollector.class);
+
+ public static Map<String, List<Path>> allLogs() {
+ Map<String, List<Path>> results = new HashMap<>();
+ if (LOGGER.isDebugEnabled())
+ LOGGER.debug("Collecting all logs from declarative services");
+
+ Collection<LogProvider> logProviders = getLogProviders();
+ for (LogProvider logProvider : logProviders) {
+ List<Path> logs = logProvider.get();
+ String key = logProvider.getClass().getSimpleName();
+ Collection<Path> existing = results.get(key);
+ if (existing != null) {
+ LOGGER.info("Duplicate log providers with name {} exist, merging logs", key);
+ logs.addAll(existing);
+ }
+ results.put(key, logs);
+ }
+ if (LOGGER.isDebugEnabled())
+ LOGGER.debug("Found logs from {} providers", results.keySet());
+ return results;
+ }
+
+ private static List<LogProvider> getLogProviders() {
+ ServiceReference<?>[] serviceReferences = new ServiceReference<?>[0];
+ String key = LogProvider.class.getName();
+ try {
+ serviceReferences = Activator.getContext().getAllServiceReferences(key, null);
+ } catch (InvalidSyntaxException e) {
+ LOGGER.error("Could not get service references for {}!", key, e);
+ }
+ if (serviceReferences.length == 0) {
+ if (LOGGER.isDebugEnabled())
+ LOGGER.debug("No service references found for {}", key);
+ return Collections.emptyList();
+ }
+
+ List<LogProvider> logProviders = new ArrayList<>(serviceReferences.length);
+ for (ServiceReference<?> reference : serviceReferences) {
+ LogProvider logProvider = (LogProvider) Activator.getContext().getService(reference);
+ logProviders.add(logProvider);
+ }
+ if (LOGGER.isDebugEnabled())
+ LOGGER.debug("Found {} log providers", logProviders);
+ return logProviders;
+ }
+}
--- /dev/null
+package org.simantics.logging;
+
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.LoggerContext;
+
+/**
+ * Class for modifying the active logging configuration
+ *
+ * @author Jani Simomaa
+ *
+ */
+public final class LogConfigurator {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(LogConfigurator.class);
+
+ private LogConfigurator() {
+ }
+
+ /**
+ * Sets logging level to represent the given argument
+ *
+ * @param level ERROR WARN INFO DEBUG TRACE
+ */
+ public static void setLoggingLevel(String level) {
+ if (LOGGER.isInfoEnabled())
+ LOGGER.info("Setting logger level to {}", level);
+ LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
+ Level ll = getLoggerLevel(level);
+ List<ch.qos.logback.classic.Logger> loggerList = context.getLoggerList();
+ loggerList.forEach(l -> l.setLevel(ll));
+ if (LOGGER.isDebugEnabled())
+ LOGGER.debug("Loggers installed {}", loggerList);
+ }
+
+ public static void setLoggingLevelForLogger(String logger, String level) {
+ if (LOGGER.isInfoEnabled())
+ LOGGER.info("Setting logger level to {} for loggers {}", level, logger);
+ LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
+ Level ll = getLoggerLevel(level);
+ ch.qos.logback.classic.Logger loggerList = context.getLogger(logger);
+ loggerList.setLevel(ll);
+ if (LOGGER.isDebugEnabled())
+ LOGGER.debug("Loggers installed {}", loggerList);
+ }
+
+ private static Level getLoggerLevel(String level) {
+ return Level.valueOf(level);
+ }
+}
--- /dev/null
+package org.simantics.logging;
+
+import java.nio.file.Path;
+import java.util.List;
+import java.util.function.Supplier;
+
+public interface LogProvider extends Supplier<List<Path>> {
+
+}
--- /dev/null
+package org.simantics.logging;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.slf4j.LoggerFactory;
+
+import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.Appender;
+import ch.qos.logback.core.FileAppender;
+import ch.qos.logback.core.rolling.RollingFileAppender;
+import ch.qos.logback.core.spi.AppenderAttachable;
+
+public class LogbackLogProvider implements LogProvider {
+
+ private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(LogbackLogProvider.class);
+
+ @Override
+ public List<Path> get() {
+ List<Path> logs = new ArrayList<>();
+ try {
+ LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
+ Logger logger = context.getLogger(Logger.ROOT_LOGGER_NAME);
+ Iterator<Appender<ILoggingEvent>> appenderIter = logger.iteratorForAppenders();
+ while (appenderIter.hasNext()) {
+ FileAppender<ILoggingEvent> appender = findFileAppender(appenderIter.next());
+ if (appender != null) {
+ String logFile = ((FileAppender<ILoggingEvent>)appender).getFile();
+ Path log = Paths.get(logFile).toAbsolutePath();
+ if (appender instanceof RollingFileAppender) {
+ // Collect all logs
+ Path parent = log.getParent();
+ List<Path> newLogs = Files.walk(parent).collect(Collectors.toList());
+ if (LOGGER.isDebugEnabled())
+ LOGGER.debug("Found {} from {}", newLogs, appender);
+ logs.addAll(newLogs);
+ } else {
+ logs.add(log);
+ }
+ } else {
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("Appender is not {} but is {} instead", FileAppender.class.getName(), appender != null ? appender.getClass().getName() : "null");
+ }
+ }
+ }
+ } catch (ClassCastException e) {
+ // Okay, we are not using logback here
+ if (LOGGER.isDebugEnabled())
+ LOGGER.debug("Seems like we are not using logback but {} instead", LoggerFactory.getILoggerFactory(), e);
+ } catch (Throwable t) {
+ LOGGER.error("Could not collect logs", t);
+ }
+ if (LOGGER.isDebugEnabled())
+ LOGGER.debug("Found {} log files : {}", logs.size(), logs);
+ return logs;
+ }
+
+ private static FileAppender<ILoggingEvent> findFileAppender(Appender<ILoggingEvent> appender) {
+ if (appender instanceof AppenderAttachable) {
+ // Ok, has child appender
+ Iterator<Appender<ILoggingEvent>> children = ((AppenderAttachable<ILoggingEvent>) appender).iteratorForAppenders();
+ while (children.hasNext()) {
+ FileAppender<ILoggingEvent> app = findFileAppender(children.next());
+ // TODO: returns only first FileAppender that it founds but not a collection
+ if (app != null)
+ return app;
+ }
+ return null;
+ } else if (appender instanceof FileAppender) {
+ return (FileAppender<ILoggingEvent>) appender;
+ } else {
+ return null;
+ }
+ }
+
+}
--- /dev/null
+package org.simantics.logging.internal;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+public class Activator implements BundleActivator {
+
+ private static BundleContext context;
+
+ public static BundleContext getContext() {
+ return context;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
+ */
+ public void start(BundleContext bundleContext) throws Exception {
+ Activator.context = bundleContext;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
+ */
+ public void stop(BundleContext bundleContext) throws Exception {
+ Activator.context = null;
+ }
+
+}
<module>org.simantics.layer0.utils</module>
<module>org.simantics.layer0x.ontology</module>
<module>org.simantics.logback.configuration</module>
+ <module>org.simantics.logging</module>
+ <module>org.simantics.logging.ui</module>
<module>org.simantics.ltk</module>
<module>org.simantics.ltk.antlr</module>
<module>org.simantics.lz4</module>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.simantics.logging.feature</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.pde.FeatureBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.FeatureNature</nature>
+ </natures>
+</projectDescription>
--- /dev/null
+bin.includes = feature.xml
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<feature
+ id="org.simantics.logging.feature"
+ label="Simantics Logging Feature"
+ version="1.0.0.qualifier"
+ provider-name="Semantum Oy">
+
+ <description url="http://www.example.com/description">
+ [Enter Feature Description here.]
+ </description>
+
+ <copyright url="http://www.example.com/copyright">
+ [Enter Copyright Description here.]
+ </copyright>
+
+ <license url="http://www.example.com/license">
+ [Enter License Description here.]
+ </license>
+
+ <plugin
+ id="org.simantics.logging"
+ download-size="0"
+ install-size="0"
+ version="0.0.0"
+ unpack="false"/>
+
+</feature>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.simantics.logging.ui.feature</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.pde.FeatureBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.FeatureNature</nature>
+ </natures>
+</projectDescription>
--- /dev/null
+bin.includes = feature.xml
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<feature
+ id="org.simantics.logging.ui.feature"
+ label="Simantics Logging UI Feature"
+ version="1.0.0.qualifier"
+ provider-name="Semantum Oy">
+
+ <description url="http://www.example.com/description">
+ [Enter Feature Description here.]
+ </description>
+
+ <copyright url="http://www.example.com/copyright">
+ [Enter Copyright Description here.]
+ </copyright>
+
+ <license url="http://www.example.com/license">
+ [Enter License Description here.]
+ </license>
+
+ <includes
+ id="org.simantics.logging.feature"
+ version="0.0.0"/>
+
+ <plugin
+ id="org.simantics.logging.ui"
+ download-size="0"
+ install-size="0"
+ version="0.0.0"
+ unpack="false"/>
+
+</feature>
id="hdf.hdf5"
version="0.0.0"/>
+ <includes
+ id="org.simantics.logging.feature"
+ version="0.0.0"/>
+
+ <includes
+ id="org.simantics.logging.ui.feature"
+ version="0.0.0"/>
+
<plugin
id="org.simantics.fileimport"
download-size="0"
<module>org.simantics.issues.feature</module>
<module>org.simantics.issues.ui.feature</module>
<module>org.simantics.layer0.feature</module>
+ <module>org.simantics.logging.feature</module>
+ <module>org.simantics.logging.ui.feature</module>
<module>org.simantics.message.feature</module>
<module>org.simantics.migration.feature</module>
<module>org.simantics.modeling.feature</module>