From e34753cd57cd73cc59f194816f188165eb4a0457 Mon Sep 17 00:00:00 2001 From: Ryan McKinley Date: Tue, 17 Apr 2012 18:12:09 +0000 Subject: [PATCH] SOLR-3358: Logging events are captured and available from the /admin/logging request handler. git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1327210 13f79535-47bb-0310-9956-ffa450edef68 --- dev-tools/eclipse/dot.classpath | 2 +- dev-tools/maven/solr/core/pom.xml.template | 6 + solr/CHANGES.txt | 5 +- solr/build.xml | 3 +- solr/core/ivy.xml | 1 + .../org/apache/solr/core/CoreContainer.java | 63 ++- .../solr/handler/admin/AdminHandlers.java | 5 +- .../solr/handler/admin/LogLevelHandler.java | 444 ------------------ .../solr/handler/admin/LoggingHandler.java | 152 ++++++ .../org/apache/solr/logging/CircularList.java | 154 ++++++ .../apache/solr/logging/ListenerConfig.java | 26 + .../org/apache/solr/logging/LogWatcher.java | 107 +++++ .../org/apache/solr/logging/LoggerInfo.java | 68 +++ .../org/apache/solr/logging/jul/JulInfo.java | 70 +++ .../apache/solr/logging/jul/JulWatcher.java | 169 +++++++ .../solr/logging/jul/RecordHandler.java | 47 ++ .../solr/logging/log4j/EventAppender.java | 48 ++ .../apache/solr/logging/log4j/Log4jInfo.java | 50 ++ .../solr/logging/log4j/Log4jWatcher.java | 162 +++++++ ...ndlerTest.java => LoggingHandlerTest.java} | 12 +- .../apache/solr/util/CircularListTest.java | 50 ++ solr/example/solr/solr.xml | 5 + solr/lib/log4j-1.2.16.jar.sha1 | 1 + solr/lib/log4j-LICENSE-ASL.txt | 202 ++++++++ solr/lib/log4j-NOTICE.txt | 5 + .../org/apache/solr/util/TestHarness.java | 7 +- solr/webapp/web/js/scripts/logging.js | 4 +- 27 files changed, 1408 insertions(+), 460 deletions(-) delete mode 100644 solr/core/src/java/org/apache/solr/handler/admin/LogLevelHandler.java create mode 100644 solr/core/src/java/org/apache/solr/handler/admin/LoggingHandler.java create mode 100644 solr/core/src/java/org/apache/solr/logging/CircularList.java create mode 100644 solr/core/src/java/org/apache/solr/logging/ListenerConfig.java create mode 100644 solr/core/src/java/org/apache/solr/logging/LogWatcher.java create mode 100644 solr/core/src/java/org/apache/solr/logging/LoggerInfo.java create mode 100644 solr/core/src/java/org/apache/solr/logging/jul/JulInfo.java create mode 100644 solr/core/src/java/org/apache/solr/logging/jul/JulWatcher.java create mode 100644 solr/core/src/java/org/apache/solr/logging/jul/RecordHandler.java create mode 100644 solr/core/src/java/org/apache/solr/logging/log4j/EventAppender.java create mode 100644 solr/core/src/java/org/apache/solr/logging/log4j/Log4jInfo.java create mode 100644 solr/core/src/java/org/apache/solr/logging/log4j/Log4jWatcher.java rename solr/core/src/test/org/apache/solr/handler/admin/{LogLevelHandlerTest.java => LoggingHandlerTest.java} (84%) create mode 100644 solr/core/src/test/org/apache/solr/util/CircularListTest.java create mode 100644 solr/lib/log4j-1.2.16.jar.sha1 create mode 100644 solr/lib/log4j-LICENSE-ASL.txt create mode 100644 solr/lib/log4j-NOTICE.txt diff --git a/dev-tools/eclipse/dot.classpath b/dev-tools/eclipse/dot.classpath index 6df57ffcc0c..734a70ae45e 100644 --- a/dev-tools/eclipse/dot.classpath +++ b/dev-tools/eclipse/dot.classpath @@ -110,8 +110,8 @@ + - diff --git a/dev-tools/maven/solr/core/pom.xml.template b/dev-tools/maven/solr/core/pom.xml.template index c6c416a62dc..c3273c98441 100644 --- a/dev-tools/maven/solr/core/pom.xml.template +++ b/dev-tools/maven/solr/core/pom.xml.template @@ -215,6 +215,12 @@ org.apache.httpcomponents httpmime + + log4j + log4j + 1.2.16 + provided + ${build-directory} diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt index c5112fd7337..5d73cf64509 100644 --- a/solr/CHANGES.txt +++ b/solr/CHANGES.txt @@ -204,7 +204,6 @@ New Features * SOLR-2134 Trie* fields should support sortMissingLast=true, and deprecate Sortable* Field Types (Ryan McKinley, Mike McCandless, Uwe Schindler, Erick Erickson) - * SOLR-2438 added MultiTermAwareComponent to the various classes to allow automatic lowercasing for multiterm queries (wildcards, regex, prefix, range, etc). You can now optionally specify a "multiterm" analyzer in our schema.xml, but Solr should "do the right thing" if you don't @@ -265,6 +264,10 @@ New Features * SOLR-3255: OpenExchangeRates.Org Exchange Rate Provider for CurrencyField (janhoy) +* SOLR-3358: Logging events are captured and available from the /admin/logging + request handler. (ryan) + + Optimizations ---------------------- diff --git a/solr/build.xml b/solr/build.xml index 0e55e92b57f..d15faa22d1c 100644 --- a/solr/build.xml +++ b/solr/build.xml @@ -317,6 +317,7 @@ + @@ -325,7 +326,7 @@ description="Creates a Solr WAR Distribution file, excluding slf4j bindings."> - + diff --git a/solr/core/ivy.xml b/solr/core/ivy.xml index afb6c17dd71..f4a5bcf0dd3 100644 --- a/solr/core/ivy.xml +++ b/solr/core/ivy.xml @@ -25,6 +25,7 @@ + diff --git a/solr/core/src/java/org/apache/solr/core/CoreContainer.java b/solr/core/src/java/org/apache/solr/core/CoreContainer.java index 02b906fa29b..1c140c0986a 100644 --- a/solr/core/src/java/org/apache/solr/core/CoreContainer.java +++ b/solr/core/src/java/org/apache/solr/core/CoreContainer.java @@ -65,11 +65,16 @@ import org.apache.solr.core.SolrXMLSerializer.SolrXMLDef; import org.apache.solr.handler.admin.CoreAdminHandler; import org.apache.solr.handler.component.HttpShardHandlerFactory; import org.apache.solr.handler.component.ShardHandlerFactory; +import org.apache.solr.logging.ListenerConfig; +import org.apache.solr.logging.LogWatcher; +import org.apache.solr.logging.jul.JulWatcher; +import org.apache.solr.logging.log4j.Log4jWatcher; import org.apache.solr.schema.IndexSchema; import org.apache.solr.update.SolrCoreState; import org.apache.zookeeper.KeeperException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.slf4j.impl.StaticLoggerBinder; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; @@ -114,7 +119,7 @@ public class CoreContainer private ZkController zkController; private SolrZkServer zkServer; private ShardHandlerFactory shardHandlerFactory; - + protected LogWatcher logging = null; private String zkHost; private Map coreToOrigName = new ConcurrentHashMap(); @@ -383,6 +388,55 @@ public class CoreContainer cfg.substituteProperties(); + // Initialize Logging + if(cfg.getBool("solr/logging/@enabled",true)) { + String slf4jImpl = null; + String fname = cfg.get("solr/logging/watcher/@class", null); + try { + slf4jImpl = StaticLoggerBinder.getSingleton().getLoggerFactoryClassStr(); + if(fname==null) { + if( slf4jImpl.indexOf("Log4j") > 0) { + fname = "Log4j"; + } + else if( slf4jImpl.indexOf("JDK") > 0) { + fname = "JUL"; + } + } + } + catch(Exception ex) { + log.warn("Unable to read SLF4J version", ex); + } + + // Now load the framework + if(fname!=null) { + if("JUL".equalsIgnoreCase(fname)) { + logging = new JulWatcher(slf4jImpl); + } + else if( "Log4j".equals(fname) ) { + logging = new Log4jWatcher(slf4jImpl); + } + else { + try { + logging = loader.newInstance(fname, LogWatcher.class); + } + catch (Exception e) { + throw new SolrException(ErrorCode.SERVER_ERROR, e); + } + } + + if( logging != null ) { + ListenerConfig v = new ListenerConfig(); + v.size = cfg.getInt("solr/logging/watcher/@size",50); + v.threshold = cfg.get("solr/logging/watcher/@threshold",null); + if(v.size>0) { + log.info("Registering Log Listener"); + logging.registerListener(v, this); + } + } + } + } + + String dcoreName = cfg.get("solr/cores/@defaultCoreName", null); if(dcoreName != null) { defaultCoreName = dcoreName; @@ -1022,6 +1076,13 @@ public class CoreContainer this.managementPath = path; } + public LogWatcher getLogging() { + return logging; + } + public void setLogging(LogWatcher v) { + logging = v; + } + public File getConfigFile() { return configFile; } diff --git a/solr/core/src/java/org/apache/solr/handler/admin/AdminHandlers.java b/solr/core/src/java/org/apache/solr/handler/admin/AdminHandlers.java index 802d2eb8b76..6ad01bc1a87 100644 --- a/solr/core/src/java/org/apache/solr/handler/admin/AdminHandlers.java +++ b/solr/core/src/java/org/apache/solr/handler/admin/AdminHandlers.java @@ -31,7 +31,6 @@ import org.apache.solr.util.plugin.SolrCoreAware; /** * A special Handler that registers all standard admin handlers * - * * @since solr 1.3 */ public class AdminHandlers implements SolrCoreAware, SolrRequestHandler @@ -86,7 +85,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( "logging", new LoggingHandler() ), new StandardHandler( "file", new ShowFileRequestHandler() ) }; @@ -95,7 +94,7 @@ public class AdminHandlers implements SolrCoreAware, SolrRequestHandler handler.handler.init( initArgs ); core.registerRequestHandler( path+handler.name, handler.handler ); if( handler.handler instanceof SolrCoreAware ) { - ((SolrCoreAware)handler).inform(core); + ((SolrCoreAware)handler.handler).inform(core); } } } diff --git a/solr/core/src/java/org/apache/solr/handler/admin/LogLevelHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/LogLevelHandler.java deleted file mode 100644 index c9653a8fd41..00000000000 --- a/solr/core/src/java/org/apache/solr/handler/admin/LogLevelHandler.java +++ /dev/null @@ -1,444 +0,0 @@ -/** - * 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.lang.reflect.Method; -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; -import org.slf4j.impl.StaticLoggerBinder; - - -/** - * 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 { - 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 getAllLevels(); - public void setLogLevel(String category, String level); - public Collection getLoggers(); - } - - - //------------------------------------------------------------------------------------------------- - // - // java.util.logging - // - //------------------------------------------------------------------------------------------------- - - - public static class LoggerFactoryWrapperJUL implements LoggerFactoryWrapper { - - @Override - public String getName() { - return "java.util.logging"; - } - - @Override - public List 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 getLoggers() { - LogManager manager = LogManager.getLogManager(); - - Logger root = manager.getLogger(""); - Map map = new HashMap(); - Enumeration 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; - } - Object level = logger.getLevel(); - if(level==null) { - return null; - } - return level.toString(); - } - - @Override - public String getName() { - return name; - } - - @Override - public boolean isSet() { - return (logger!=null && logger.getLevel()!=null); - } - } - - public static class LoggerFactoryWrapperLog4j implements LoggerFactoryWrapper { - - @Override - public String getName() { - return "log4j"; - } - - @Override - public List 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)) { - setLevelWithReflection(log,null); - } - else { - setLevelWithReflection(log,org.apache.log4j.Level.toLevel(level)); - } - } - - /** - * log.setLevel(level); - */ - private void setLevelWithReflection(org.apache.log4j.Logger log, org.apache.log4j.Level level) { - try { - Class logclass = Class.forName("org.apache.log4j.Logger"); - Class levelclass = Class.forName("org.apache.log4j.Level"); - Method method = logclass.getMethod("setLevel", levelclass); - method.invoke(log, level); - } - catch(Exception ex) { - throw new RuntimeException("Unable to set Log4j Level", ex); - } - } - - @Override - public Collection getLoggers() { - - org.apache.log4j.Logger root = org.apache.log4j.LogManager.getRootLogger(); - Map map = new HashMap(); - 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; - String slf4jImpl = null; - - @Override - public void init(NamedList args) { - String fname = (String)args.get("logger.factory"); - try { - slf4jImpl = StaticLoggerBinder.getSingleton().getLoggerFactoryClassStr(); - if(fname == null ) { - if( slf4jImpl.indexOf("Log4j") > 0) { - fname = "Log4j"; - } - else if( slf4jImpl.indexOf("JDK") > 0) { - fname = "JUL"; - } - else { - return; // unsuppored - } - } - } - catch(Exception ex) {} - - if("JUL".equalsIgnoreCase(fname)) { - factory = new LoggerFactoryWrapperJUL(); - } - else if( "Log4j".equals(fname) ) { - 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 { - // Don't do anything if the framework is unknown - if(factory==null) { - rsp.add("error", "Unsupported Logging Framework: "+slf4jImpl); - return; - } - - 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("slfj4", slf4jImpl); - rsp.add("levels", factory.getAllLevels()); - - List loggers = new ArrayList(factory.getLoggers()); - Collections.sort(loggers); - - List> info = new ArrayList>(); - 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 getSource() { - return "$URL$"; - } -} diff --git a/solr/core/src/java/org/apache/solr/handler/admin/LoggingHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/LoggingHandler.java new file mode 100644 index 00000000000..ee8332971b7 --- /dev/null +++ b/solr/core/src/java/org/apache/solr/handler/admin/LoggingHandler.java @@ -0,0 +1,152 @@ +/** + * 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.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.apache.solr.common.SolrDocumentList; +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.SimpleOrderedMap; +import org.apache.solr.core.SolrCore; +import org.apache.solr.handler.RequestHandlerBase; +import org.apache.solr.logging.LogWatcher; +import org.apache.solr.logging.LoggerInfo; +import org.apache.solr.request.SolrQueryRequest; +import org.apache.solr.response.SolrQueryResponse; +import org.apache.solr.util.plugin.SolrCoreAware; +import org.slf4j.LoggerFactory; + + +/** + * A request handler to show which loggers are registered and allows you to set them + * + * @since 4.0 + */ +public class LoggingHandler extends RequestHandlerBase implements SolrCoreAware { + static final org.slf4j.Logger log = LoggerFactory.getLogger(LoggingHandler.class); + + LogWatcher watcher = null; + + @Override + public void inform(SolrCore core) { + watcher = core.getCoreDescriptor().getCoreContainer().getLogging(); + } + + @Override + public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception { + // Don't do anything if the framework is unknown + if(watcher==null) { + rsp.add("error", "Logging Not Initalized"); + return; + } + rsp.add("watcher", watcher.getName()); + + SolrParams params = req.getParams(); + if(params.get("threshold")!=null) { + watcher.setThreshold(params.get("threshold")); + } + + // Write something at each level + if(params.get("test")!=null) { + log.trace("trace message"); + log.debug( "debug message"); + log.info("info (with exception)", new RuntimeException("test") ); + log.warn("warn (with exception)", new RuntimeException("test") ); + log.error("error (with exception)", new RuntimeException("test") ); + } + + 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]; + + watcher.setLogLevel(category, level); + } + } + + String since = req.getParams().get("since"); + if(since != null) { + long time = -1; + try { + time = Long.parseLong(since); + } + catch(Exception ex) { + throw new SolrException(ErrorCode.BAD_REQUEST, "invalid timestamp: "+since); + } + AtomicBoolean found = new AtomicBoolean(false); + SolrDocumentList docs = watcher.getHistory(time, found); + if(docs==null) { + rsp.add("error", "History not enabled"); + return; + } + else { + SimpleOrderedMap info = new SimpleOrderedMap(); + if(time>0) { + info.add("since", time); + info.add("found", found); + } + else { + info.add("levels", watcher.getAllLevels()); // show for the first request + } + info.add("last", watcher.getLastEvent()); + info.add("buffer", watcher.getHistorySize()); + info.add("threshold", watcher.getThreshold()); + + rsp.add("info", info); + rsp.add("history", docs); + } + } + else { + rsp.add("levels", watcher.getAllLevels()); + + List loggers = new ArrayList(watcher.getAllLoggers()); + Collections.sort(loggers); + + List> info = new ArrayList>(); + for(LoggerInfo wrap:loggers) { + info.add(wrap.getInfo()); + } + rsp.add("loggers", info); + } + rsp.setHttpCaching(false); + } + + // ////////////////////// SolrInfoMBeans methods ////////////////////// + + @Override + public String getDescription() { + return "Logging Handler"; + } + + @Override + public String getSource() { + return "$URL$"; + } +} \ No newline at end of file diff --git a/solr/core/src/java/org/apache/solr/logging/CircularList.java b/solr/core/src/java/org/apache/solr/logging/CircularList.java new file mode 100644 index 00000000000..7095d720986 --- /dev/null +++ b/solr/core/src/java/org/apache/solr/logging/CircularList.java @@ -0,0 +1,154 @@ +/** + * 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.logging; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * FIFO Circular List. + * + * Once the size is reached, it will overwrite previous entries + * + */ +public class CircularList implements Iterable +{ + private T[] data; + private int head=0; + private int tail=0; + private int size=0; + + @SuppressWarnings("unchecked") + public CircularList(int size) { + data = (T[])new Object[size]; + } + + @SuppressWarnings("unchecked") + public synchronized void resize(int newsize) { + if(newsize==this.size) return; + + T[] vals = (T[])new Object[newsize]; + int i = 0; + if(newsize>size) { + for(i=0; i= size || index < 0) + throw new IndexOutOfBoundsException("Index: "+index+", Size: "+size); + } + + public T get(int index) { + checkIndex(index); + return data[convert(index)]; + } + + public synchronized void add(T o) { + data[tail] = o; + tail = (tail+1)%data.length; + if( size == data.length ) { + head = (head+1)%data.length; + } + size++; + if( size > data.length ) { + size = data.length; + } + } + + public synchronized void clear() { + for( int i=0; i toList() + { + ArrayList list = new ArrayList( size ); + for( int i=0; i 0 ) { + str.append( "," ); + } + str.append( data[convert(i)] ); + } + str.append( "]" ); + return str.toString(); + } + + @Override + public Iterator iterator() { + return new Iterator() { + int idx = 0; + + @Override + public boolean hasNext() { + return idx { + + protected CircularList history; + protected long last = -1; + + /** + * @return The implementation name + */ + public abstract String getName(); + + /** + * @return The valid level names for this framework + */ + public abstract List getAllLevels(); + + /** + * Sets the log level within this framework + */ + public abstract void setLogLevel(String category, String level); + + /** + * @return all registered loggers + */ + public abstract Collection getAllLoggers(); + + public abstract void setThreshold(String level); + public abstract String getThreshold(); + + public void add(E event, long timstamp) { + history.add(event); + last = timstamp; + } + + public long getLastEvent() { + return last; + } + + public int getHistorySize() { + return (history==null) ? -1 : history.getBufferSize(); + } + + public SolrDocumentList getHistory(long since, AtomicBoolean found) { + if(history==null) { + return null; + } + + SolrDocumentList docs = new SolrDocumentList(); + Iterator iter = history.iterator(); + while(iter.hasNext()) { + E e = iter.next(); + long ts = getTimestamp(e); + if(ts == since) { + if(found!=null) { + found.set(true); + } + } + if(ts>since) { + docs.add(toSolrDocument(e)); + } + } + docs.setNumFound(docs.size()); // make it not look too funny + return docs; + } + + public abstract long getTimestamp(E event); + public abstract SolrDocument toSolrDocument(E event); + + public abstract void registerListener(ListenerConfig cfg, CoreContainer container); + + public void reset() { + history.clear(); + last = -1; + } +} \ No newline at end of file diff --git a/solr/core/src/java/org/apache/solr/logging/LoggerInfo.java b/solr/core/src/java/org/apache/solr/logging/LoggerInfo.java new file mode 100644 index 00000000000..08987bb8fe7 --- /dev/null +++ b/solr/core/src/java/org/apache/solr/logging/LoggerInfo.java @@ -0,0 +1,68 @@ +/** + * 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.logging; + +import org.apache.solr.common.util.SimpleOrderedMap; + +/** + * Wrapper class for Logger implementaions + */ +public abstract class LoggerInfo implements Comparable { + public static final String ROOT_NAME = "root"; + + protected final String name; + protected String level; + + public LoggerInfo(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(LoggerInfo 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); + } +} \ No newline at end of file diff --git a/solr/core/src/java/org/apache/solr/logging/jul/JulInfo.java b/solr/core/src/java/org/apache/solr/logging/jul/JulInfo.java new file mode 100644 index 00000000000..7ec22c6b80d --- /dev/null +++ b/solr/core/src/java/org/apache/solr/logging/jul/JulInfo.java @@ -0,0 +1,70 @@ +/** + * 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.logging.jul; + +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.apache.solr.logging.LoggerInfo; + +public class JulInfo extends LoggerInfo { + 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 JulInfo(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); + } +} \ No newline at end of file diff --git a/solr/core/src/java/org/apache/solr/logging/jul/JulWatcher.java b/solr/core/src/java/org/apache/solr/logging/jul/JulWatcher.java new file mode 100644 index 00000000000..de6adff6f5e --- /dev/null +++ b/solr/core/src/java/org/apache/solr/logging/jul/JulWatcher.java @@ -0,0 +1,169 @@ +/** + * 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.logging.jul; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Date; +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.LogRecord; +import java.util.logging.Logger; + +import org.apache.solr.common.SolrDocument; +import org.apache.solr.core.CoreContainer; +import org.apache.solr.logging.CircularList; +import org.apache.solr.logging.ListenerConfig; +import org.apache.solr.logging.LoggerInfo; +import org.apache.solr.logging.LogWatcher; + +import com.google.common.base.Throwables; + +public class JulWatcher extends LogWatcher { + + final String name; + RecordHandler handler = null; + + public JulWatcher(String name) { + this.name = name; + } + + @Override + public String getName() { + return "JUL ("+name+")"; + } + + + @Override + public List getAllLevels() { + return Arrays.asList( + Level.FINEST.getName(), + Level.FINER.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(LoggerInfo.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 getAllLoggers() { + LogManager manager = LogManager.getLogManager(); + + Logger root = manager.getLogger(""); + Map map = new HashMap(); + Enumeration names = manager.getLoggerNames(); + while (names.hasMoreElements()) { + String name = names.nextElement(); + Logger logger = Logger.getLogger(name); + if( logger == root) { + continue; + } + map.put(name, new JulInfo(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 JulInfo(name, null)); + } + } + } + map.put(LoggerInfo.ROOT_NAME, new JulInfo(LoggerInfo.ROOT_NAME, root)); + return map.values(); + } + + @Override + public void setThreshold(String level) { + if(handler==null) { + throw new IllegalStateException("Must have an handler"); + } + handler.setLevel( Level.parse(level) ); + } + + @Override + public String getThreshold() { + if(handler==null) { + throw new IllegalStateException("Must have an handler"); + } + return handler.getLevel().toString(); + } + + @Override + public void registerListener(ListenerConfig cfg, CoreContainer container) { + if(history!=null) { + throw new IllegalStateException("History already registered"); + } + history = new CircularList(cfg.size); + handler = new RecordHandler(this); + if(cfg.threshold != null) { + handler.setLevel(Level.parse(cfg.threshold)); + } + else { + handler.setLevel(Level.WARNING); + } + + Logger log = LogManager.getLogManager().getLogger(""); + log.addHandler(handler); + } + + @Override + public long getTimestamp(LogRecord event) { + return event.getMillis(); + } + + @Override + public SolrDocument toSolrDocument(LogRecord event) { + SolrDocument doc = new SolrDocument(); + doc.setField("time", new Date(event.getMillis())); + doc.setField("level", event.getLevel().toString()); + doc.setField("logger", event.getLoggerName()); + doc.setField("message", event.getMessage().toString()); + Throwable t = event.getThrown(); + if(t!=null) { + doc.setField("trace", Throwables.getStackTraceAsString(t)); + } + return doc; + } +} \ No newline at end of file diff --git a/solr/core/src/java/org/apache/solr/logging/jul/RecordHandler.java b/solr/core/src/java/org/apache/solr/logging/jul/RecordHandler.java new file mode 100644 index 00000000000..1067e200b52 --- /dev/null +++ b/solr/core/src/java/org/apache/solr/logging/jul/RecordHandler.java @@ -0,0 +1,47 @@ +/** + * 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.logging.jul; + + +import java.util.logging.LogRecord; + +import org.apache.solr.logging.LogWatcher; + +public final class RecordHandler extends java.util.logging.Handler { + final LogWatcher framework; + + public RecordHandler(LogWatcher framework) { + this.framework = framework; + } + + @Override + public void close() throws SecurityException { + //history.reset(); + } + + @Override + public void flush() { + // nothing + } + + @Override + public void publish(LogRecord r) { + if(isLoggable(r)) { + framework.add(r, r.getMillis()); + } + } +} \ No newline at end of file diff --git a/solr/core/src/java/org/apache/solr/logging/log4j/EventAppender.java b/solr/core/src/java/org/apache/solr/logging/log4j/EventAppender.java new file mode 100644 index 00000000000..90fbc8d642b --- /dev/null +++ b/solr/core/src/java/org/apache/solr/logging/log4j/EventAppender.java @@ -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.logging.log4j; + +import org.apache.log4j.AppenderSkeleton; +import org.apache.log4j.spi.LoggingEvent; + +import org.apache.solr.logging.LogWatcher; + + +public final class EventAppender extends AppenderSkeleton { + + final LogWatcher watcher; + + public EventAppender(LogWatcher framework) { + this.watcher = framework; + } + + @Override + public void append( LoggingEvent event ) + { + watcher.add(event,event.timeStamp); + } + + @Override + public void close() { + watcher.reset(); + } + + @Override + public boolean requiresLayout() { + return false; + } +} \ No newline at end of file diff --git a/solr/core/src/java/org/apache/solr/logging/log4j/Log4jInfo.java b/solr/core/src/java/org/apache/solr/logging/log4j/Log4jInfo.java new file mode 100644 index 00000000000..42cf7610415 --- /dev/null +++ b/solr/core/src/java/org/apache/solr/logging/log4j/Log4jInfo.java @@ -0,0 +1,50 @@ +/** + * 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.logging.log4j; + +import org.apache.solr.logging.LoggerInfo; + +public class Log4jInfo extends LoggerInfo { + final org.apache.log4j.Logger logger; + + public Log4jInfo(String name, org.apache.log4j.Logger logger) { + super(name); + this.logger = logger; + } + + @Override + public String getLevel() { + if(logger==null) { + return null; + } + Object level = logger.getLevel(); + if(level==null) { + return null; + } + return level.toString(); + } + + @Override + public String getName() { + return name; + } + + @Override + public boolean isSet() { + return (logger!=null && logger.getLevel()!=null); + } +} \ No newline at end of file diff --git a/solr/core/src/java/org/apache/solr/logging/log4j/Log4jWatcher.java b/solr/core/src/java/org/apache/solr/logging/log4j/Log4jWatcher.java new file mode 100644 index 00000000000..d7cd22e52be --- /dev/null +++ b/solr/core/src/java/org/apache/solr/logging/log4j/Log4jWatcher.java @@ -0,0 +1,162 @@ +/** + * 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.logging.log4j; + + +import java.util.Arrays; +import java.util.Collection; +import java.util.Date; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.log4j.AppenderSkeleton; +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.apache.log4j.spi.LoggingEvent; +import org.apache.log4j.spi.ThrowableInformation; +import org.apache.solr.common.SolrDocument; +import org.apache.solr.core.CoreContainer; +import org.apache.solr.logging.CircularList; +import org.apache.solr.logging.ListenerConfig; +import org.apache.solr.logging.LoggerInfo; +import org.apache.solr.logging.LogWatcher; + +import com.google.common.base.Throwables; + +public class Log4jWatcher extends LogWatcher { + + final String name; + AppenderSkeleton appender = null; + + public Log4jWatcher(String name) { + this.name = name; + } + + @Override + public String getName() { + return "Log4j ("+name+")"; + } + + @Override + public List 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(LoggerInfo.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 getAllLoggers() { + org.apache.log4j.Logger root = org.apache.log4j.LogManager.getRootLogger(); + Map map = new HashMap(); + 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 Log4jInfo(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 Log4jInfo(name, null)); + } + } + } + map.put(LoggerInfo.ROOT_NAME, new Log4jInfo(LoggerInfo.ROOT_NAME, root)); + return map.values(); + } + + @Override + public void setThreshold(String level) { + if(appender==null) { + throw new IllegalStateException("Must have an appender"); + } + appender.setThreshold(Level.toLevel(level)); + } + + @Override + public String getThreshold() { + if(appender==null) { + throw new IllegalStateException("Must have an appender"); + } + return appender.getThreshold().toString(); + } + + @Override + public void registerListener(ListenerConfig cfg, CoreContainer container) { + if(history!=null) { + throw new IllegalStateException("History already registered"); + } + history = new CircularList(cfg.size); + + appender = new EventAppender(this); + if(cfg.threshold != null) { + appender.setThreshold(Level.toLevel(cfg.threshold)); + } + else { + appender.setThreshold(Level.WARN); + } + Logger log = org.apache.log4j.LogManager.getRootLogger(); + log.addAppender(appender); + } + + @Override + public long getTimestamp(LoggingEvent event) { + return event.timeStamp; + } + + @Override + public SolrDocument toSolrDocument(LoggingEvent event) { + SolrDocument doc = new SolrDocument(); + doc.setField("time", new Date(event.getTimeStamp())); + doc.setField("level", event.getLevel().toString()); + doc.setField("logger", event.getLogger().getName()); + doc.setField("message", event.getMessage().toString()); + ThrowableInformation t = event.getThrowableInformation(); + if(t!=null) { + doc.setField("trace", Throwables.getStackTraceAsString(t.getThrowable())); + } + return doc; + } +} \ No newline at end of file diff --git a/solr/core/src/test/org/apache/solr/handler/admin/LogLevelHandlerTest.java b/solr/core/src/test/org/apache/solr/handler/admin/LoggingHandlerTest.java similarity index 84% rename from solr/core/src/test/org/apache/solr/handler/admin/LogLevelHandlerTest.java rename to solr/core/src/test/org/apache/solr/handler/admin/LoggingHandlerTest.java index c29837986c7..2f7f82a12dc 100644 --- a/solr/core/src/test/org/apache/solr/handler/admin/LogLevelHandlerTest.java +++ b/solr/core/src/test/org/apache/solr/handler/admin/LoggingHandlerTest.java @@ -17,15 +17,15 @@ package org.apache.solr.handler.admin; - import java.util.logging.Logger; import org.apache.solr.SolrTestCaseJ4; import org.apache.solr.common.params.CommonParams; +import org.apache.solr.logging.jul.JulInfo; import org.junit.BeforeClass; import org.junit.Test; -public class LogLevelHandlerTest extends SolrTestCaseJ4 { +public class LoggingHandlerTest extends SolrTestCaseJ4 { @BeforeClass public static void beforeClass() throws Exception { @@ -34,17 +34,17 @@ public class LogLevelHandlerTest extends SolrTestCaseJ4 { @Test public void testLogLevelHandlerOutput() throws Exception { - Logger log = Logger.getLogger("org.apache.solr.SolrTestCaseJ4"); - LogLevelHandler.LoggerWrapperJUL wrap = new LogLevelHandler.LoggerWrapperJUL(log.getName(), log); + Logger tst = Logger.getLogger("org.apache.solr.SolrTestCaseJ4"); + JulInfo wrap = new JulInfo(tst.getName(), tst); assertQ("Show Log Levels OK", - req(CommonParams.QT,"/admin/loglevel") + req(CommonParams.QT,"/admin/logging") ,"//arr[@name='loggers']/lst/str[.='"+wrap.getName()+"']/../str[@name='level'][.='"+wrap.getLevel()+"']" ,"//arr[@name='loggers']/lst/str[.='org.apache']/../null[@name='level']" ); assertQ("Set and remove a level", - req(CommonParams.QT,"/admin/loglevel", + req(CommonParams.QT,"/admin/logging", "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']" diff --git a/solr/core/src/test/org/apache/solr/util/CircularListTest.java b/solr/core/src/test/org/apache/solr/util/CircularListTest.java new file mode 100644 index 00000000000..c781ca86a3a --- /dev/null +++ b/solr/core/src/test/org/apache/solr/util/CircularListTest.java @@ -0,0 +1,50 @@ +/** + * 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.util; + +import java.io.IOException; + +import junit.framework.TestCase; + +import org.apache.solr.logging.CircularList; +import org.junit.Test; + +/** + * Test circular list + */ +public class CircularListTest extends TestCase { + + @Test + public void testCircularList() throws IOException { + CircularList list = new CircularList(10); + for(int i=0;i<10; i++) { + list.add(new Integer(i)); + } + assertEquals("within list", new Integer(0), list.get(0)); + for(int i=10;i<20; i++) { + list.add(new Integer(i)); + assertEquals("within list", new Integer(i-9), list.get(0)); + } + + // now try the resize + list.resize(5); + assertEquals(new Integer(15), list.get(0)); + list.resize(10); + assertEquals(new Integer(15), list.get(0)); + } +} diff --git a/solr/example/solr/solr.xml b/solr/example/solr/solr.xml index 55397716e94..bdd0417399b 100644 --- a/solr/example/solr/solr.xml +++ b/solr/example/solr/solr.xml @@ -33,6 +33,11 @@ sharedLib: path to a lib directory that will be shared across all cores --> +