diff --git a/src/uws/service/file/EventFrequency.java b/src/uws/service/file/EventFrequency.java index 98815e7a665bcfaaf1fc8d7a805983b41bb38953..a2c11f9a8e02192aa862d327057774815a7837f2 100644 --- a/src/uws/service/file/EventFrequency.java +++ b/src/uws/service/file/EventFrequency.java @@ -16,8 +16,8 @@ package uws.service.file; * You should have received a copy of the GNU Lesser General Public License * along with UWSLibrary. If not, see <http://www.gnu.org/licenses/>. * - * Copyright 2014 - UDS/Centre de Données astronomiques de Strasbourg (CDS), - * Astronomisches Rechen Institut (ARI) + * Copyright 2014-2015 - UDS/Centre de Données astronomiques de Strasbourg (CDS), + * Astronomisches Rechen Institut (ARI) */ import java.text.DateFormat; @@ -49,7 +49,7 @@ import java.util.regex.MatchResult; * <p><i><b>Warning:</b> * The frequency type is case sensitive! Then you should particularly pay attention at the case * when using the frequency types 'M' (monthly) and 'm' (every minute). - * </p> + * </i></p> * * <p> * Parsing errors are not thrown but "resolved" silently. The "solution" depends of the error. @@ -101,7 +101,7 @@ import java.util.regex.MatchResult; * * @author Marc Wenger (CDS) * @author Grégory Mantelet (ARI) - * @version 4.1 (09/2014) + * @version 4.1 (02/2015) * @since 4.1 */ public final class EventFrequency { @@ -151,7 +151,7 @@ public final class EventFrequency { * <p><i><b>Warning:</b> * The frequency type is case sensitive! Then you should particularly pay attention at the case * when using the frequency types 'M' (monthly) and 'm' (every minute). - * </p> + * </i></p> * * <p> * Parsing errors are not thrown but "resolved" silently. The "solution" depends of the error. @@ -195,7 +195,7 @@ public final class EventFrequency { if (interval == null) interval = ""; else{ - interval = interval.trim(); + interval = interval.replaceAll("[ \t]+", " ").trim(); p = interval.indexOf(' '); } diff --git a/src/uws/service/file/LocalUWSFileManager.java b/src/uws/service/file/LocalUWSFileManager.java index 633f7519d9c11d2d86165802225171eb81dc8d90..3ac55bd100686d39fa39a30fe0bc9b4265fa9f70 100644 --- a/src/uws/service/file/LocalUWSFileManager.java +++ b/src/uws/service/file/LocalUWSFileManager.java @@ -65,7 +65,7 @@ import uws.service.request.UploadFile; * <p> * A log file rotation is set by default so that avoiding a too big log file after several months/years of use. * By default the rotation is done every month on the 1st at 6am. This frequency can be changed easily thanks to the function - * {@link #setRotationFreq(String)}. + * {@link #setLogRotationFreq(String)}. * </p> * * @author Grégory Mantelet (CDS;ARI) @@ -88,7 +88,7 @@ public class LocalUWSFileManager implements UWSFileManager { protected PrintWriter logOutput = null; /** Frequency at which the log file must be "rotated" (the file is renamed with the date of its first write and a new log file is created). * Thus, too big log files can be avoided. */ - protected EventFrequency logRotation = new EventFrequency("M 1 06 00"); // Log file rotation every month on the 1st at 6am. + protected EventFrequency logRotation = new EventFrequency("D 0 0"); // Log file rotation every day at midnight. /** Indicate whether a directory must be used to gather all jobs, results and errors related to one identified user. * If FALSE, all jobs, results and errors will be in only one directory, whoever owns them. */ @@ -250,7 +250,7 @@ public class LocalUWSFileManager implements UWSFileManager { * * @return A human readable frequency of the log file rotation. */ - public final String getRotationFreq(){ + public final String getLogRotationFreq(){ return logRotation.toString(); } @@ -311,7 +311,7 @@ public class LocalUWSFileManager implements UWSFileManager { * * @param interval Interval between two log rotations. */ - public final void setRotationFreq(final String interval){ + public final void setLogRotationFreq(final String interval){ logRotation = new EventFrequency(interval); } diff --git a/src/uws/service/log/DefaultUWSLog.java b/src/uws/service/log/DefaultUWSLog.java index cfaadb47430a31511e131ec141376f6ff2593e17..f9ea297cf4d409912195e8cbdec6e80d4851ad69 100644 --- a/src/uws/service/log/DefaultUWSLog.java +++ b/src/uws/service/log/DefaultUWSLog.java @@ -16,7 +16,7 @@ package uws.service.log; * You should have received a copy of the GNU Lesser General Public License * along with UWSLibrary. If not, see <http://www.gnu.org/licenses/>. * - * Copyright 2012,2014 - UDS/Centre de Données astronomiques de Strasbourg (CDS), + * Copyright 2012-2015 - UDS/Centre de Données astronomiques de Strasbourg (CDS), * Astronomisches Rechen Institut (ARI) */ @@ -43,7 +43,7 @@ import uws.service.file.UWSFileManager; * <p>Default implementation of {@link UWSLog} interface which lets logging any message about a UWS.</p> * * @author Grégory Mantelet (CDS;ARI) - * @version 4.1 (09/2014) + * @version 4.1 (02/2015) */ public class DefaultUWSLog implements UWSLog { @@ -54,6 +54,18 @@ public class DefaultUWSLog implements UWSLog { protected final UWSFileManager fileManager; protected final PrintWriter defaultOutput; + /** <p>Minimum level that a message must have in order to be logged.</p> + * <p>The default behavior is the following:</p> + * <ul> + * <li><b>DEBUG</b>: every messages are logged.</li> + * <li><b>INFO</b>: every messages EXCEPT DEBUG are logged.</li> + * <li><b>WARNING</b>: every messages EXCEPT DEBUG and INFO are logged.</li> + * <li><b>ERROR</b>: only ERROR and FATAL messages are logged.</li> + * <li><b>FATAL</b>: only FATAL messages are logged.</li> + * </ul> + * @since 4.1 */ + protected LogLevel minLogLevel = LogLevel.DEBUG; + /** * <p>Builds a {@link UWSLog} which will use the file manager * of the given UWS to get the log output (see {@link UWSFileManager#getLogOutput(UWSLogType)}).</p> @@ -116,6 +128,51 @@ public class DefaultUWSLog implements UWSLog { defaultOutput = writer; } + /** + * <p>Get the minimum level that a message must have in order to be logged.</p> + * + * <p>The default behavior is the following:</p> + * <ul> + * <li><b>DEBUG</b>: every messages are logged.</li> + * <li><b>INFO</b>: every messages EXCEPT DEBUG are logged.</li> + * <li><b>WARNING</b>: every messages EXCEPT DEBUG and INFO are logged.</li> + * <li><b>ERROR</b>: only ERROR and FATAL messages are logged.</li> + * <li><b>FATAL</b>: only FATAL messages are logged.</li> + * </ul> + * + * @return The minimum log level. + * + * @since 4.1 + */ + public final LogLevel getMinLogLevel(){ + return minLogLevel; + } + + /** + * <p>Set the minimum level that a message must have in order to be logged.</p> + * + * <p>The default behavior is the following:</p> + * <ul> + * <li><b>DEBUG</b>: every messages are logged.</li> + * <li><b>INFO</b>: every messages EXCEPT DEBUG are logged.</li> + * <li><b>WARNING</b>: every messages EXCEPT DEBUG and INFO are logged.</li> + * <li><b>ERROR</b>: only ERROR and FATAL messages are logged.</li> + * <li><b>FATAL</b>: only FATAL messages are logged.</li> + * </ul> + * + * <p><i>Note: + * If the given level is NULL, this function has no effect. + * </i></p> + * + * @param newMinLevel The new minimum log level. + * + * @since 4.1 + */ + public final void setMinLogLevel(final LogLevel newMinLevel){ + if (newMinLevel != null) + minLogLevel = newMinLevel; + } + /** * Gets the date formatter/parser to use for any date read/write into this logger. * @return A date formatter/parser. @@ -163,6 +220,45 @@ public class DefaultUWSLog implements UWSLog { /* GENERAL LOGGING METHODS */ /* *********************** */ + /** + * <p>Tells whether a message with the given error level can be logged or not.</p> + * + * <p>In function of the minimum log level of this class, the default behavior is the following:</p> + * <ul> + * <li><b>DEBUG</b>: every messages are logged.</li> + * <li><b>INFO</b>: every messages EXCEPT DEBUG are logged.</li> + * <li><b>WARNING</b>: every messages EXCEPT DEBUG and INFO are logged.</li> + * <li><b>ERROR</b>: only ERROR and FATAL messages are logged.</li> + * <li><b>FATAL</b>: only FATAL messages are logged.</li> + * </ul> + * + * @param msgLevel Level of the message which has been asked to log. <i>Note: if NULL, it will be considered as DEBUG.</i> + * + * @return <i>true</i> if the message associated with the given log level can be logged, <i>false</i> otherwise. + * + * @since 4.1 + */ + protected boolean canLog(LogLevel msgLevel){ + // No level specified => DEBUG + if (msgLevel == null) + msgLevel = LogLevel.DEBUG; + + // Decide in function of the minimum log level set in this class: + switch(minLogLevel){ + case INFO: + return (msgLevel != LogLevel.DEBUG); + case WARNING: + return (msgLevel != LogLevel.DEBUG && msgLevel != LogLevel.INFO); + case ERROR: + return (msgLevel == LogLevel.ERROR || msgLevel == LogLevel.FATAL); + case FATAL: + return (msgLevel == LogLevel.FATAL); + case DEBUG: + default: + return true; + } + } + @Override public void log(LogLevel level, final String context, final String message, final Throwable error){ log(level, context, null, null, message, error); @@ -193,6 +289,10 @@ public class DefaultUWSLog implements UWSLog { if (level == null) level = (error != null) ? LogLevel.ERROR : LogLevel.INFO; + // Log or not? + if (!canLog(level)) + return; + StringBuffer buf = new StringBuffer(); // Print the date/time: buf.append(dateFormat.format(new Date())).append('\t'); @@ -296,9 +396,17 @@ public class DefaultUWSLog implements UWSLog { * @see uws.service.log.UWSLog#logHttp(uws.service.log.UWSLog.LogLevel, javax.servlet.http.HttpServletRequest, java.lang.String, java.lang.String, java.lang.Throwable) */ @Override - public void logHttp(final LogLevel level, final HttpServletRequest request, final String requestId, final String message, final Throwable error){ + public void logHttp(LogLevel level, final HttpServletRequest request, final String requestId, final String message, final Throwable error){ // IF A REQUEST IS PROVIDED, write its details after the message in a new column: if (request != null){ + // If the type is missing: + if (level == null) + level = (error != null) ? LogLevel.ERROR : LogLevel.INFO; + + // Log or not? + if (!canLog(level)) + return; + StringBuffer str = new StringBuffer(); // Write the message (if any): @@ -352,6 +460,14 @@ public class DefaultUWSLog implements UWSLog { @Override public void logHttp(LogLevel level, HttpServletResponse response, String requestId, JobOwner user, String message, Throwable error){ if (response != null){ + // If the type is missing: + if (level == null) + level = (error != null) ? LogLevel.ERROR : LogLevel.INFO; + + // Log or not? + if (!canLog(level)) + return; + StringBuffer str = new StringBuffer(); // Write the message (if any): @@ -390,6 +506,14 @@ public class DefaultUWSLog implements UWSLog { @Override public void logUWS(LogLevel level, Object obj, String event, String message, Throwable error){ + // If the type is missing: + if (level == null) + level = (error != null) ? LogLevel.ERROR : LogLevel.INFO; + + // Log or not? + if (!canLog(level)) + return; + // CASE "BACKUPED": Append to the message the backup report: if (event != null && event.equalsIgnoreCase("BACKUPED") && obj != null && obj.getClass().getName().equals("[I")){ int[] backupReport = (int[])obj; @@ -419,6 +543,14 @@ public class DefaultUWSLog implements UWSLog { @Override public void logThread(LogLevel level, Thread thread, String event, String message, Throwable error){ if (thread != null){ + // If the type is missing: + if (level == null) + level = (error != null) ? LogLevel.ERROR : LogLevel.INFO; + + // Log or not? + if (!canLog(level)) + return; + StringBuffer str = new StringBuffer(); // Write the message (if any): diff --git a/test/uws/service/file/TestLogRotation.java b/test/uws/service/file/TestLogRotation.java index 05f937bc3ae8d3c19929c4b9ec7f7d7d9c4bdcf1..b721d00fea953f9f04689a89172657ab2c7e1f58 100644 --- a/test/uws/service/file/TestLogRotation.java +++ b/test/uws/service/file/TestLogRotation.java @@ -56,6 +56,10 @@ public class TestLogRotation { freq = new EventFrequency("D 6 30"); assertEquals("daily at 06:30", freq.toString()); + // FREQ = "D 06 30" => ok! (with spaces and tabs inside) ; frequency = every day at 06:30 + freq = new EventFrequency("D 06 30"); + assertEquals("daily at 06:30", freq.toString()); + // FREQ = "D 24 30" => !!! ; frequency = every day at midnight freq = new EventFrequency("D 24 30"); assertEquals(DEFAULT_FREQ, freq.toString()); @@ -65,7 +69,7 @@ public class TestLogRotation { assertEquals(DEFAULT_FREQ, freq.toString()); // FREQ = "D 6 30 01 blabla" => ok! ; frequency = every day at 06:30 - freq = new EventFrequency("D 6 30"); + freq = new EventFrequency("D 6 30 01 blabla"); assertEquals("daily at 06:30", freq.toString()); // FREQ = "d 06 30" => !!! ; frequency = every day at midnight @@ -121,8 +125,12 @@ public class TestLogRotation { freq = new EventFrequency("W 2 6 30"); assertEquals("weekly on Monday at 06:30", freq.toString()); + // FREQ = "W 2 6 30" => ok! (with spaces and tabs inside) ; frequency = every week the Monday at 06:30 + freq = new EventFrequency("W 2 6 30"); + assertEquals("weekly on Monday at 06:30", freq.toString()); + // FREQ = "W 2 6 30 12 blabla" => ok! ; frequency = every week the Monday at 06:30 - freq = new EventFrequency("W 2 6 30"); + freq = new EventFrequency("W 2 6 30 12 blabla"); assertEquals("weekly on Monday at 06:30", freq.toString()); /* ***************************************** */ @@ -134,6 +142,10 @@ public class TestLogRotation { freq = new EventFrequency("M 2 06 30"); assertEquals("monthly on the 2nd at 06:30", freq.toString()); + // FREQ = "M 2 06 30" => ok! (with spaces and tabs inside) ; frequency = every month on the 2nd at 06:30 + freq = new EventFrequency("M 2 06 30"); + assertEquals("monthly on the 2nd at 06:30", freq.toString()); + // FREQ = "m 2 06 30" => !!! ; frequency = every minute freq = new EventFrequency("m 2 06 30"); assertEquals("every minute", freq.toString()); @@ -159,6 +171,10 @@ public class TestLogRotation { freq = new EventFrequency("h 10"); assertEquals("hourly at 10", freq.toString()); + // FREQ = "h 10" => ok! (with spaces and tabs inside) ; frequency = every hour at 10 + freq = new EventFrequency("h 10"); + assertEquals("hourly at 10", freq.toString()); + // FREQ = "H 10" => !!! ; frequency = every day at 00:00 freq = new EventFrequency("H 10"); assertEquals("daily at 00:00", freq.toString()); @@ -172,7 +188,7 @@ public class TestLogRotation { assertEquals("hourly at 00", freq.toString()); // FREQ = "h 10 12 blabla" => ok! ; frequency = every hour at 10 - freq = new EventFrequency("h 10"); + freq = new EventFrequency("h 10 12 blabla"); assertEquals("hourly at 10", freq.toString()); /* ********** */ @@ -185,7 +201,7 @@ public class TestLogRotation { assertEquals(DEFAULT_FREQ, freq.toString()); // FREQ = "m 10 blabla" => ok! ; frequency = every minute - freq = new EventFrequency("m"); + freq = new EventFrequency("m 10 blabla"); assertEquals(DEFAULT_FREQ, freq.toString()); // FREQ = "M" => !!! ; frequency = every month on the 1st at 00:00 diff --git a/test/uws/service/log/DefaultUWSLogTest.java b/test/uws/service/log/DefaultUWSLogTest.java new file mode 100644 index 0000000000000000000000000000000000000000..000823f149b36933fb40875e3c74d51ac0541f55 --- /dev/null +++ b/test/uws/service/log/DefaultUWSLogTest.java @@ -0,0 +1,63 @@ +package uws.service.log; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.io.ByteArrayOutputStream; +import java.io.OutputStream; + +import org.junit.Test; + +import uws.service.log.UWSLog.LogLevel; + +public class DefaultUWSLogTest { + + @Test + public void testCanLog(){ + OutputStream output = new ByteArrayOutputStream(); + DefaultUWSLog logger = new DefaultUWSLog(output); + + // Default value = DEBUG => ALL MESSAGES CAN BE LOGGED + assertEquals(LogLevel.DEBUG, logger.getMinLogLevel()); + for(LogLevel ll : LogLevel.values()) + assertTrue(logger.canLog(ll)); + + // Test: INFO => ALL EXCEPT DEBUG CAN BE LOGGED + logger.setMinLogLevel(LogLevel.INFO); + assertEquals(LogLevel.INFO, logger.getMinLogLevel()); + assertFalse(logger.canLog(LogLevel.DEBUG)); + assertTrue(logger.canLog(LogLevel.INFO)); + assertTrue(logger.canLog(LogLevel.WARNING)); + assertTrue(logger.canLog(LogLevel.ERROR)); + assertTrue(logger.canLog(LogLevel.FATAL)); + + // Test: WARNING => ALL EXCEPT DEBUG AND INFO CAN BE LOGGED + logger.setMinLogLevel(LogLevel.WARNING); + assertEquals(LogLevel.WARNING, logger.getMinLogLevel()); + assertFalse(logger.canLog(LogLevel.DEBUG)); + assertFalse(logger.canLog(LogLevel.INFO)); + assertTrue(logger.canLog(LogLevel.WARNING)); + assertTrue(logger.canLog(LogLevel.ERROR)); + assertTrue(logger.canLog(LogLevel.FATAL)); + + // Test: ERROR => ONLY ERROR AND FATAL CAN BE LOGGED + logger.setMinLogLevel(LogLevel.ERROR); + assertEquals(LogLevel.ERROR, logger.getMinLogLevel()); + assertFalse(logger.canLog(LogLevel.DEBUG)); + assertFalse(logger.canLog(LogLevel.INFO)); + assertFalse(logger.canLog(LogLevel.WARNING)); + assertTrue(logger.canLog(LogLevel.ERROR)); + assertTrue(logger.canLog(LogLevel.FATAL)); + + // Test: FATAL => ONLY FATAL CAN BE LOGGED + logger.setMinLogLevel(LogLevel.FATAL); + assertEquals(LogLevel.FATAL, logger.getMinLogLevel()); + assertFalse(logger.canLog(LogLevel.DEBUG)); + assertFalse(logger.canLog(LogLevel.INFO)); + assertFalse(logger.canLog(LogLevel.WARNING)); + assertFalse(logger.canLog(LogLevel.ERROR)); + assertTrue(logger.canLog(LogLevel.FATAL)); + } + +}