--- /dev/null
+/*
+ * 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.catalina.ant;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Ant task that implements the <code>/findleaks</code> command, supported by
+ * the Tomcat manager application.
+ */
+public class FindLeaksTask extends AbstractCatalinaTask {
+
+ private boolean statusLine = true;
+
+ /**
+ * Sets the statusLine parameter that controls if the response includes a
+ * status line or not.
+ */
+ public void setStatusLine(boolean statusLine) {
+ this.statusLine = statusLine;
+ }
+
+ /**
+ * Returns the statusLine parameter that controls if the response includes a
+ * status line or not.
+ */
+ public boolean getStatusLine() {
+ return statusLine;
+ }
+
+ /**
+ * Execute the requested operation.
+ *
+ * @exception BuildException if an error occurs
+ */
+ @Override
+ public void execute() throws BuildException {
+
+ super.execute();
+ execute("/findleaks?statusLine=" + Boolean.toString(statusLine));
+ }
+
+}
StringWriter stringWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(stringWriter);
- super.findleaks(printWriter, smClient);
+ super.findleaks(false, printWriter, smClient);
- if (stringWriter.getBuffer().length() > 0) {
- msg.append(smClient.getString("htmlManagerServlet.findleaksList"));
- msg.append(stringWriter.toString());
+ String writerText = stringWriter.toString();
+
+ if (writerText.length() > 0) {
+ if (!writerText.startsWith("FAIL -")) {
+ msg.append(smClient.getString(
+ "htmlManagerServlet.findleaksList"));
+ }
+ msg.append(writerText);
} else {
msg.append(smClient.getString("htmlManagerServlet.findleaksNone"));
}
managerServlet.deployedButNotStarted=FAIL - Deployed application at context path {0} but context failed to start
managerServlet.exception=FAIL - Encountered exception {0}
managerServlet.findleaksFail=FAIL - Find leaks failed: Host not instance of StandardHost
+managerServlet.findleaksList=OK - Found potential memory leaks in the following applications:
+managerServlet.findleaksNone=OK - No memory leaks found
managerServlet.invalidPath=FAIL - Invalid context path {0} was specified
managerServlet.invalidWar=FAIL - Invalid application URL {0} was specified
managerServlet.listed=OK - Listed applications for virtual host {0}
&& (request.getParameter("update").equals("true"))) {
update = true;
}
+
+ boolean statusLine = false;
+ if ("true".equals(request.getParameter("statusLine"))) {
+ statusLine = true;
+ }
// Prepare our output writer to generate the response message
response.setContentType("text/plain; charset=" + Constants.CHARSET);
} else if (command.equals("/undeploy")) {
undeploy(writer, cn, smClient);
} else if (command.equals("/findleaks")) {
- findleaks(writer, smClient);
+ findleaks(statusLine, writer, smClient);
} else {
writer.println(smClient.getString("managerServlet.unknownCommand",
command));
/**
* Find potential memory leaks caused by web application reload.
*/
- protected void findleaks(PrintWriter writer, StringManager smClient) {
+ protected void findleaks(boolean statusLine, PrintWriter writer,
+ StringManager smClient) {
if (!(host instanceof StandardHost)) {
writer.println(smClient.getString("managerServlet.findleaksFail"));
String[] results =
((StandardHost) host).findReloadedContextMemoryLeaks();
- for (String result : results) {
- if ("".equals(result)) {
- result = "/";
+ if (results.length > 0) {
+ if (statusLine) {
+ writer.println(
+ smClient.getString("managerServlet.findleaksList"));
+ }
+ for (String result : results) {
+ if ("".equals(result)) {
+ result = "/";
+ }
+ writer.println(result);
}
- writer.println(result);
+ } else if (statusLine) {
+ writer.println(smClient.getString("managerServlet.findleaksNone"));
}
}
<subsection name="Finding memory leaks">
<source>
-http://localhost:8080/manager/text/findleaks
+http://localhost:8080/manager/text/findleaks[?statusLine=[true|false]]
</source>
<p><strong>The find leaks diagnostic triggers a full garbage collection. It
<p>Explicitly triggering a full garbage collection from Java code is documented
to be unreliable. Furthermore, depending on the JVM used, there are options to
disable explicit GC triggering, like <code>-XX:+DisableExplicitGC</code>.
-If you want to make sure, that the diagnostics were successfully running a full GC,
-you will need to check using tools like GC logging, JConsole or similar.</p>
+If you want to make sure, that the diagnostics were successfully running a full
+GC, you will need to check using tools like GC logging, JConsole or similar.</p>
<p>If this command succeeds, you will see a response like this:</p>
<source>
/leaking-webapp
</source>
+<p>If you wish to see a status line included in the response then include the
+<code>statusLine</code> query parameter in the request with a value of
+<code>true</code>.</p>
+
<p>Each context path for a web application that was stopped, reloaded or
undeployed, but which classes from the previous runs are still loaded in memory,
thus causing a memory leak, will be listed on a new line. If an application
<taskdef name="deploy" classname="org.apache.catalina.ant.DeployTask"/>
<taskdef name="list" classname="org.apache.catalina.ant.ListTask"/>
<taskdef name="reload" classname="org.apache.catalina.ant.ReloadTask"/>
+ <taskdef name="findleaks" classname="org.apache.catalina.ant.FindLeaksTask"/>
<taskdef name="resources" classname="org.apache.catalina.ant.ResourcesTask"/>
<taskdef name="start" classname="org.apache.catalina.ant.StartTask"/>
<taskdef name="stop" classname="org.apache.catalina.ant.StopTask"/>