Repository: sentry Updated Branches: refs/heads/master ebb94b189 -> a41a1447b
SENTRY-1853: Add the log level access mechanism (Donghui Xu, reviewed by Alex Kolbasov) Project: http://git-wip-us.apache.org/repos/asf/sentry/repo Commit: http://git-wip-us.apache.org/repos/asf/sentry/commit/a41a1447 Tree: http://git-wip-us.apache.org/repos/asf/sentry/tree/a41a1447 Diff: http://git-wip-us.apache.org/repos/asf/sentry/diff/a41a1447 Branch: refs/heads/master Commit: a41a1447b206abe2129a1656faf7d28e2b9d4176 Parents: ebb94b1 Author: Alexander Kolbasov <[email protected]> Authored: Wed Aug 23 13:53:22 2017 -0700 Committer: Alexander Kolbasov <[email protected]> Committed: Wed Aug 23 13:53:22 2017 -0700 ---------------------------------------------------------------------- .../db/service/thrift/LogLevelServlet.java | 122 +++++++++++++++++++ .../db/service/thrift/SentryWebServer.java | 7 +- .../thrift/TestSentryServerLogLevel.java | 100 +++++++++++++++ 3 files changed, 226 insertions(+), 3 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/sentry/blob/a41a1447/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/LogLevelServlet.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/LogLevelServlet.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/LogLevelServlet.java new file mode 100644 index 0000000..fce41a8 --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/LogLevelServlet.java @@ -0,0 +1,122 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.sentry.provider.db.service.thrift; + +import org.apache.log4j.Level; +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; + +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PrintWriter; + +import static org.apache.commons.lang.StringEscapeUtils.escapeHtml; + +public class LogLevelServlet extends HttpServlet { + private static final String LF = "\n"; + private static final String BR = "<br />"; + private static final String B_BR = "<b>%s</b><br />"; + private static final String FORMS_HEAD = + "<h1>" + "Log Level" + "</h1>" + + LF + BR + "<hr /><h3>Results</h3>" + + LF + " Submitted Log Name: " + B_BR; + private static final String FORMS_CONTENT_GET = + LF + " Effective level: " + B_BR; + private static final String FORMS_CONTENT_SET = + LF + " Submitted Level: " + B_BR + + LF + " Setting Level to %s" + BR + + LF + " Effective level: " + B_BR; + private static final String FORMS_END = + LF + BR + "<hr /><h3>Get / Set</h3>" + + LF + "<form>Log: <input type='text' size='50' name='log' /> " + + "<input type='submit' value='Get Log Level' />" + "</form>" + + LF + "<form>Log: <input type='text' size='50' name='log' /> " + + "Level: <input type='text' name='level' /> " + + "<input type='submit' value='Set Log Level' />" + "</form>"; + private static final String FORMS_GET = FORMS_HEAD + FORMS_CONTENT_GET; + private static final String FORMS_SET = FORMS_HEAD + FORMS_CONTENT_SET; + + /** + * Return parameter on servlet request for the given name + * + * @param request: Servlet request + * @param name: Name of parameter in servlet request + * @return Parameter in servlet request for the given name, return null if can't find parameter. + */ + private String getParameter(ServletRequest request, String name) { + String s = request.getParameter(name); + if (s == null) { + return null; + } + s = s.trim(); + return s.length() == 0 ? null : s; + } + + /** + * Check the validity of the log level. + * @param level: The log level to be checked + * @return + * true: The log level is valid + * false: The log level is invalid + */ + private boolean isLogLevelValid(String level) { + return level.equals(Level.toLevel(level).toString()); + } + + /** + * Parse the class name and log level in the http servlet request. + * If the request contains only class name, return the log level in the response message. + * If the request contains both class name and level, set the log level to the requested level + * and return the setting result in the response message. + */ + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + String logName = getParameter(request, "log"); + String level = getParameter(request, "level"); + response.setContentType("text/html;charset=utf-8"); + response.setStatus(HttpServletResponse.SC_OK); + PrintWriter out = response.getWriter(); + + if (logName != null) { + Logger logInstance = LogManager.getLogger(logName); + if (level == null) { + out.write(String.format(FORMS_GET, + escapeHtml(logName), + logInstance.getEffectiveLevel().toString())); + } else if (isLogLevelValid(level)) { + logInstance.setLevel(Level.toLevel(level)); + out.write(String.format(FORMS_SET, + escapeHtml(logName), + level, + level, + logInstance.getEffectiveLevel().toString())); + } else { + response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid log level: " + level); + return; + } + } + out.write(FORMS_END); + out.close(); + response.flushBuffer(); + } +} http://git-wip-us.apache.org/repos/asf/sentry/blob/a41a1447/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/SentryWebServer.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/SentryWebServer.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/SentryWebServer.java index 01f3a0d..84324c3 100644 --- a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/SentryWebServer.java +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/SentryWebServer.java @@ -104,6 +104,8 @@ public class SentryWebServer { servletContextHandler.getServletContext() .setAttribute(ConfServlet.CONF_CONTEXT_ATTRIBUTE, conf); + servletContextHandler.addServlet(new ServletHolder(LogLevelServlet.class), "/admin/logLevel"); + ResourceHandler resourceHandler = new ResourceHandler(); resourceHandler.setDirectoriesListed(true); URL url = this.getClass().getResource(RESOURCE_DIR); @@ -121,7 +123,7 @@ public class SentryWebServer { String authMethod = conf.get(ServerConfig.SENTRY_WEB_SECURITY_TYPE); if (!ServerConfig.SENTRY_WEB_SECURITY_TYPE_NONE.equals(authMethod)) { - /** + /* * SentryAuthFilter is a subclass of AuthenticationFilter and * AuthenticationFilter tagged as private and unstable interface: * While there are not guarantees that this interface will not change, @@ -182,8 +184,7 @@ public class SentryWebServer { throw new IllegalArgumentException("Can't use Kerberos authentication, principal [" + principal + "] keytab [" + keytabFile + "]", ex); } - LOGGER.info("Using Kerberos authentication, principal [" - + principal + "] keytab [" + keytabFile + "]"); + LOGGER.info("Using Kerberos authentication, principal [{}] keytab [{}]", principal, keytabFile); } } } http://git-wip-us.apache.org/repos/asf/sentry/blob/a41a1447/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/thrift/TestSentryServerLogLevel.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/thrift/TestSentryServerLogLevel.java b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/thrift/TestSentryServerLogLevel.java new file mode 100644 index 0000000..9e4e0a9 --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/thrift/TestSentryServerLogLevel.java @@ -0,0 +1,100 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.sentry.provider.db.service.thrift; + +import org.apache.commons.io.IOUtils; +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; +import org.apache.sentry.service.thrift.SentryServiceIntegrationBase; +import org.junit.*; + +import java.net.HttpURLConnection; +import java.net.URL; + +public class TestSentryServerLogLevel extends SentryServiceIntegrationBase { + private final String CLASS_NAME = "org.eclipse.jetty.server.handler.ContextHandler"; + + @BeforeClass + public static void setup() throws Exception { + webServerEnabled = true; + webSecurity = false; + SentryServiceIntegrationBase.setup(); + } + + @Override + @Before + public void before() throws Exception { + } + + @Override + @After + public void after() { + } + + /** + * Get the log level for the specified class + * @param className: Name of class + * @return + * Log level of the class + */ + private String getLogLevel(String className) { + Logger logInstance = LogManager.getLogger(className); + return logInstance.getEffectiveLevel().toString(); + } + + /** + * Send log level and class name via the HTTP interface and verify that it is set at the loogger. + * @throws Exception + */ + @Test + public void testSetLogLevel() throws Exception { + final URL url = new URL("http://"+ SERVER_HOST + ":" + webServerPort + "/admin/logLevel?log=" + + CLASS_NAME + "&level=INFO"); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + Assert.assertEquals(HttpURLConnection.HTTP_OK, conn.getResponseCode()); + String response = IOUtils.toString(conn.getInputStream()); + Assert.assertTrue(response.contains("INFO")); + Assert.assertEquals("INFO", getLogLevel(CLASS_NAME)); + } + + /** + * Send class name via the HTTP interface and verify that it is get at the loogger. + * @throws Exception + */ + @Test + public void testGetLogLevel() throws Exception { + final URL url = new URL("http://"+ SERVER_HOST + ":" + webServerPort + "/admin/logLevel?log=" + CLASS_NAME); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + Assert.assertEquals(HttpURLConnection.HTTP_OK, conn.getResponseCode()); + String response = IOUtils.toString(conn.getInputStream()); + Assert.assertTrue(response.contains("INFO")); + Assert.assertEquals("INFO", getLogLevel(CLASS_NAME)); + } + + /** + * Send class name and invalid log level via the HTTP interface and verify that it returns error response. + * @throws Exception + */ + @Test + public void testInvalidLogLevel() throws Exception { + final URL url = new URL("http://"+ SERVER_HOST + ":" + webServerPort + "/admin/logLevel?log=" + + CLASS_NAME + "&level=ABCD"); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + Assert.assertEquals(HttpURLConnection.HTTP_BAD_REQUEST, conn.getResponseCode()); + } +}
