From 162a8748037756f4a8204fff9bf6dc3a8b5979bb Mon Sep 17 00:00:00 2001
From: gmantele <gmantele@ari.uni-heidelberg.de>
Date: Fri, 15 Sep 2017 15:37:19 +0200
Subject: [PATCH] [UWS,TAP] Allow the specification of a custom logger in the
 configuration file.

This commit resolves partially the issue #28

Ideally, there should be an implementation of UWSLog and TAPLog working with
Log4j and another for SLF4J (and eventually for other logging mechanism).
Additionally, an implementation storing log messages in database would be
interesting. All these ideas may be implemented in UWSLib and TAPLib in a
future version.
---
 .../config/ConfigurableServiceConnection.java | 55 +++++++++++--------
 src/tap/config/TAPConfiguration.java          |  7 ++-
 src/tap/config/tap_configuration_file.html    | 26 ++++++++-
 src/tap/config/tap_full.properties            | 16 ++++++
 src/uws/config/ConfigurableUWSServlet.java    | 20 +++++--
 src/uws/config/UWSConfiguration.java          |  9 ++-
 src/uws/config/uws_configuration_file.html    | 24 ++++++++
 src/uws/config/uws_full.properties            | 23 +++++++-
 .../TestConfigurableServiceConnection.java    | 54 +++++++++++++++++-
 9 files changed, 199 insertions(+), 35 deletions(-)

diff --git a/src/tap/config/ConfigurableServiceConnection.java b/src/tap/config/ConfigurableServiceConnection.java
index 48d3db4..2071290 100644
--- a/src/tap/config/ConfigurableServiceConnection.java
+++ b/src/tap/config/ConfigurableServiceConnection.java
@@ -1,9 +1,29 @@
 package tap.config;
 
+/*
+ * This file is part of TAPLibrary.
+ * 
+ * TAPLibrary is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * TAPLibrary is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with TAPLibrary.  If not, see <http://www.gnu.org/licenses/>.
+ * 
+ * Copyright 2016-2017 - Astronomisches Rechen Institut (ARI)
+ */
+
 import static tap.config.TAPConfiguration.DEFAULT_ASYNC_FETCH_SIZE;
 import static tap.config.TAPConfiguration.DEFAULT_DIRECTORY_PER_USER;
 import static tap.config.TAPConfiguration.DEFAULT_EXECUTION_DURATION;
 import static tap.config.TAPConfiguration.DEFAULT_GROUP_USER_DIRECTORIES;
+import static tap.config.TAPConfiguration.DEFAULT_LOGGER;
 import static tap.config.TAPConfiguration.DEFAULT_MAX_ASYNC_JOBS;
 import static tap.config.TAPConfiguration.DEFAULT_RETENTION_PERIOD;
 import static tap.config.TAPConfiguration.DEFAULT_SYNC_FETCH_SIZE;
@@ -19,6 +39,7 @@ import static tap.config.TAPConfiguration.KEY_FILE_MANAGER;
 import static tap.config.TAPConfiguration.KEY_FILE_ROOT_PATH;
 import static tap.config.TAPConfiguration.KEY_GEOMETRIES;
 import static tap.config.TAPConfiguration.KEY_GROUP_USER_DIRECTORIES;
+import static tap.config.TAPConfiguration.KEY_LOGGER;
 import static tap.config.TAPConfiguration.KEY_LOG_ROTATION;
 import static tap.config.TAPConfiguration.KEY_MAX_ASYNC_JOBS;
 import static tap.config.TAPConfiguration.KEY_MAX_EXECUTION_DURATION;
@@ -69,25 +90,6 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Properties;
 
-/*
- * This file is part of TAPLibrary.
- * 
- * TAPLibrary is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * 
- * TAPLibrary is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public License
- * along with TAPLibrary.  If not, see <http://www.gnu.org/licenses/>.
- * 
- * Copyright 2016 - Astronomisches Rechen Institut (ARI)
- */
-
 import adql.db.FunctionDef;
 import adql.db.STCS;
 import adql.parser.ParseException;
@@ -125,7 +127,7 @@ import uws.service.log.UWSLog.LogLevel;
  * </p>
  * 
  * @author Gr&eacute;gory Mantelet (ARI)
- * @version 2.1 (09/2016)
+ * @version 2.1 (09/2017)
  * @since 2.0
  */
 public final class ConfigurableServiceConnection implements ServiceConnection {
@@ -354,15 +356,22 @@ public final class ConfigurableServiceConnection implements ServiceConnection {
 	 * Initialize the TAP logger with the given TAP configuration file.
 	 * 
 	 * @param tapConfig	The content of the TAP configuration file.
+	 * 
+	 * @throws TAPException	If no instance of the specified custom logger can
+	 *                     	be created.
 	 */
-	private void initLogger(final Properties tapConfig){
+	private void initLogger(final Properties tapConfig) throws TAPException{
 		// Create the logger:
-		logger = new DefaultTAPLog(fileManager);
+		String propValue = getProperty(tapConfig, KEY_LOGGER);
+		if (propValue == null || propValue.trim().equalsIgnoreCase(DEFAULT_LOGGER))
+			logger = new DefaultTAPLog(fileManager);
+		else
+			logger = newInstance(propValue, KEY_LOGGER, TAPLog.class, new Class<?>[]{UWSFileManager.class}, new Object[]{fileManager});
 
 		StringBuffer buf = new StringBuffer("Logger initialized");
 
 		// Set the minimum log level:
-		String propValue = getProperty(tapConfig, KEY_MIN_LOG_LEVEL);
+		propValue = getProperty(tapConfig, KEY_MIN_LOG_LEVEL);
 		if (propValue != null){
 			try{
 				((DefaultTAPLog)logger).setMinLogLevel(LogLevel.valueOf(propValue.toUpperCase()));
diff --git a/src/tap/config/TAPConfiguration.java b/src/tap/config/TAPConfiguration.java
index 00363ce..1f1b260 100644
--- a/src/tap/config/TAPConfiguration.java
+++ b/src/tap/config/TAPConfiguration.java
@@ -36,7 +36,7 @@ import tap.backup.DefaultTAPBackupManager;
  * and it must be used only thanks to its static classes and attributes.</i></p>
  *
  * @author Gr&eacute;gory Mantelet (ARI)
- * @version 2.1 (08/2017)
+ * @version 2.1 (09/2017)
  * @since 2.0
  */
 public final class TAPConfiguration {
@@ -80,6 +80,11 @@ public final class TAPConfiguration {
 	public final static int DEFAULT_RETENTION_PERIOD = 0;
 
 	/* LOG KEYS */
+	/** Name/Key of the property specifying the logger to use.
+	 * By default, {@link tap.log.DefaultTAPLog} is used. */
+	public final static String KEY_LOGGER = "logger";
+	/** Default value of the property {@link #KEY_LOGGER}: {@value #DEFAULT_LOGGER}. */
+	public final static String DEFAULT_LOGGER = "default";
 	/** Name/Key of the property specifying the minimum type of messages (i.e. DEBUG, INFO, WARNING, ERROR, FATAL)
 	 * that must be logged. By default all messages are logged...which is equivalent to set this property to "DEBUG". */
 	public final static String KEY_MIN_LOG_LEVEL = "min_log_level";
diff --git a/src/tap/config/tap_configuration_file.html b/src/tap/config/tap_configuration_file.html
index 1e7c61c..60d1015 100644
--- a/src/tap/config/tap_configuration_file.html
+++ b/src/tap/config/tap_configuration_file.html
@@ -400,13 +400,37 @@
 			</tr>
 			
 			<tr><td colspan="5">Log files</td></tr>
+			<tr class="optional">
+				<td class="done">logger</td>
+				<td></td>
+				<td>text</td>
+				<td>
+					<p>Only two possibilities are already implemented.</p>
+					<ul>
+						<li><b>default</b>: default logger provided by the
+							library. Any logged message will be appended in the
+							file 'service.log' inside the root directory of this
+							service (cf property <code>file_root_path</code>).
+						</li>
+						<li><b><em>{...}</em></b>: a custom logger. A class name MUST be
+							provided (between {...}). The specified class must
+							reference an implementation of tap.log.TAPLog. This
+							implementation must have at least one constructor
+							with a single parameter of type
+							uws.service.file.UWSFileManager.
+						</li>
+					</ul>
+	 				<p><em>Default: <code>default</code> (i.e. tap.log.DefaultTAPLog)</em></p>
+				</td>
+				<td><ul><li>default</li><li>{aPackage.MyLogger}</li></ul></td>
+			</tr>
 			<tr class="optional">
 				<td class="done">min_log_level</td>
 				<td></td>
 				<td>text</td>
 				<td>
 					<p>Minimum level that a message must have in order to be logged.</p>
-					<p>5 possible values:</p>p>
+					<p>5 possible values:</p>
 	 				<ul>
 	 					<li><b>DEBUG</b>: every messages are logged.</li>
 	 					<li><b>INFO</b>: every messages EXCEPT DEBUG are logged.</li>
diff --git a/src/tap/config/tap_full.properties b/src/tap/config/tap_full.properties
index 0784203..b900cc3 100644
--- a/src/tap/config/tap_full.properties
+++ b/src/tap/config/tap_full.properties
@@ -248,6 +248,22 @@ max_retention_period = 0
 # LOG FILES #
 #############
 
+# [OPTIONAL]
+# Logging method to use.
+# 
+# Only two possibilities are already implemented.
+#     * default: default logger provided by the library. Any logged message
+#                will be appended in the file 'service.log' inside the root
+#                directory of this service (cf property 'file_root_path').
+#     * {...}: a custom logger. A class name MUST be provided
+#              (between {...}). The specified class must reference
+#              an implementation of tap.log.TAPLog. This implementation
+#              must have at least one constructor with a single parameter of
+#              type uws.service.file.UWSFileManager.
+# 
+# Default: 'default' (i.e. tap.log.DefaultTAPLog)
+logger = 
+
 # [OPTIONAL]
 # Minimum level that a message must have in order to be logged.
 #
diff --git a/src/uws/config/ConfigurableUWSServlet.java b/src/uws/config/ConfigurableUWSServlet.java
index b317612..d449236 100644
--- a/src/uws/config/ConfigurableUWSServlet.java
+++ b/src/uws/config/ConfigurableUWSServlet.java
@@ -16,13 +16,14 @@ package uws.config;
  * 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 2016 - Astronomisches Rechen Institut (ARI)
+ * Copyright 2016-2017 - Astronomisches Rechen Institut (ARI)
  */
 
 import static uws.config.UWSConfiguration.DEFAULT_BACKUP_BY_USER;
 import static uws.config.UWSConfiguration.DEFAULT_BACKUP_FREQUENCY;
 import static uws.config.UWSConfiguration.DEFAULT_DIRECTORY_PER_USER;
 import static uws.config.UWSConfiguration.DEFAULT_GROUP_USER_DIRECTORIES;
+import static uws.config.UWSConfiguration.DEFAULT_LOGGER;
 import static uws.config.UWSConfiguration.DEFAULT_UWS_CONF_FILE;
 import static uws.config.UWSConfiguration.KEY_ADD_SERIALIZERS;
 import static uws.config.UWSConfiguration.KEY_ADD_UWS_ACTIONS;
@@ -38,6 +39,7 @@ import static uws.config.UWSConfiguration.KEY_GROUP_USER_DIRECTORIES;
 import static uws.config.UWSConfiguration.KEY_HOME_PAGE;
 import static uws.config.UWSConfiguration.KEY_HOME_PAGE_MIME_TYPE;
 import static uws.config.UWSConfiguration.KEY_JOB_LISTS;
+import static uws.config.UWSConfiguration.KEY_LOGGER;
 import static uws.config.UWSConfiguration.KEY_LOG_ROTATION;
 import static uws.config.UWSConfiguration.KEY_MAX_RUNNING_JOBS;
 import static uws.config.UWSConfiguration.KEY_MIN_LOG_LEVEL;
@@ -103,7 +105,7 @@ import uws.service.log.UWSLog.LogLevel;
  * </p>
  * 
  * @author Gr&eacute;gory Mantelet (ARI)
- * @version 4.2 (06/2016)
+ * @version 4.2 (09/2017)
  * @since 4.2
  */
 public class ConfigurableUWSServlet extends HttpServlet {
@@ -292,15 +294,23 @@ public class ConfigurableUWSServlet extends HttpServlet {
 	 * 
 	 * @param uwsConfig		The content of the UWS configuration file.
 	 * @param fileManager	The file manager to access the log file(s).
+	 * 
+	 * @throws UWSException	If no instance of the specified custom logger can
+	 *                     	be created.
 	 */
-	private UWSLog createLogger(final Properties uwsConfig, final UWSFileManager fileManager){
+	private UWSLog createLogger(final Properties uwsConfig, final UWSFileManager fileManager) throws UWSException{
 		// Create the logger:
-		UWSLog logger = new DefaultUWSLog(fileManager);
+		UWSLog logger;
+		String propValue = getProperty(uwsConfig, KEY_LOGGER);
+		if (propValue == null || propValue.trim().equalsIgnoreCase(DEFAULT_LOGGER))
+			logger = new DefaultUWSLog(fileManager);
+		else
+			logger = newInstance(propValue, KEY_LOGGER, UWSLog.class, new Class<?>[]{UWSFileManager.class}, new Object[]{fileManager});
 
 		StringBuffer buf = new StringBuffer("Logger initialized");
 
 		// Set the minimum log level:
-		String propValue = getProperty(uwsConfig, KEY_MIN_LOG_LEVEL);
+		propValue = getProperty(uwsConfig, KEY_MIN_LOG_LEVEL);
 		if (propValue != null){
 			try{
 				((DefaultUWSLog)logger).setMinLogLevel(LogLevel.valueOf(propValue.toUpperCase()));
diff --git a/src/uws/config/UWSConfiguration.java b/src/uws/config/UWSConfiguration.java
index 4112420..5814445 100644
--- a/src/uws/config/UWSConfiguration.java
+++ b/src/uws/config/UWSConfiguration.java
@@ -16,7 +16,7 @@ package uws.config;
  * 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 2016 - Astronomisches Rechen Institut (ARI)
+ * Copyright 2016-2017 - Astronomisches Rechen Institut (ARI)
  */
 
 import java.lang.reflect.Constructor;
@@ -39,7 +39,7 @@ import uws.service.request.UWSRequestParser;
  * and it must be used only thanks to its static classes and attributes.</i></p>
  * 
  * @author Gr&eacute;gory Mantelet (ARI)
- * @version 4.2 (06/2016)
+ * @version 4.2 (09/2017)
  * @since 4.2
  */
 public final class UWSConfiguration {
@@ -178,6 +178,11 @@ public final class UWSConfiguration {
 
 	/* LOG KEYS */
 
+	/** Name/Key of the property specifying the logger to use.
+	 * By default, {@link uws.service.log.DefaultUWSLog} is used. */
+	public final static String KEY_LOGGER = "logger";
+	/** Default value of the property {@link #KEY_LOGGER}: {@value #DEFAULT_LOGGER}. */
+	public final static String DEFAULT_LOGGER = "default";
 	/** Name/Key of the property specifying the minimum type of messages (i.e. DEBUG, INFO, WARNING, ERROR, FATAL)
 	 * that must be logged. By default all messages are logged...which is equivalent to set this property to "DEBUG". */
 	public final static String KEY_MIN_LOG_LEVEL = "min_log_level";
diff --git a/src/uws/config/uws_configuration_file.html b/src/uws/config/uws_configuration_file.html
index 3882d94..56f7f6c 100644
--- a/src/uws/config/uws_configuration_file.html
+++ b/src/uws/config/uws_configuration_file.html
@@ -419,6 +419,30 @@
 			</tr>
 			
 			<tr><td colspan="5">Log files</td></tr>
+			<tr class="optional">
+				<td class="todo">logger</td>
+				<td></td>
+				<td>text</td>
+				<td>
+					<p>Only two possibilities are already implemented.</p>
+					<ul>
+						<li><b>default</b>: default logger provided by the
+							library. Any logged message will be appended in the
+							file 'service.log' inside the root directory of this
+							service (cf property <code>file_root_path</code>).
+						</li>
+						<li><b><em>{...}</em></b>: a custom logger. A class name
+							MUST be provided (between {...}). The specified
+							class must reference an implementation of
+							uws.service.log.UWSLog. This implementation must
+							have at least one constructor with a single
+							parameter of type uws.service.file.UWSFileManager.
+						</li>
+					</ul>
+	 				<p><em>Default: <code>default</code> (i.e. uws.service.log.DefaultUWSLog)</em></p>
+				</td>
+				<td><ul><li>default</li><li>{aPackage.MyLogger}</li></ul></td>
+			</tr>
 			<tr class="optional">
 				<td class="todo">min_log_level</td>
 				<td></td>
diff --git a/src/uws/config/uws_full.properties b/src/uws/config/uws_full.properties
index c4f2c76..db107e7 100644
--- a/src/uws/config/uws_full.properties
+++ b/src/uws/config/uws_full.properties
@@ -327,6 +327,22 @@ group_user_dir = false
 # LOG FILES #
 #############
 
+# [OPTIONAL]
+# Logging method to use.
+# 
+# Only two possibilities are already implemented.
+#     * default: default logger provided by the library. Any logged message
+#                will be appended in the file 'service.log' inside the root
+#                directory of this service (cf property 'file_root_path').
+#     * {...}: a custom logger. A class name must be provided
+#              (between {...}). The specified class must reference
+#              an implementation of uws.service.log.UWSLog. This implementation
+#              must have at least one constructor with a single parameter of
+#              type uws.service.file.UWSFileManager.
+# 
+# Default: 'default' (i.e. uws.service.log.DefaultUWSLog)
+logger = 
+
 # [OPTIONAL]
 # Minimum level that a message must have in order to be logged.
 #
@@ -360,8 +376,11 @@ min_log_level =
 #          pay attention at the case when using the frequency types 'M'
 #          (monthly) and 'm' (every minute).
 # 
-# Note: this property is ignored if the file manager is not any more an
-#       extension of uws.service.file.LocalUWSFileManager.
+# Note 1: this property is ignored if the file manager is not any more an
+#         extension of uws.service.file.LocalUWSFileManager.
+# 
+# Note 2: this property may be ignored if the specified logger is not the
+#         default one (cf property 'logger').
 # 
 # Default: D 0 0 (daily at midnight)
 log_rotation = 
diff --git a/test/tap/config/TestConfigurableServiceConnection.java b/test/tap/config/TestConfigurableServiceConnection.java
index 38ddbd5..e0e3be4 100644
--- a/test/tap/config/TestConfigurableServiceConnection.java
+++ b/test/tap/config/TestConfigurableServiceConnection.java
@@ -7,6 +7,7 @@ import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static tap.config.TAPConfiguration.DEFAULT_ASYNC_FETCH_SIZE;
+import static tap.config.TAPConfiguration.DEFAULT_LOGGER;
 import static tap.config.TAPConfiguration.DEFAULT_MAX_ASYNC_JOBS;
 import static tap.config.TAPConfiguration.DEFAULT_SYNC_FETCH_SIZE;
 import static tap.config.TAPConfiguration.KEY_ASYNC_FETCH_SIZE;
@@ -14,6 +15,7 @@ import static tap.config.TAPConfiguration.KEY_COORD_SYS;
 import static tap.config.TAPConfiguration.KEY_DEFAULT_OUTPUT_LIMIT;
 import static tap.config.TAPConfiguration.KEY_FILE_MANAGER;
 import static tap.config.TAPConfiguration.KEY_GEOMETRIES;
+import static tap.config.TAPConfiguration.KEY_LOGGER;
 import static tap.config.TAPConfiguration.KEY_LOG_ROTATION;
 import static tap.config.TAPConfiguration.KEY_MAX_ASYNC_JOBS;
 import static tap.config.TAPConfiguration.KEY_MAX_OUTPUT_LIMIT;
@@ -67,6 +69,7 @@ import tap.db.JDBCConnection;
 import tap.db_testtools.DBTools;
 import tap.formatter.OutputFormat;
 import tap.formatter.VOTableFormat;
+import tap.log.DefaultTAPLog;
 import tap.metadata.TAPMetadata;
 import tap.metadata.TAPSchema;
 import uk.ac.starlink.votable.DataFormat;
@@ -77,6 +80,7 @@ import uws.job.user.JobOwner;
 import uws.service.UWSUrl;
 import uws.service.UserIdentifier;
 import uws.service.file.LocalUWSFileManager;
+import uws.service.file.UWSFileManager;
 import uws.service.log.DefaultUWSLog;
 import uws.service.log.UWSLog.LogLevel;
 
@@ -86,7 +90,8 @@ public class TestConfigurableServiceConnection {
 
 	private static Properties validProp, noFmProp, fmClassNameProp,
 			incorrectFmProp, correctLogProp, incorrectLogLevelProp,
-			incorrectLogRotationProp, xmlMetaProp,
+			incorrectLogRotationProp, customLoggerProp,
+			explicitDefaultLoggerProp, xmlMetaProp,
 			xmlMetaPropWithCustomMetaClass, xmlMetaPropWithBadCustomMetaClass,
 			xmlMetaPropWithANonMetaClass, wrongManualMetaProp, missingMetaProp,
 			missingMetaFileProp, wrongMetaProp, wrongMetaFileProp,
@@ -139,6 +144,12 @@ public class TestConfigurableServiceConnection {
 		incorrectLogRotationProp = (Properties)validProp.clone();
 		incorrectLogRotationProp.setProperty(KEY_LOG_ROTATION, "foo");
 
+		customLoggerProp = (Properties)validProp.clone();
+		customLoggerProp.setProperty(KEY_LOGGER, "{tap.config.TestConfigurableServiceConnection$CustomLogger}");
+
+		explicitDefaultLoggerProp = (Properties)validProp.clone();
+		explicitDefaultLoggerProp.setProperty(KEY_LOGGER, DEFAULT_LOGGER);
+
 		xmlMetaProp = (Properties)validProp.clone();
 		xmlMetaProp.setProperty(KEY_METADATA, VALUE_XML);
 		xmlMetaProp.setProperty(KEY_METADATA_FILE, XML_FILE);
@@ -543,6 +554,24 @@ public class TestConfigurableServiceConnection {
 			fail("This MUST have succeeded because the provided log level and log rotation are valid! \nCaught exception: " + getPertinentMessage(e));
 		}
 
+		// Explicit default logger:
+		try{
+			ServiceConnection connection = new ConfigurableServiceConnection(explicitDefaultLoggerProp);
+			assertNotNull(connection.getFileManager());
+			assertEquals(DefaultTAPLog.class, connection.getLogger().getClass());
+		}catch(Exception e){
+			fail("This MUST have succeeded because the value 'default' should be supported and should set the default TAP logger! \nCaught exception: " + getPertinentMessage(e));
+		}
+
+		// Custom logger:
+		try{
+			ServiceConnection connection = new ConfigurableServiceConnection(customLoggerProp);
+			assertNotNull(connection.getFileManager());
+			assertEquals(CustomLogger.class, connection.getLogger().getClass());
+		}catch(Exception e){
+			fail("This MUST have succeeded because the specified class implements TAPLog and has a constructor with a single parameter of type UWSFileManager! \nCaught exception: " + getPertinentMessage(e));
+		}
+
 		// Incorrect log level:
 		try{
 			ServiceConnection connection = new ConfigurableServiceConnection(incorrectLogLevelProp);
@@ -1324,4 +1353,27 @@ public class TestConfigurableServiceConnection {
 		}
 	}
 
+	/**
+	 * Custom TAPLog implementation.
+	 * 
+	 * <p><i>
+	 * 	Actually, for quick implementation, this class just extends
+	 * 	{@link DefaultTAPLog} (and so, implements TAPLog).
+	 * </i></p>
+	 * 
+	 * @author Gr&eacute;gory Mantelet (ARI)
+	 * @version 09/2017
+	 */
+	private static class CustomLogger extends DefaultTAPLog {
+		public CustomLogger(final UWSFileManager fm){
+			super(fm);
+		}
+
+		@Override
+		public void logTAP(LogLevel level, Object obj, String event, String message, Throwable error){
+			super.logTAP(level, obj, event, "[MY] " + message, error);
+		}
+
+	}
+
 }
-- 
GitLab