Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Option to send Equinox Framework trace to the OSGi LogService #766

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
@RunWith(Suite.class)
@Suite.SuiteClasses({ //
AllLogServiceTests.class, //
AllExtendedLogServiceTests.class //
AllExtendedLogServiceTests.class, //
LogEquinoxTraceTest.class, //
})
public class AllTests {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
/*******************************************************************************
* Copyright (c) 2007, 2022 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors: IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.equinox.log.test;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.equinox.log.SynchronousLogListener;
import org.eclipse.osgi.internal.debug.Debug;
import org.eclipse.osgi.launch.Equinox;
import org.eclipse.osgi.service.debug.DebugOptions;
import org.eclipse.osgi.tests.OSGiTestsActivator;
import org.eclipse.osgi.tests.bundles.AbstractBundleTests;
import org.junit.Test;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
import org.osgi.service.condition.Condition;
import org.osgi.service.log.LogEntry;
import org.osgi.service.log.LogLevel;
import org.osgi.service.log.LogReaderService;
import org.osgi.service.log.Logger;
import org.osgi.service.log.admin.LoggerAdmin;
import org.osgi.service.log.admin.LoggerContext;
import org.osgi.service.startlevel.StartLevel;

@SuppressWarnings("deprecation") // LogService
public class LogEquinoxTraceTest extends AbstractBundleTests {

static class TestListener implements SynchronousLogListener {
List<LogEntry> logs = new ArrayList<>();

@Override
public void logged(LogEntry entry) {
synchronized (logs) {
Bundle b = entry.getBundle();
if (b != null && b.getBundleId() == 0) {
logs.add(entry);
}
}
}

List<LogEntry> getLogs() {
synchronized (logs) {
List<LogEntry> results = new ArrayList(logs);
logs.clear();
return results;
}
}
}

private LoggerAdmin loggerAdmin = null;
private TestListener testListener = null;
private Equinox equinox = null;

@Override
public void setUp() throws Exception {
File config = OSGiTestsActivator.getContext().getDataFile(getName());
Map<String, Object> configuration = new HashMap<>();
configuration.put(Constants.FRAMEWORK_STORAGE, config.getAbsolutePath());
equinox = new Equinox(configuration);
equinox.start();
loggerAdmin = equinox.getBundleContext()
.getService(equinox.getBundleContext().getServiceReference(LoggerAdmin.class));
LogReaderService logReader = equinox.getBundleContext()
.getService(equinox.getBundleContext().getServiceReference(LogReaderService.class));

testListener = new TestListener();
logReader.addLogListener(testListener);
}

@Override
public void tearDown() {
if (equinox != null) {
try {
equinox.stop();
} catch (Exception e) {
// ignore
}
}
}

@Test
public void testEnableTrace() {
BundleContext systemContext = equinox.getBundleContext();
DebugOptions debugOptions = systemContext.getService(systemContext.getServiceReference(DebugOptions.class));
assertFalse("Expected debug options to be disabled.", debugOptions.isDebugEnabled());
assertEquals("Expected no debug Options.", 0, debugOptions.getOptions().size());

LoggerContext rootContext = loggerAdmin.getLoggerContext(null);
Map<String, LogLevel> rootLogLevels = rootContext.getLogLevels();

// enable service trace
rootLogLevels.put(Debug.EQUINOX_TRACE, LogLevel.TRACE);
rootLogLevels.put(Debug.OPTION_DEBUG_SERVICES, LogLevel.TRACE);
rootContext.setLogLevels(rootLogLevels);

assertTrue("Expected debug to be enabled.", debugOptions.isDebugEnabled());
assertEquals("Expected 1 debug Option.", 1, debugOptions.getOptions().size());
assertTrue("Expected trace option to be enabled.",
debugOptions.getBooleanOption(Debug.OPTION_DEBUG_SERVICES, false));
assertFalse("Expected trace option to be disabled.",
debugOptions.getBooleanOption(Debug.OPTION_DEBUG_STARTLEVEL, false));

// get some service to generate trace
ServiceReference<StartLevel> ref = equinox.getBundleContext().getServiceReference(StartLevel.class);
List<LogEntry> traceLogs = testListener.getLogs();
assertNotEquals("Expected to have some trace logs.", 0, traceLogs.size());
for (LogEntry logEntry : traceLogs) {
assertEquals("Wrong logger name", Debug.OPTION_DEBUG_SERVICES,
logEntry.getLoggerName());
}

// disable service trace, enable startlevel trace
rootLogLevels.remove(Debug.OPTION_DEBUG_SERVICES);
rootLogLevels.put(Debug.OPTION_DEBUG_STARTLEVEL, LogLevel.TRACE);
rootContext.setLogLevels(rootLogLevels);

assertTrue("Expected debug to be enabled.", debugOptions.isDebugEnabled());
assertEquals("Expected 1 debug Option.", 1, debugOptions.getOptions().size());
assertTrue("Expected trace option to be enabled.",
debugOptions.getBooleanOption(Debug.OPTION_DEBUG_STARTLEVEL, false));
assertFalse("Expected trace option to be disabled.",
debugOptions.getBooleanOption(Debug.OPTION_DEBUG_SERVICES, false));

// Get the StartLevel service to generate service logs (should be disabled)
// Use the StartLevel service to generate startlevel logs (should be enabled)
StartLevel startLevel = equinox.getBundleContext().getService(ref);
startLevel.setStartLevel(20);

traceLogs = testListener.getLogs();
assertNotEquals("Expected to have some trace logs.", 0, traceLogs.size());
for (LogEntry logEntry : traceLogs) {
assertEquals("Wrong logger name", Debug.OPTION_DEBUG_STARTLEVEL,
logEntry.getLoggerName());
}

// remove all debug options which should disable debug trace
rootLogLevels.clear();
rootLogLevels.put(Debug.EQUINOX_TRACE, LogLevel.TRACE);
rootContext.setLogLevels(rootLogLevels);
assertFalse("Expected debug to be disabled.", debugOptions.isDebugEnabled());
assertEquals("Expected no debug Options.", 0, debugOptions.getOptions().size());
}

@Test
public void testRootLoggerTrace() {
LoggerContext rootContext = loggerAdmin.getLoggerContext(null);
Map<String, LogLevel> rootLogLevels = rootContext.getLogLevels();

// make sure that enabling the root logger trace does not enable all Equinox
// trace
rootLogLevels.put(Logger.ROOT_LOGGER_NAME, LogLevel.TRACE);
// enable some unused trace for equinox
rootLogLevels.put(Debug.EQUINOX_TRACE, LogLevel.TRACE);
rootLogLevels.put(Debug.OPTION_DEBUG_STARTLEVEL, LogLevel.TRACE);
rootContext.setLogLevels(rootLogLevels);

// get some service to generate trace
equinox.getBundleContext().getServiceReference(Condition.class);
List<LogEntry> traceLogs = testListener.getLogs();
assertEquals("Did not expect any trace logs.", 0, traceLogs.size());
}

@Test
public void testLoaderTrace() {
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
Expand Down Expand Up @@ -82,7 +81,6 @@
import org.eclipse.osgi.container.namespaces.EclipsePlatformNamespace;
import org.eclipse.osgi.container.namespaces.EquinoxModuleDataNamespace;
import org.eclipse.osgi.framework.util.ThreadInfoReport;
import org.eclipse.osgi.internal.debug.Debug;
import org.eclipse.osgi.internal.framework.EquinoxConfiguration;
import org.eclipse.osgi.report.resolution.ResolutionReport;
import org.eclipse.osgi.tests.container.dummys.DummyCollisionHook;
Expand Down Expand Up @@ -1879,20 +1877,15 @@ public void testUses1Dynamic() throws BundleException, IOException {
ModuleWire dynamicWire = container.resolveDynamic("uses1", uses_c_dynamic.getCurrentRevision());
assertNotNull("No dynamic wire.", dynamicWire);

PrintStream originalOut = Debug.out;
ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
PrintStream testOut = new PrintStream(bytesOut);
Debug.out = testOut;
try {
dynamicWire = container.resolveDynamic("uses2", uses_c_dynamic.getCurrentRevision());
assertNull("Dynamic wire found.", dynamicWire);
} finally {
Debug.out = originalOut;
testOut.close();
}
String traceOutput = bytesOut.toString();
assertTrue("Wrong traceOutput: " + traceOutput,
traceOutput.startsWith("org.apache.felix.resolver.reason.ReasonException"));
dynamicWire = container.resolveDynamic("uses2", uses_c_dynamic.getCurrentRevision());
assertNull("Dynamic wire found.", dynamicWire);

List<String> messages = adaptor.getTraceMessages();
assertEquals("Did not expect messages", 0, messages.size());
List<Throwable> throwables = adaptor.getTraceThrowables();
assertEquals("Expected a resolution exception.", 1, throwables.size());
assertEquals("Expected a resolution exception.", "org.apache.felix.resolver.reason.ReasonException",
throwables.get(0).getClass().getName());
}

/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,13 @@
*******************************************************************************/
package org.eclipse.osgi.tests.container.dummys;

import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
Expand Down Expand Up @@ -44,6 +48,8 @@ public class DummyContainerAdaptor extends ModuleContainerAdaptor {
private final DebugOptions debugOptions;
private final AtomicReference<CountDownLatch> startLatch = new AtomicReference<>();
private final AtomicReference<CountDownLatch> stopLatch = new AtomicReference<>();
private final Queue<String> traceMessages = new ConcurrentLinkedQueue<>();
private final Queue<Throwable> traceThrowables = new ConcurrentLinkedQueue<>();
private volatile Executor resolverExecutor;
private volatile ScheduledExecutorService timeoutExecutor;

Expand Down Expand Up @@ -170,4 +176,21 @@ public void setStopLatch(CountDownLatch stopLatch) {
this.stopLatch.set(stopLatch);
}

@Override
public void trace(String topic, String message) {
traceMessages.add(message);
}

@Override
public void traceThrowable(String topic, Throwable t) {
traceThrowables.add(t);
}

public List<String> getTraceMessages() {
return new ArrayList<>(traceMessages);
}

public List<Throwable> getTraceThrowables() {
return new ArrayList<>(traceThrowables);
}
}
4 changes: 0 additions & 4 deletions bundles/org.eclipse.osgi/.options
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,6 @@ org.eclipse.osgi/debug/loader/cds=false
org.eclipse.osgi/debug/events=false
# Prints out OSGi service debug information (registration/getting/ungetting etc.)
org.eclipse.osgi/debug/services=false
# Prints out bundle manifest parsing debug information
org.eclipse.osgi/debug/manifest=false
# Prints out LDAP filter debug information
org.eclipse.osgi/debug/filter=false
# Prints out security (PermissionAdmin service) debug information
org.eclipse.osgi/debug/security=false
# Prints out start level service debug information
Expand Down
2 changes: 1 addition & 1 deletion bundles/org.eclipse.osgi/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2
Export-Package: org.eclipse.core.runtime.adaptor;x-friends:="org.eclipse.core.runtime",
org.eclipse.core.runtime.internal.adaptor;x-internal:=true,
org.eclipse.equinox.log;version="1.1";uses:="org.osgi.framework,org.osgi.service.log",
org.eclipse.osgi.container;version="1.8.0";
org.eclipse.osgi.container;version="1.9.0";
uses:="org.eclipse.osgi.report.resolution,
org.osgi.framework.wiring,
org.eclipse.osgi.framework.eventmgr,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,31 @@
*******************************************************************************/
package org.eclipse.core.runtime.adaptor;

import java.io.*;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.net.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import org.eclipse.core.runtime.internal.adaptor.*;
import org.eclipse.core.runtime.internal.adaptor.ConsoleManager;
import org.eclipse.core.runtime.internal.adaptor.DefaultStartupMonitor;
import org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher;
import org.eclipse.osgi.container.Module;
import org.eclipse.osgi.container.ModuleRevision;
import org.eclipse.osgi.container.namespaces.EquinoxModuleDataNamespace;
Expand All @@ -44,7 +60,18 @@
import org.eclipse.osgi.storage.url.reference.Handler;
import org.eclipse.osgi.util.ManifestElement;
import org.eclipse.osgi.util.NLS;
import org.osgi.framework.*;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;
import org.osgi.framework.BundleException;
import org.osgi.framework.BundleListener;
import org.osgi.framework.Constants;
import org.osgi.framework.FrameworkEvent;
import org.osgi.framework.FrameworkListener;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
import org.osgi.framework.SynchronousBundleListener;
import org.osgi.framework.launch.Framework;
import org.osgi.framework.startlevel.BundleStartLevel;
import org.osgi.framework.startlevel.FrameworkStartLevel;
Expand Down Expand Up @@ -397,8 +424,9 @@ private static int getStartLevel() {
try {
return Integer.parseInt(level);
} catch (NumberFormatException e) {
if (debug)
if (debug) {
Debug.println("Start level = " + level + " parsed. Using hardcoded default: 6"); //$NON-NLS-1$ //$NON-NLS-2$
}
}
return DEFAULT_INITIAL_STARTLEVEL;
}
Expand Down Expand Up @@ -655,8 +683,9 @@ private static Bundle[] loadBasicBundles() throws InterruptedException {
Bundle[] lazyInitBundles = lazyActivationBundles.toArray(new Bundle[lazyActivationBundles.size()]);
startBundles(startInitBundles, lazyInitBundles);

if (debug)
if (debug) {
Debug.println("Time to load bundles: " + (System.currentTimeMillis() - startTime)); //$NON-NLS-1$
}
return startInitBundles;
}

Expand Down
Loading
Loading