package aQute.bnd.testing; import java.util.ArrayList; import java.util.Formatter; import java.util.List; import java.util.Map; import java.util.regex.Pattern; import org.osgi.framework.Bundle; import org.osgi.framework.ServiceReference; import org.osgi.service.log.LogEntry; import org.osgi.service.log.LogService; import aQute.bnd.annotation.component.Activate; import aQute.bnd.annotation.component.Component; import aQute.bnd.annotation.metatype.Configurable; import aQute.bnd.testing.TestingLog.Config; /** * Provides a log service object to be used in testing. It can filter levels and * messages and can trace stack traces and directly output the diagnostic info. * At the end it can be checked if there were any messages logged that fell * within the set criteria. */ @Component(designate = Config.class) @SuppressWarnings("rawtypes") public class TestingLog implements LogService { boolean stacktrace; boolean direct; int level; long start = System.currentTimeMillis(); List<LogEntry> entries = new ArrayList<LogEntry>(); List<Pattern> filters = new ArrayList<Pattern>(); interface Config { boolean stacktrace(); boolean direct(); int level(); String[] filters(); } Config config; @Activate void activate(Map<String,Object> props) { config = Configurable.createConfigurable(Config.class, props); if (config.stacktrace()) stacktrace(); if (config.direct()) direct(); level(config.level()); if (config.filters() != null) { for (String pattern : config.filters()) filter(pattern); } } public void log(int level, String message) { log(null, level, message, null); } public void log(int level, String message, Throwable exception) { log(null, level, message, exception); } public void log(ServiceReference sr, int level, String message) { log(sr, level, message, null); } public synchronized void log(final ServiceReference sr, final int level, final String message, final Throwable exception) { if (exception != null && stacktrace) exception.printStackTrace(); if (level < this.level) return; for (Pattern p : filters) { if (p.matcher(message).find()) return; } final long now = System.currentTimeMillis(); LogEntry entry = new LogEntry() { public long getTime() { return now; } public ServiceReference getServiceReference() { return sr; } public String getMessage() { return message; } public int getLevel() { return level; } public Throwable getException() { return exception; } public Bundle getBundle() { return null; } public String toString() { StringBuilder sb = new StringBuilder(); try (Formatter f = new Formatter(sb)) { f.format("%6s %-4s %s %s", (now - start + 500) / 1000, (sr == null ? "" : sr.getProperty("service.id")), message, (exception == null ? "" : exception)); return sb.toString(); } } }; entries.add(entry); if (direct) System.out.println(entry); } public List<LogEntry> getEntries() { return entries; } public TestingLog filter(String pattern) { filters.add(Pattern.compile(pattern)); return this; } public TestingLog stacktrace() { stacktrace = true; return this; } public TestingLog direct() { direct = true; return this; } public TestingLog errors() { return level(LogService.LOG_ERROR); } public TestingLog warnings() { return level(LogService.LOG_WARNING); } public TestingLog infos() { return level(LogService.LOG_INFO); } public TestingLog debugs() { return level(LogService.LOG_DEBUG); } public TestingLog level(int level) { this.level = level; return this; } public TestingLog full() { stacktrace = true; direct = true; level = Integer.MIN_VALUE; return this; } public boolean check(String... patterns) { if (entries.isEmpty()) return true; int n = entries.size(); for (LogEntry le : entries) { for (String pattern : patterns) { if (le.getMessage().contains(pattern)) n--; else System.out.println(le); } } entries.clear(); return n != 0; } }