Commit 6fc94d89 authored by gmantele's avatar gmantele
Browse files

[UWS] Add a log message filter: only messages whose the level is greater or...

[UWS] Add a log message filter: only messages whose the level is greater or equal to a given one are displayed. This level is by default DEBUG (meaning all messages are always written).
parent 3f59de36
Loading
Loading
Loading
Loading
+6 −6
Original line number Diff line number Diff line
@@ -16,7 +16,7 @@ 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),
 * Copyright 2014-2015 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
 *                       Astronomisches Rechen Institut (ARI)
 */

@@ -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&eacute;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(' ');
		}

+4 −4
Original line number Diff line number Diff line
@@ -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&eacute;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);
	}

+135 −3
Original line number Diff line number Diff line
@@ -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&eacute;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):
+20 −4
Original line number Diff line number Diff line
@@ -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,10 +125,14 @@ public class TestLogRotation {
			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 = "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 12 blabla");
			assertEquals("weekly on Monday at 06:30", freq.toString());

			/* ***************************************** */
			/* MONTH EVENT (same code as for WEEK EVENT) */
			/* ***************************************** */
@@ -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
+63 −0
Original line number Diff line number Diff line
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));
	}

}