YARN-9606. Set sslfactory for AuthenticatedURL() while creating LogsCLI#webServiceClient. Contributed by Bilwa S T.

This commit is contained in:
Peter Bacsko 2021-09-23 13:58:56 +02:00
parent 80d2bda51c
commit 99d84b941b
6 changed files with 77 additions and 100 deletions

View File

@ -27,17 +27,13 @@ import com.sun.jersey.api.client.UniformInterfaceException;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.WebResource.Builder;
import com.sun.jersey.api.client.filter.ClientFilter;
import com.sun.jersey.client.urlconnection.HttpURLConnectionFactory;
import com.sun.jersey.client.urlconnection.URLConnectionClientHandler;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@ -68,8 +64,6 @@ import org.apache.hadoop.classification.InterfaceStability.Evolving;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.security.authentication.client.AuthenticatedURL;
import org.apache.hadoop.security.authentication.client.AuthenticationException;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.yarn.api.records.ApplicationAttemptReport;
import org.apache.hadoop.yarn.api.records.ApplicationId;
@ -89,6 +83,7 @@ import org.apache.hadoop.yarn.logaggregation.LogToolUtils;
import org.apache.hadoop.yarn.server.metrics.AppAttemptMetricsConstants;
import org.apache.hadoop.yarn.util.Apps;
import org.apache.hadoop.yarn.webapp.util.WebAppUtils;
import org.apache.hadoop.yarn.webapp.util.WebServiceClient;
import org.apache.hadoop.yarn.webapp.util.YarnWebServiceUtils;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONException;
@ -140,21 +135,7 @@ public class LogsCLI extends Configured implements Tool {
@Override
public int run(String[] args) throws Exception {
try {
webServiceClient = new Client(new URLConnectionClientHandler(
new HttpURLConnectionFactory() {
@Override
public HttpURLConnection getHttpURLConnection(URL url)
throws IOException {
AuthenticatedURL.Token token = new AuthenticatedURL.Token();
HttpURLConnection conn = null;
try {
conn = new AuthenticatedURL().openConnection(url, token);
} catch (AuthenticationException e) {
throw new IOException(e);
}
return conn;
}
}));
webServiceClient = WebServiceClient.getWebServiceClient().createClient();
return runCommand(args);
} finally {
if (yarnClient != null) {
@ -418,7 +399,9 @@ public class LogsCLI extends Configured implements Tool {
Configuration conf = new YarnConfiguration();
LogsCLI logDumper = new LogsCLI();
logDumper.setConf(conf);
WebServiceClient.initialize(conf);
int exitCode = logDumper.run(args);
WebServiceClient.destroy();
System.exit(exitCode);
}

View File

@ -89,8 +89,10 @@ import org.apache.hadoop.yarn.logaggregation.filecontroller.LogAggregationFileCo
import org.apache.hadoop.yarn.logaggregation.filecontroller.LogAggregationFileControllerContext;
import org.apache.hadoop.yarn.logaggregation.filecontroller.LogAggregationFileControllerFactory;
import org.apache.hadoop.yarn.logaggregation.filecontroller.ifile.LogAggregationIndexedFileController;
import org.apache.hadoop.yarn.webapp.util.WebServiceClient;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONObject;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
@ -109,8 +111,10 @@ public class TestLogsCLI {
ByteArrayOutputStream sysErrStream;
private PrintStream sysErr;
private Configuration conf;
@Before
public void setUp() {
public void setUp() throws Exception {
sysOutStream = new ByteArrayOutputStream();
sysOut = new PrintStream(sysOutStream);
System.setOut(sysOut);
@ -118,11 +122,17 @@ public class TestLogsCLI {
sysErrStream = new ByteArrayOutputStream();
sysErr = new PrintStream(sysErrStream);
System.setErr(sysErr);
conf = new YarnConfiguration();
WebServiceClient.initialize(conf);
}
@After
public void tearDown() {
WebServiceClient.destroy();
}
@Test(timeout = 5000l)
public void testFailResultCodes() throws Exception {
Configuration conf = new YarnConfiguration();
conf.setClass("fs.file.impl", LocalFileSystem.class, FileSystem.class);
LogCLIHelpers cliHelper = new LogCLIHelpers();
cliHelper.setConf(conf);
@ -145,7 +155,6 @@ public class TestLogsCLI {
@Test(timeout = 10000l)
public void testInvalidOpts() throws Exception {
Configuration conf = new YarnConfiguration();
YarnClient mockYarnClient = createMockYarnClient(
YarnApplicationState.FINISHED,
UserGroupInformation.getCurrentUser().getShortUserName());
@ -160,7 +169,6 @@ public class TestLogsCLI {
@Test(timeout = 5000l)
public void testInvalidApplicationId() throws Exception {
Configuration conf = new YarnConfiguration();
YarnClient mockYarnClient = createMockYarnClient(
YarnApplicationState.FINISHED,
UserGroupInformation.getCurrentUser().getShortUserName());
@ -174,7 +182,6 @@ public class TestLogsCLI {
@Test(timeout = 5000L)
public void testInvalidAMContainerId() throws Exception {
Configuration conf = new YarnConfiguration();
conf.setBoolean(YarnConfiguration.APPLICATION_HISTORY_ENABLED, true);
YarnClient mockYarnClient =
createMockYarnClient(YarnApplicationState.FINISHED,
@ -196,7 +203,6 @@ public class TestLogsCLI {
@Test
public void testAMContainerInfoFetchFromTimelineReader() throws Exception {
Configuration conf = new YarnConfiguration();
conf.setBoolean(YarnConfiguration.TIMELINE_SERVICE_ENABLED, true);
conf.set(YarnConfiguration.TIMELINE_SERVICE_VERSIONS, "2.0f");
YarnClient mockYarnClient =
@ -232,7 +238,6 @@ public class TestLogsCLI {
@Test(timeout = 5000l)
public void testUnknownApplicationId() throws Exception {
Configuration conf = new YarnConfiguration();
YarnClient mockYarnClient = createMockYarnClientUnknownApp();
LogsCLI cli = new LogsCLIForTest(mockYarnClient);
cli.setConf(conf);
@ -248,7 +253,6 @@ public class TestLogsCLI {
@Test (timeout = 10000)
public void testHelpMessage() throws Exception {
Configuration conf = new YarnConfiguration();
YarnClient mockYarnClient = createMockYarnClient(
YarnApplicationState.FINISHED,
UserGroupInformation.getCurrentUser().getShortUserName());
@ -372,13 +376,12 @@ public class TestLogsCLI {
@Test (timeout = 15000)
public void testFetchFinishedApplictionLogs() throws Exception {
String remoteLogRootDir = "target/logs/";
Configuration configuration = new YarnConfiguration();
configuration.setBoolean(YarnConfiguration.LOG_AGGREGATION_ENABLED, true);
configuration
conf.setBoolean(YarnConfiguration.LOG_AGGREGATION_ENABLED, true);
conf
.set(YarnConfiguration.NM_REMOTE_APP_LOG_DIR, remoteLogRootDir);
configuration.setBoolean(YarnConfiguration.YARN_ACL_ENABLE, true);
configuration.set(YarnConfiguration.YARN_ADMIN_ACL, "admin");
FileSystem fs = FileSystem.get(configuration);
conf.setBoolean(YarnConfiguration.YARN_ACL_ENABLE, true);
conf.set(YarnConfiguration.YARN_ADMIN_ACL, "admin");
FileSystem fs = FileSystem.get(conf);
UserGroupInformation ugi = UserGroupInformation.getCurrentUser();
ApplicationId appId = ApplicationId.newInstance(0, 1);
@ -431,15 +434,15 @@ public class TestLogsCLI {
// the first two logs is empty. When we try to read first two logs,
// we will meet EOF exception, but it will not impact other logs.
// Other logs should be read successfully.
uploadEmptyContainerLogIntoRemoteDir(ugi, configuration, rootLogDirs, nodeId,
uploadEmptyContainerLogIntoRemoteDir(ugi, conf, rootLogDirs, nodeId,
containerId0, path, fs);
uploadEmptyContainerLogIntoRemoteDir(ugi, configuration, rootLogDirs, nodeId,
uploadEmptyContainerLogIntoRemoteDir(ugi, conf, rootLogDirs, nodeId,
containerId1, path, fs);
uploadContainerLogIntoRemoteDir(ugi, configuration, rootLogDirs, nodeId,
uploadContainerLogIntoRemoteDir(ugi, conf, rootLogDirs, nodeId,
containerId1, path, fs);
uploadContainerLogIntoRemoteDir(ugi, configuration, rootLogDirs, nodeId,
uploadContainerLogIntoRemoteDir(ugi, conf, rootLogDirs, nodeId,
containerId2, path, fs);
uploadContainerLogIntoRemoteDir(ugi, configuration, rootLogDirs, nodeId,
uploadContainerLogIntoRemoteDir(ugi, conf, rootLogDirs, nodeId,
containerId3, path, fs);
YarnClient mockYarnClient =
@ -455,7 +458,7 @@ public class TestLogsCLI {
return mockReport;
}
};
cli.setConf(configuration);
cli.setConf(conf);
int exitCode = cli.run(new String[] { "-applicationId", appId.toString() });
LOG.info(sysOutStream.toString());
@ -723,7 +726,7 @@ public class TestLogsCLI {
YarnClient mockYarnClientWithException =
createMockYarnClientWithException();
cli = new LogsCLIForTest(mockYarnClientWithException);
cli.setConf(configuration);
cli.setConf(conf);
exitCode =
cli.run(new String[] { "-applicationId", appId.toString(),
@ -846,8 +849,7 @@ public class TestLogsCLI {
any(ContainerId.class));
// create local logs
Configuration configuration = new YarnConfiguration();
FileSystem fs = FileSystem.get(configuration);
FileSystem fs = FileSystem.get(conf);
String rootLogDir = "target/LocalLogs";
Path rootLogDirPath = new Path(rootLogDir);
if (fs.exists(rootLogDirPath)) {
@ -1006,13 +1008,12 @@ public class TestLogsCLI {
UserGroupInformation testUgi = UserGroupInformation
.createRemoteUser(testUser);
Configuration configuration = new YarnConfiguration();
configuration.setBoolean(YarnConfiguration.LOG_AGGREGATION_ENABLED, true);
configuration
conf.setBoolean(YarnConfiguration.LOG_AGGREGATION_ENABLED, true);
conf
.set(YarnConfiguration.NM_REMOTE_APP_LOG_DIR, remoteLogRootDir);
configuration.setBoolean(YarnConfiguration.YARN_ACL_ENABLE, true);
configuration.set(YarnConfiguration.YARN_ADMIN_ACL, "admin");
FileSystem fs = FileSystem.get(configuration);
conf.setBoolean(YarnConfiguration.YARN_ACL_ENABLE, true);
conf.set(YarnConfiguration.YARN_ADMIN_ACL, "admin");
FileSystem fs = FileSystem.get(conf);
ApplicationId appId = ApplicationId.newInstance(0, 1);
ApplicationAttemptId appAttemptId =
@ -1052,13 +1053,13 @@ public class TestLogsCLI {
assertTrue(fs.mkdirs(path));
// upload container logs for app into remote dir
uploadContainerLogIntoRemoteDir(testUgi, configuration, rootLogDirs,
uploadContainerLogIntoRemoteDir(testUgi, conf, rootLogDirs,
nodeId, containerId, path, fs);
YarnClient mockYarnClient = createMockYarnClient(
YarnApplicationState.FINISHED, testUgi.getShortUserName());
LogsCLI cli = new LogsCLIForTest(mockYarnClient);
cli.setConf(configuration);
cli.setConf(conf);
// Verify that we can get the application logs by specifying
// a correct appOwner
@ -1085,7 +1086,7 @@ public class TestLogsCLI {
// and can get app logs successfully.
YarnClient mockYarnClient2 = createMockYarnClientUnknownApp();
cli = new LogsCLIForTest(mockYarnClient2);
cli.setConf(configuration);
cli.setConf(conf);
exitCode = cli.run(new String[] {
"-applicationId", appId.toString()});
assertTrue(exitCode == 0);
@ -1099,7 +1100,7 @@ public class TestLogsCLI {
fs.delete(path, true);
}
assertTrue(fs.mkdirs(path));
uploadContainerLogIntoRemoteDir(testUgi, configuration, rootLogDirs,
uploadContainerLogIntoRemoteDir(testUgi, conf, rootLogDirs,
nodeId, containerId, path, fs);
exitCode = cli.run(new String[] {
@ -1154,14 +1155,13 @@ public class TestLogsCLI {
public void testLogsCLIWithInvalidArgs() throws Exception {
String localDir = "target/SaveLogs";
Path localPath = new Path(localDir);
Configuration configuration = new YarnConfiguration();
FileSystem fs = FileSystem.get(configuration);
FileSystem fs = FileSystem.get(conf);
ApplicationId appId = ApplicationId.newInstance(0, 1);
YarnClient mockYarnClient =
createMockYarnClient(YarnApplicationState.FINISHED,
UserGroupInformation.getCurrentUser().getShortUserName());
LogsCLI cli = new LogsCLIForTest(mockYarnClient);
cli.setConf(configuration);
cli.setConf(conf);
// Specify an invalid applicationId
int exitCode = cli.run(new String[] {"-applicationId",
@ -1222,7 +1222,6 @@ public class TestLogsCLI {
String remoteLogRootDir = "target/logs/";
String jobUser = "user1";
String loggedUser = "user2";
Configuration conf = new YarnConfiguration();
conf.setBoolean(YarnConfiguration.LOG_AGGREGATION_ENABLED, true);
conf.set(YarnConfiguration.NM_REMOTE_APP_LOG_DIR, remoteLogRootDir);
conf.setBoolean(YarnConfiguration.YARN_ACL_ENABLE, true);
@ -1268,7 +1267,6 @@ public class TestLogsCLI {
String remoteLogRootDir1 = "target/logs1/";
String jobUser = "user1";
String loggedUser = "user2";
Configuration conf = new YarnConfiguration();
conf.setBoolean(YarnConfiguration.LOG_AGGREGATION_ENABLED, true);
conf.set(YarnConfiguration.NM_REMOTE_APP_LOG_DIR, remoteLogRootDir);
String controllerName = "indexed";
@ -1303,14 +1301,13 @@ public class TestLogsCLI {
String localDir = "target/SaveLogs";
Path localPath = new Path(localDir);
Configuration configuration = new YarnConfiguration();
configuration.setBoolean(YarnConfiguration.LOG_AGGREGATION_ENABLED, true);
configuration
conf.setBoolean(YarnConfiguration.LOG_AGGREGATION_ENABLED, true);
conf
.set(YarnConfiguration.NM_REMOTE_APP_LOG_DIR, remoteLogRootDir);
configuration.setBoolean(YarnConfiguration.YARN_ACL_ENABLE, true);
configuration.set(YarnConfiguration.YARN_ADMIN_ACL, "admin");
conf.setBoolean(YarnConfiguration.YARN_ACL_ENABLE, true);
conf.set(YarnConfiguration.YARN_ADMIN_ACL, "admin");
FileSystem fs = FileSystem.get(configuration);
FileSystem fs = FileSystem.get(conf);
ApplicationId appId = ApplicationId.newInstance(0, 1);
ApplicationAttemptId appAttemptId =
ApplicationAttemptId.newInstance(appId, 1);
@ -1329,14 +1326,14 @@ public class TestLogsCLI {
nodeIds.add(nodeId2);
try {
createContainerLogs(configuration, remoteLogRootDir, rootLogDir, fs,
createContainerLogs(conf, remoteLogRootDir, rootLogDir, fs,
appId, containerIds, nodeIds);
YarnClient mockYarnClient =
createMockYarnClient(YarnApplicationState.FINISHED,
UserGroupInformation.getCurrentUser().getShortUserName());
LogsCLI cli = new LogsCLIForTest(mockYarnClient);
cli.setConf(configuration);
cli.setConf(conf);
int exitCode = cli.run(new String[] {"-applicationId",
appId.toString(),
"-out" , localPath.toString()});
@ -1394,13 +1391,12 @@ public class TestLogsCLI {
@Test (timeout = 15000)
public void testPrintContainerLogMetadata() throws Exception {
String remoteLogRootDir = "target/logs/";
Configuration configuration = new YarnConfiguration();
configuration.setBoolean(YarnConfiguration.LOG_AGGREGATION_ENABLED, true);
configuration
conf.setBoolean(YarnConfiguration.LOG_AGGREGATION_ENABLED, true);
conf
.set(YarnConfiguration.NM_REMOTE_APP_LOG_DIR, remoteLogRootDir);
configuration.setBoolean(YarnConfiguration.YARN_ACL_ENABLE, true);
configuration.set(YarnConfiguration.YARN_ADMIN_ACL, "admin");
FileSystem fs = FileSystem.get(configuration);
conf.setBoolean(YarnConfiguration.YARN_ACL_ENABLE, true);
conf.set(YarnConfiguration.YARN_ADMIN_ACL, "admin");
FileSystem fs = FileSystem.get(conf);
String rootLogDir = "target/LocalLogs";
ApplicationId appId = ApplicationId.newInstance(0, 1);
@ -1419,14 +1415,14 @@ public class TestLogsCLI {
nodeIds.add(nodeId);
nodeIds.add(nodeId);
createContainerLogs(configuration, remoteLogRootDir, rootLogDir, fs,
createContainerLogs(conf, remoteLogRootDir, rootLogDir, fs,
appId, containerIds, nodeIds);
YarnClient mockYarnClient =
createMockYarnClient(YarnApplicationState.FINISHED,
UserGroupInformation.getCurrentUser().getShortUserName());
LogsCLI cli = new LogsCLIForTest(mockYarnClient);
cli.setConf(configuration);
cli.setConf(conf);
cli.run(new String[] {"-applicationId", appId.toString(),
"-show_container_log_info"});
@ -1499,12 +1495,11 @@ public class TestLogsCLI {
@Test (timeout = 15000)
public void testListNodeInfo() throws Exception {
String remoteLogRootDir = "target/logs/";
Configuration configuration = new YarnConfiguration();
configuration.setBoolean(YarnConfiguration.LOG_AGGREGATION_ENABLED, true);
configuration
conf.setBoolean(YarnConfiguration.LOG_AGGREGATION_ENABLED, true);
conf
.set(YarnConfiguration.NM_REMOTE_APP_LOG_DIR, remoteLogRootDir);
configuration.setBoolean(YarnConfiguration.YARN_ACL_ENABLE, true);
configuration.set(YarnConfiguration.YARN_ADMIN_ACL, "admin");
conf.setBoolean(YarnConfiguration.YARN_ACL_ENABLE, true);
conf.set(YarnConfiguration.YARN_ADMIN_ACL, "admin");
ApplicationId appId = ApplicationId.newInstance(0, 1);
ApplicationAttemptId appAttemptId =
@ -1524,16 +1519,16 @@ public class TestLogsCLI {
nodeIds.add(nodeId2);
String rootLogDir = "target/LocalLogs";
FileSystem fs = FileSystem.get(configuration);
FileSystem fs = FileSystem.get(conf);
createContainerLogs(configuration, remoteLogRootDir, rootLogDir, fs,
createContainerLogs(conf, remoteLogRootDir, rootLogDir, fs,
appId, containerIds, nodeIds);
YarnClient mockYarnClient =
createMockYarnClient(YarnApplicationState.FINISHED,
UserGroupInformation.getCurrentUser().getShortUserName());
LogsCLI cli = new LogsCLIForTest(mockYarnClient);
cli.setConf(configuration);
cli.setConf(conf);
cli.run(new String[] { "-applicationId", appId.toString(),
"-list_nodes" });
@ -1550,13 +1545,12 @@ public class TestLogsCLI {
@Test (timeout = 15000)
public void testFetchApplictionLogsHar() throws Exception {
String remoteLogRootDir = "target/logs/";
Configuration configuration = new YarnConfiguration();
configuration.setBoolean(YarnConfiguration.LOG_AGGREGATION_ENABLED, true);
configuration
conf.setBoolean(YarnConfiguration.LOG_AGGREGATION_ENABLED, true);
conf
.set(YarnConfiguration.NM_REMOTE_APP_LOG_DIR, remoteLogRootDir);
configuration.setBoolean(YarnConfiguration.YARN_ACL_ENABLE, true);
configuration.set(YarnConfiguration.YARN_ADMIN_ACL, "admin");
FileSystem fs = FileSystem.get(configuration);
conf.setBoolean(YarnConfiguration.YARN_ACL_ENABLE, true);
conf.set(YarnConfiguration.YARN_ADMIN_ACL, "admin");
FileSystem fs = FileSystem.get(conf);
UserGroupInformation ugi = UserGroupInformation.getCurrentUser();
URL harUrl = ClassLoader.getSystemClassLoader()
.getResource("application_1440536969523_0001.har");
@ -1576,7 +1570,7 @@ public class TestLogsCLI {
createMockYarnClient(YarnApplicationState.FINISHED,
ugi.getShortUserName());
LogsCLI cli = new LogsCLIForTest(mockYarnClient);
cli.setConf(configuration);
cli.setConf(conf);
int exitCode = cli.run(new String[]{"-applicationId",
"application_1440536969523_0001"});
assertTrue(exitCode == 0);

View File

@ -15,7 +15,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.yarn.server.webapp;
package org.apache.hadoop.yarn.webapp.util;
import java.io.IOException;
import java.net.HttpURLConnection;
@ -46,8 +46,8 @@ public class WebServiceClient {
* Construct a new WebServiceClient based on the configuration. It will try to
* load SSL certificates when it is specified.
*
* @param conf Configuration object
* @throws Exception if creation of SSLFactory fails
* @param conf Configuration
* @throws Exception
*/
public static void initialize(Configuration conf) throws Exception {
if (instance == null) {
@ -75,8 +75,8 @@ public class WebServiceClient {
/**
* Start SSL factory.
*
* @param conf
* @return
* @param conf Configuration
* @return sslfactory object
* @throws Exception
*/
private static SSLFactory createSSLFactory(Configuration conf)

View File

@ -15,7 +15,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.yarn.server.webapp;
package org.apache.hadoop.yarn.webapp.util;
import java.io.File;
import java.net.HttpURLConnection;

View File

@ -36,11 +36,11 @@ import org.apache.hadoop.yarn.server.resourcemanager.webapp.RMWebAppUtil;
import org.apache.hadoop.yarn.server.router.clientrm.RouterClientRMService;
import org.apache.hadoop.yarn.server.router.rmadmin.RouterRMAdminService;
import org.apache.hadoop.yarn.server.router.webapp.RouterWebApp;
import org.apache.hadoop.yarn.server.webapp.WebServiceClient;
import org.apache.hadoop.yarn.webapp.WebApp;
import org.apache.hadoop.yarn.webapp.WebApps;
import org.apache.hadoop.yarn.webapp.WebApps.Builder;
import org.apache.hadoop.yarn.webapp.util.WebAppUtils;
import org.apache.hadoop.yarn.webapp.util.WebServiceClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

View File

@ -50,10 +50,10 @@ import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ClusterMetricsIn
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeInfo;
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodesInfo;
import org.apache.hadoop.yarn.server.uam.UnmanagedApplicationManager;
import org.apache.hadoop.yarn.server.webapp.WebServiceClient;
import org.apache.hadoop.yarn.webapp.BadRequestException;
import org.apache.hadoop.yarn.webapp.ForbiddenException;
import org.apache.hadoop.yarn.webapp.NotFoundException;
import org.apache.hadoop.yarn.webapp.util.WebServiceClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;