Skip to content

Commit b5ab68a

Browse files
authored
Merge pull request #272 from scijava/log-revamp
Revamp the LogService
2 parents 501e2c8 + 10f74fd commit b5ab68a

20 files changed

+1262
-25
lines changed

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
</parent>
1111

1212
<artifactId>scijava-common</artifactId>
13-
<version>2.65.1-SNAPSHOT</version>
13+
<version>2.66.0-SNAPSHOT</version>
1414

1515
<name>SciJava Common</name>
1616
<description>SciJava Common is a shared library for SciJava software. It provides a plugin framework, with an extensible mechanism for service discovery, backed by its own annotation processor, so that plugins can be loaded dynamically. It is used by downstream projects in the SciJava ecosystem, such as ImageJ and SCIFIO.</description>
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* #%L
3+
* SciJava Common shared library for SciJava software.
4+
* %%
5+
* Copyright (C) 2009 - 2017 Board of Regents of the University of
6+
* Wisconsin-Madison, Broad Institute of MIT and Harvard, and Max Planck
7+
* Institute of Molecular Cell Biology and Genetics.
8+
* %%
9+
* Redistribution and use in source and binary forms, with or without
10+
* modification, are permitted provided that the following conditions are met:
11+
*
12+
* 1. Redistributions of source code must retain the above copyright notice,
13+
* this list of conditions and the following disclaimer.
14+
* 2. Redistributions in binary form must reproduce the above copyright notice,
15+
* this list of conditions and the following disclaimer in the documentation
16+
* and/or other materials provided with the distribution.
17+
*
18+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
22+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28+
* POSSIBILITY OF SUCH DAMAGE.
29+
* #L%
30+
*/
31+
32+
package org.scijava;
33+
34+
/**
35+
* Interface for event listeners.
36+
*
37+
* @author Curtis Rueden
38+
* @param <L> type of listener
39+
* @param <E> type of event
40+
*/
41+
public interface Listenable<L, E> {
42+
43+
/** Adds an item to the list of registered listeners. */
44+
void addListener(L listener);
45+
46+
/** Removes an item from the list of registered listeners. */
47+
void removeListener(L listener);
48+
49+
/** Informs the registered list of listeners that an event has occurred. */
50+
void notifyListeners(E event);
51+
}

src/main/java/org/scijava/console/ConsoleService.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
*/
5050
public interface ConsoleService extends
5151
HandlerService<LinkedList<String>, ConsoleArgument>, SciJavaService
52+
// TODO: SJC3: Extend Listenable<OutputListener, OutputEvent>
5253
{
5354

5455
/** Handles arguments from an external source such as the command line. */

src/main/java/org/scijava/log/AbstractLogService.java

Lines changed: 70 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
*
4444
* @author Johannes Schindelin
4545
* @author Curtis Rueden
46+
* @author Matthias Arzt
4647
*/
4748
@IgnoreAsCallingClass
4849
public abstract class AbstractLogService extends AbstractService implements
@@ -53,23 +54,54 @@ public abstract class AbstractLogService extends AbstractService implements
5354

5455
private final Map<String, Integer> classAndPackageLevels;
5556

57+
private final Logger rootLogger;
58+
5659
// -- constructor --
5760

5861
public AbstractLogService() {
5962
this(System.getProperties());
6063
}
6164

6265
public AbstractLogService(final Properties properties) {
66+
rootLogger = new RootLogger();
6367
// provide this constructor to enable unit tests
6468
final int level = LogLevel.value(properties.getProperty(
6569
LogService.LOG_LEVEL_PROPERTY));
6670
if (level >= 0) currentLevel = level;
6771
classAndPackageLevels = setupMapFromProperties(properties,
6872
LogService.LOG_LEVEL_PROPERTY + ":");
73+
initLogSourceLevels(properties);
74+
}
75+
76+
// -- AbstractLogService methods --
77+
78+
@Override
79+
public void setLevel(final int level) {
80+
currentLevel = level;
81+
}
82+
83+
@Override
84+
public void setLevel(final String classOrPackageName, final int level) {
85+
classAndPackageLevels.put(classOrPackageName, level);
86+
}
87+
88+
@Override
89+
public void setLevelForLogger(final String source, final int level) {
90+
rootLogger.getSource().subSource(source).setLogLevel(level);
6991
}
7092

7193
// -- Logger methods --
7294

95+
@Override
96+
public void alwaysLog(final int level, final Object msg, final Throwable t) {
97+
rootLogger.alwaysLog(level, msg, t);
98+
}
99+
100+
@Override
101+
public LogSource getSource() {
102+
return rootLogger.getSource();
103+
}
104+
73105
@Override
74106
public int getLevel() {
75107
if (classAndPackageLevels.isEmpty()) return currentLevel;
@@ -78,13 +110,25 @@ public int getLevel() {
78110
}
79111

80112
@Override
81-
public void setLevel(final int level) {
82-
currentLevel = level;
113+
public Logger subLogger(String name, int level) {
114+
return rootLogger.subLogger(name, level);
83115
}
84116

117+
// -- Listenable methods --
118+
85119
@Override
86-
public void setLevel(final String classOrPackageName, final int level) {
87-
classAndPackageLevels.put(classOrPackageName, level);
120+
public void addListener(final LogListener listener) {
121+
rootLogger.addListener(listener);
122+
}
123+
124+
@Override
125+
public void removeListener(final LogListener listener) {
126+
rootLogger.removeListener(listener);
127+
}
128+
129+
@Override
130+
public void notifyListeners(final LogMessage event) {
131+
rootLogger.notifyListeners(event);
88132
}
89133

90134
// -- Deprecated --
@@ -97,6 +141,12 @@ protected String getPrefix(final int level) {
97141

98142
// -- Helper methods --
99143

144+
private void initLogSourceLevels(Properties properties) {
145+
Map<String, Integer> nameLevels = setupMapFromProperties(properties,
146+
LOG_LEVEL_BY_SOURCE_PROPERTY + ":");
147+
nameLevels.forEach(this::setLevelForLogger);
148+
}
149+
100150
private int getLevelForClass(String classOrPackageName, int defaultLevel) {
101151
// check for a custom log level for calling class or its parent packages
102152
while (classOrPackageName != null) {
@@ -129,4 +179,20 @@ private Map<String, Integer> setupMapFromProperties(Properties properties,
129179
}
130180
return map;
131181
}
182+
183+
// -- Helper classes --
184+
185+
@IgnoreAsCallingClass
186+
private class RootLogger extends DefaultLogger {
187+
188+
public RootLogger() {
189+
super(AbstractLogService.this::notifyListeners, LogSource.newRoot(),
190+
LogLevel.NONE);
191+
}
192+
193+
@Override
194+
public int getLevel() {
195+
return AbstractLogService.this.getLevel();
196+
}
197+
}
132198
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/*
2+
* #%L
3+
* SciJava Common shared library for SciJava software.
4+
* %%
5+
* Copyright (C) 2009 - 2017 Board of Regents of the University of
6+
* Wisconsin-Madison, Broad Institute of MIT and Harvard, and Max Planck
7+
* Institute of Molecular Cell Biology and Genetics.
8+
* %%
9+
* Redistribution and use in source and binary forms, with or without
10+
* modification, are permitted provided that the following conditions are met:
11+
*
12+
* 1. Redistributions of source code must retain the above copyright notice,
13+
* this list of conditions and the following disclaimer.
14+
* 2. Redistributions in binary form must reproduce the above copyright notice,
15+
* this list of conditions and the following disclaimer in the documentation
16+
* and/or other materials provided with the distribution.
17+
*
18+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
22+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28+
* POSSIBILITY OF SUCH DAMAGE.
29+
* #L%
30+
*/
31+
32+
package org.scijava.log;
33+
34+
import java.util.List;
35+
import java.util.concurrent.CopyOnWriteArrayList;
36+
37+
/**
38+
* Default implementation of {@link Logger}.
39+
*
40+
* @author Matthias Arzt
41+
* @author Curtis Rueden
42+
*/
43+
@IgnoreAsCallingClass
44+
public class DefaultLogger implements Logger, LogListener {
45+
46+
private final LogListener destination;
47+
48+
private final LogSource source;
49+
50+
private final int level;
51+
52+
private final List<LogListener> listeners = new CopyOnWriteArrayList<>();
53+
54+
public DefaultLogger(final LogListener destination,
55+
final LogSource source, final int level)
56+
{
57+
this.destination = destination;
58+
this.source = source;
59+
this.level = level;
60+
}
61+
62+
// -- Logger methods --
63+
64+
@Override
65+
public LogSource getSource() {
66+
return source;
67+
}
68+
69+
@Override
70+
public int getLevel() {
71+
return level;
72+
}
73+
74+
@Override
75+
public void alwaysLog(final int level, final Object msg, final Throwable t) {
76+
messageLogged(new LogMessage(source, level, msg, t));
77+
}
78+
79+
public Logger subLogger(final String name, final int level) {
80+
LogSource source = getSource().subSource(name);
81+
int actualLevel = source.hasLogLevel() ? source.logLevel() : level;
82+
return new DefaultLogger(this, source, actualLevel);
83+
}
84+
85+
// -- Listenable methods --
86+
87+
@Override
88+
public void addListener(final LogListener listener) {
89+
listeners.add(listener);
90+
}
91+
92+
@Override
93+
public void removeListener(final LogListener listener) {
94+
listeners.remove(listener);
95+
}
96+
97+
@Override
98+
public void notifyListeners(final LogMessage message) {
99+
for (LogListener listener : listeners)
100+
listener.messageLogged(message);
101+
}
102+
103+
// -- LogListener methods --
104+
105+
@Override
106+
public void messageLogged(final LogMessage message) {
107+
notifyListeners(message);
108+
destination.messageLogged(message);
109+
}
110+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* #%L
3+
* SciJava Common shared library for SciJava software.
4+
* %%
5+
* Copyright (C) 2009 - 2017 Board of Regents of the University of
6+
* Wisconsin-Madison, Broad Institute of MIT and Harvard, and Max Planck
7+
* Institute of Molecular Cell Biology and Genetics.
8+
* %%
9+
* Redistribution and use in source and binary forms, with or without
10+
* modification, are permitted provided that the following conditions are met:
11+
*
12+
* 1. Redistributions of source code must retain the above copyright notice,
13+
* this list of conditions and the following disclaimer.
14+
* 2. Redistributions in binary form must reproduce the above copyright notice,
15+
* this list of conditions and the following disclaimer in the documentation
16+
* and/or other materials provided with the distribution.
17+
*
18+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
22+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28+
* POSSIBILITY OF SUCH DAMAGE.
29+
* #L%
30+
*/
31+
32+
package org.scijava.log;
33+
34+
/**
35+
* Callback function used by {@link Logger}.
36+
*
37+
* @author Matthias Arzt
38+
* @see Logger
39+
* @see LogMessage
40+
*/
41+
public interface LogListener {
42+
43+
/**
44+
* This method is normally called from many threads in parallel. It must be
45+
* implemented highly thread safe and must not use any kind of locks.
46+
*/
47+
void messageLogged(LogMessage message);
48+
49+
}

0 commit comments

Comments
 (0)