mirror of https://github.com/apache/lucene.git
SOLR-2459: Expose LogLevel selection with a RequestHandler rather then servlet
git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1292617 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
930816cc5b
commit
198c2a8b2d
|
@ -224,6 +224,9 @@ New Features
|
|||
* SOLR-3120: Optional post filtering for spatial queries bbox and geofilt
|
||||
for LatLonType. (yonik)
|
||||
|
||||
* SOLR-2459: Expose LogLevel selection with a RequestHandler rather then servlet
|
||||
(Stefan Matheis, Upayavira, ryan)
|
||||
|
||||
|
||||
Optimizations
|
||||
----------------------
|
||||
|
|
|
@ -86,6 +86,7 @@ public class AdminHandlers implements SolrCoreAware, SolrRequestHandler
|
|||
new StandardHandler( "plugins", new PluginInfoHandler() ),
|
||||
new StandardHandler( "threads", new ThreadDumpHandler() ),
|
||||
new StandardHandler( "properties", new PropertiesRequestHandler() ),
|
||||
new StandardHandler( "loglevel", new LogLevelHandler() ),
|
||||
new StandardHandler( "file", new ShowFileRequestHandler() )
|
||||
};
|
||||
|
||||
|
@ -113,7 +114,7 @@ public class AdminHandlers implements SolrCoreAware, SolrRequestHandler
|
|||
}
|
||||
|
||||
public String getVersion() {
|
||||
return "$Revision$";
|
||||
return "$Revision$";
|
||||
}
|
||||
|
||||
public String getSourceId() {
|
||||
|
|
|
@ -0,0 +1,417 @@
|
|||
/**
|
||||
* 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.solr.handler.admin;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.LogManager;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.apache.solr.common.SolrException;
|
||||
import org.apache.solr.common.SolrException.ErrorCode;
|
||||
import org.apache.solr.common.params.SolrParams;
|
||||
import org.apache.solr.common.util.NamedList;
|
||||
import org.apache.solr.common.util.SimpleOrderedMap;
|
||||
import org.apache.solr.handler.RequestHandlerBase;
|
||||
import org.apache.solr.request.SolrQueryRequest;
|
||||
import org.apache.solr.response.SolrQueryResponse;
|
||||
|
||||
|
||||
/**
|
||||
* A request handler to show which loggers are registered and allows you to set them
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
public class LogLevelHandler extends RequestHandlerBase {
|
||||
public static final String ROOT_NAME = "root";
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// Logger wrapper classes
|
||||
//
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
public abstract static class LoggerWrapper implements Comparable<LoggerWrapper> {
|
||||
protected final String name;
|
||||
protected String level;
|
||||
|
||||
public LoggerWrapper(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public abstract boolean isSet();
|
||||
|
||||
public SimpleOrderedMap<?> getInfo() {
|
||||
SimpleOrderedMap info = new SimpleOrderedMap();
|
||||
info.add("name", getName());
|
||||
info.add("level", getLevel());
|
||||
info.add("set", isSet());
|
||||
return info;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(LoggerWrapper other) {
|
||||
if (this.equals(other))
|
||||
return 0;
|
||||
|
||||
String tN = this.getName();
|
||||
String oN = other.getName();
|
||||
|
||||
if(ROOT_NAME.equals(tN))
|
||||
return -1;
|
||||
if(ROOT_NAME.equals(oN))
|
||||
return 1;
|
||||
|
||||
return tN.compareTo(oN);
|
||||
}
|
||||
}
|
||||
|
||||
public static interface LoggerFactoryWrapper {
|
||||
public String getName();
|
||||
public List<String> getAllLevels();
|
||||
public void setLogLevel(String category, String level);
|
||||
public Collection<LoggerWrapper> getLoggers();
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// java.util.logging
|
||||
//
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
public static class LoggerFactoryWrapperJUL implements LoggerFactoryWrapper {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "java.util.logging";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getAllLevels() {
|
||||
return Arrays.asList(
|
||||
Level.FINEST.getName(),
|
||||
Level.FINE.getName(),
|
||||
Level.CONFIG.getName(),
|
||||
Level.INFO.getName(),
|
||||
Level.WARNING.getName(),
|
||||
Level.SEVERE.getName(),
|
||||
Level.OFF.getName() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLogLevel(String category, String level) {
|
||||
if(ROOT_NAME.equals(category)) {
|
||||
category = "";
|
||||
}
|
||||
|
||||
Logger log = LogManager.getLogManager().getLogger(category);
|
||||
if(level==null||"unset".equals(level)||"null".equals(level)) {
|
||||
if(log!=null) {
|
||||
log.setLevel(null);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(log==null) {
|
||||
log = Logger.getLogger(category); // create it
|
||||
}
|
||||
log.setLevel(Level.parse(level));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<LoggerWrapper> getLoggers() {
|
||||
LogManager manager = LogManager.getLogManager();
|
||||
|
||||
Logger root = manager.getLogger("");
|
||||
Map<String,LoggerWrapper> map = new HashMap<String,LoggerWrapper>();
|
||||
Enumeration<String> names = manager.getLoggerNames();
|
||||
while (names.hasMoreElements()) {
|
||||
String name = names.nextElement();
|
||||
Logger logger = Logger.getLogger(name);
|
||||
if( logger == root) {
|
||||
continue;
|
||||
}
|
||||
map.put(name, new LoggerWrapperJUL(name, logger));
|
||||
|
||||
while (true) {
|
||||
int dot = name.lastIndexOf(".");
|
||||
if (dot < 0)
|
||||
break;
|
||||
name = name.substring(0, dot);
|
||||
if(!map.containsKey(name)) {
|
||||
map.put(name, new LoggerWrapperJUL(name, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
map.put(ROOT_NAME, new LoggerWrapperJUL(ROOT_NAME, root));
|
||||
return map.values();
|
||||
}
|
||||
}
|
||||
|
||||
public static class LoggerWrapperJUL extends LoggerWrapper {
|
||||
private static final Level[] LEVELS = {
|
||||
null, // aka unset
|
||||
Level.FINEST,
|
||||
Level.FINE,
|
||||
Level.CONFIG,
|
||||
Level.INFO,
|
||||
Level.WARNING,
|
||||
Level.SEVERE,
|
||||
Level.OFF
|
||||
// Level.ALL -- ignore. It is useless.
|
||||
};
|
||||
|
||||
final Logger logger;
|
||||
|
||||
public LoggerWrapperJUL(String name, Logger logger) {
|
||||
super(name);
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLevel() {
|
||||
if(logger==null) {
|
||||
return null;
|
||||
}
|
||||
Level level = logger.getLevel();
|
||||
if (level != null) {
|
||||
return level.getName();
|
||||
}
|
||||
for (Level l : LEVELS) {
|
||||
if (l == null) {
|
||||
// avoid NPE
|
||||
continue;
|
||||
}
|
||||
if (logger.isLoggable(l)) {
|
||||
// return first level loggable
|
||||
return l.getName();
|
||||
}
|
||||
}
|
||||
return Level.OFF.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSet() {
|
||||
return (logger!=null && logger.getLevel()!=null);
|
||||
}
|
||||
}
|
||||
|
||||
/****
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// Log4j
|
||||
//
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
public static class LoggerWrapperLog4j extends LoggerWrapper {
|
||||
final org.apache.log4j.Logger logger;
|
||||
|
||||
public LoggerWrapperLog4j(String name, org.apache.log4j.Logger logger) {
|
||||
super(name);
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLevel() {
|
||||
if(logger==null) {
|
||||
return null;
|
||||
}
|
||||
return logger.getLevel().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
public static class LoggerFactoryWrapperLog4j implements LoggerFactoryWrapper {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "log4j";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getAllLevels() {
|
||||
return Arrays.asList(
|
||||
org.apache.log4j.Level.ALL.toString(),
|
||||
org.apache.log4j.Level.TRACE.toString(),
|
||||
org.apache.log4j.Level.DEBUG.toString(),
|
||||
org.apache.log4j.Level.INFO.toString(),
|
||||
org.apache.log4j.Level.WARN.toString(),
|
||||
org.apache.log4j.Level.ERROR.toString(),
|
||||
org.apache.log4j.Level.FATAL.toString(),
|
||||
org.apache.log4j.Level.OFF.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLogLevel(String category, String level) {
|
||||
if(ROOT_NAME.equals(category)) {
|
||||
category = "";
|
||||
}
|
||||
org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(category);
|
||||
if(level==null||"unset".equals(level)||"null".equals(level)) {
|
||||
log.setLevel(null);
|
||||
}
|
||||
else {
|
||||
log.setLevel(org.apache.log4j.Level.toLevel(level));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<LoggerWrapper> getLoggers() {
|
||||
|
||||
org.apache.log4j.Logger root = org.apache.log4j.LogManager.getRootLogger();
|
||||
Map<String,LoggerWrapper> map = new HashMap<String,LoggerWrapper>();
|
||||
Enumeration<?> loggers = org.apache.log4j.LogManager.getCurrentLoggers();
|
||||
while (loggers.hasMoreElements()) {
|
||||
org.apache.log4j.Logger logger = (org.apache.log4j.Logger)loggers.nextElement();
|
||||
String name = logger.getName();
|
||||
if( logger == root) {
|
||||
continue;
|
||||
}
|
||||
map.put(name, new LoggerWrapperLog4j(name, logger));
|
||||
|
||||
while (true) {
|
||||
int dot = name.lastIndexOf(".");
|
||||
if (dot < 0)
|
||||
break;
|
||||
name = name.substring(0, dot);
|
||||
if(!map.containsKey(name)) {
|
||||
map.put(name, new LoggerWrapperJUL(name, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
map.put(ROOT_NAME, new LoggerWrapperLog4j(ROOT_NAME, root));
|
||||
return map.values();
|
||||
}
|
||||
}
|
||||
***/
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// The Request Handler
|
||||
//
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
LoggerFactoryWrapper factory;
|
||||
|
||||
@Override
|
||||
public void init(NamedList args) {
|
||||
String fname = (String)args.get("logger.factory");
|
||||
if(fname == null || "JUL".equalsIgnoreCase(fname)) {
|
||||
factory = new LoggerFactoryWrapperJUL();
|
||||
}
|
||||
else if( "Log4j".equals(fname) ) {
|
||||
throw new SolrException(ErrorCode.SERVER_ERROR, "Log4j not yet supported");
|
||||
// factory = new LoggerFactoryWrapperLog4j();
|
||||
}
|
||||
else {
|
||||
try {
|
||||
factory = (LoggerFactoryWrapper) Class.forName(fname).newInstance();
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new SolrException(ErrorCode.SERVER_ERROR, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception {
|
||||
SolrParams params = req.getParams();
|
||||
String[] set = params.getParams("set");
|
||||
if (set != null) {
|
||||
for (String pair : set) {
|
||||
String[] split = pair.split(":");
|
||||
if (split.length != 2) {
|
||||
throw new SolrException(
|
||||
SolrException.ErrorCode.SERVER_ERROR,
|
||||
"Invalid format, expected level:value, got " + pair);
|
||||
}
|
||||
String category = split[0];
|
||||
String level = split[1];
|
||||
|
||||
factory.setLogLevel(category, level);
|
||||
}
|
||||
}
|
||||
|
||||
rsp.add("framework", factory.getName());
|
||||
rsp.add("levels", factory.getAllLevels());
|
||||
|
||||
List<LoggerWrapper> loggers = new ArrayList<LogLevelHandler.LoggerWrapper>(factory.getLoggers());
|
||||
Collections.sort(loggers);
|
||||
|
||||
List<SimpleOrderedMap<?>> info = new ArrayList<SimpleOrderedMap<?>>();
|
||||
for(LoggerWrapper wrap:loggers) {
|
||||
info.add(wrap.getInfo());
|
||||
}
|
||||
rsp.add("loggers", info);
|
||||
rsp.setHttpCaching(false);
|
||||
}
|
||||
|
||||
// ////////////////////// SolrInfoMBeans methods //////////////////////
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Lucene Log Level info";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersion() {
|
||||
return "$Revision: 1079707 $";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSourceId() {
|
||||
return "$Id: LogLevelHandler.... $";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSource() {
|
||||
return "$URL: https://svn.apache.org/repos/asf/lucene/dev/trunk/solr/src/... $";
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL[] getDocs() {
|
||||
try {
|
||||
return new URL[] { new URL("http://wiki.apache.org/solr/LogLevelHandler") };
|
||||
} catch (MalformedURLException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/**
|
||||
* 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.solr.handler.admin;
|
||||
|
||||
|
||||
import org.apache.solr.SolrTestCaseJ4;
|
||||
import org.apache.solr.common.params.CommonParams;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
public class LogLevelHandlerTest extends SolrTestCaseJ4 {
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
initCore("solrconfig.xml", "schema.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLogLevelHandlerOutput() throws Exception {
|
||||
assertQ("Show Log Levels OK",
|
||||
req(CommonParams.QT,"/admin/loglevel")
|
||||
,"//arr[@name='loggers']/lst/str[.='global']/../str[@name='level'][.='INFO']"
|
||||
,"//arr[@name='loggers']/lst/str[.='org.apache']/../null[@name='level']"
|
||||
);
|
||||
|
||||
assertQ("Set and remove a level",
|
||||
req(CommonParams.QT,"/admin/loglevel",
|
||||
"set", "org.xxx.yyy.abc:null",
|
||||
"set", "org.xxx.yyy.zzz:FINEST")
|
||||
,"//arr[@name='loggers']/lst/str[.='org.xxx.yyy.zzz']/../str[@name='level'][.='FINEST']"
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue