Skip to content

Commit

Permalink
Debugging classloading
Browse files Browse the repository at this point in the history
Signed-off-by: Greg Wilkins <[email protected]>
  • Loading branch information
gregw committed Mar 25, 2019
1 parent d875186 commit 0d6ee39
Show file tree
Hide file tree
Showing 7 changed files with 260 additions and 79 deletions.
5 changes: 5 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,11 @@
<type>jar</type>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud-logging</artifactId>
<version>1.64.0</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@ runtime: custom
env: flex

manual_scaling:
instances: 1
instances: 2

env_variables:
JETTY_ARGS: -Djava.util.logging.config.file=WEB-INF/logging.properties
JETTY_MODULES_ENABLE: gcp-datastore-sessions

handlers:
- url: /.*
script: this field is required, but ignored
4 changes: 3 additions & 1 deletion src/main/docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
FROM gcr.io/jetty9-work/jetty/traceid243-7
FROM gcr.io/google-appengine/jetty
# FROM gcr.io/jetty9-work/jetty/traceid243-7
ADD logging.properties /var/lib/jetty/etc/java-util-logging.properties
ADD gae-dump-1.0-SNAPSHOT.war $JETTY_BASE/webapps/root.war
8 changes: 8 additions & 0 deletions src/main/docker/logging.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
handlers=com.google.cloud.logging.LoggingHandler

# Optional configuration
.level=INFO
com.google.cloud.logging.LoggingHandler.level=FINE
com.google.cloud.logging.LoggingHandler.log=gae_app.log
com.google.cloud.logging.LoggingHandler.formatter=java.util.logging.SimpleFormatter
java.util.logging.SimpleFormatter.format=%3$s: %5$s%6$s
205 changes: 167 additions & 38 deletions src/main/java/com/webtide/gae/ClassLoaderDump.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,22 @@

package com.webtide.gae;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.concurrent.TimeUnit;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.util.ServiceLoader;

import com.google.cloud.logging.LoggingFactory;
import com.google.cloud.logging.LoggingOptions;

/**
* Test Servlet Cookies.
Expand All @@ -40,62 +44,136 @@ public class ClassLoaderDump extends HttpServlet
{
/* ------------------------------------------------------------ */
@Override
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException
{
response.setContentType("text/html");
try
{
response.setContentType("text/html");

PrintWriter out = response.getWriter();
out.println("<h1>ClassLoader Dump Servlet:</h1>");
out.println("<a href=\"/\">home</a><br/>");
PrintWriter out = response.getWriter();
out.println("<h1>ClassLoader Dump Servlet:</h1>");
out.println("<a href=\"/\">home</a><br/>");

if (request.getPathInfo()!=null)
{
out.println("<h3>Thread Context Loader:" + Thread.currentThread().getContextClassLoader() + "</h3>");

if (request.getPathInfo() != null)
{
try
{
Class<?> info = Thread.currentThread().getContextClassLoader().loadClass(request.getPathInfo().substring(1));
dump("Info", out, info);
}
catch (Throwable th)
{
out.println("<h3>Could not load " + request.getPathInfo() + ":</h3>");
out.println("<pre>");
th.printStackTrace(out);
out.println("</pre>");
}
}

Class<?> jre = String.class;
dump("JRE", out, jre);

Class<?> context = request.getServletContext().getClass();
dump("Container",out, context);

Class<?> webapp = this.getClass();
dump("WebApp", out, webapp);

Class<?> servlet = ServletException.class;
dump("Servlet API", out, servlet);

Class<?> google = com.google.appengine.api.utils.SystemProperty.class;
dump("Google API", out, google);

Class<?> gcloud = LoggingOptions.class;
dump("App GCloud API", out, gcloud);
out.println("<p>Version of " + gcloud.getClass() + ":" +
gcloud.getPackage().getImplementationVersion() + "</h3>");

Class<?> dgcloud = LoggingOptions.getDefaultInstance().getClass();
dump("App Default GCloud API", out, dgcloud);
out.println("<p>Version of " + dgcloud.getClass() + ":" +
dgcloud.getPackage().getImplementationVersion() + "</h3>");

Class<?> cgcloud = null;
try
{
Class<?> info = Thread.currentThread().getContextClassLoader().loadClass(request.getPathInfo().substring(1));
out.println("<h3>Loader for:"+info+"</h3>");
dump(out,info.getClassLoader());
cgcloud = request.getServletContext().getClass().getClassLoader().loadClass("com.google.cloud.logging.LoggingOptions");
dump("Container GCloud API", out, cgcloud);
out.println("<p>Version of " + cgcloud.getClass() + ":" +
cgcloud.getPackage().getImplementationVersion() + "</h3>");
}
catch (Throwable th)
catch(Exception e)
{
out.println("<h3>Could not load "+request.getPathInfo()+":</h3>");
out.println("<pre>");
th.printStackTrace(out);
out.println("</pre>");
out.println("<h3>Container GCloud API</h3>\n<p>not found:" + e + "</p>\n");
}
}

Class<?> jre = String.class;
out.println("<h3>JRE Loader for:"+jre+"</h3>");
dump(out,jre.getClassLoader());

Class<?> webapp = this.getClass();
out.println("<h3>WebApp Loader for:"+webapp+"</h3>");
dump(out,webapp.getClassLoader());
Class<?> dgcloudSvc = LoggingOptions.getDefaultInstance().getService().getClass();
dump("App Default GCloud Service", out, dgcloudSvc);
out.println("<p>Version from package " + dgcloudSvc.getClass() + ":" +
dgcloudSvc.getPackage().getImplementationVersion() + "</h3>");

out.println("<h3>Thread Context Loader for:"+Thread.currentThread()+"</h3>");
dump(out,Thread.currentThread().getContextClassLoader());
out.printf("<h4>Service Loader: %s</h4>%n", LoggingFactory.class);
dump("WebApp", out, dgcloud);
out.println("<pre>");
try
{
Class<?> factory = LoggingFactory.class;
ServiceLoader loader = ServiceLoader.load(factory);
for (Object o : loader)
{
out.printf("service %s of %s loader from %s%n",o, o.getClass(), getLocationOfClass(o.getClass()));
}
}
catch(Exception e)
{
e.printStackTrace(out);
}
finally
{
out.println("</pre>");
}
}
catch(Exception e)
{
throw new ServletException(e);
}
}

Class<?> container = ServletException.class;
out.println("<h3>Container Loader for:"+container+"</h3>");
dump(out,container.getClassLoader());

Class<?> google = com.google.appengine.api.utils.SystemProperty.class;
out.println("<h3>Google Loader for:"+google+"</h3>");
dump(out,google.getClassLoader());
private void dump(String scope, PrintWriter out, Class<?> clazz) throws URISyntaxException
{
if (clazz!=null)
{
out.printf("<h3>%s: class %s</h3>%n<p>Loaded from %s</p>%n",
scope, clazz.getName(), getLocationOfClass(clazz));
dump(out,clazz.getClassLoader(),"!WebApp".equals(scope));
}
}

private void dump(PrintWriter out, ClassLoader loader)
{
dump(out,loader, false);
}

private void dump(PrintWriter out, ClassLoader loader, boolean webapp)
{
if (loader==null)
{
out.println("SYSTEM LOADER<br/>");
return;
}

out.println(loader);
if (!webapp && loader==this.getClass().getClassLoader())
{
out.println("WEBAPP LOADER<br/>");
return;
}

out.printf("<p>Loader: %s</p>%n", loader);
out.println("<ul>");
if (loader instanceof URLClassLoader)
{
Expand All @@ -111,5 +189,56 @@ private void dump(PrintWriter out, ClassLoader loader)
out.println("</ul>");
}

/* ------------------------------------------------------------ */
public static URI getLocationOfClass(Class<?> clazz) throws URISyntaxException
{
ProtectionDomain domain = clazz.getProtectionDomain();
if (domain != null)
{
CodeSource source = domain.getCodeSource();
if (source != null)
{
URL location = source.getLocation();

if (location != null)
return location.toURI();
}
}

String resourceName = clazz.getName().replace('.', '/') + ".class";
ClassLoader loader = clazz.getClassLoader();
URL url = (loader == null ? ClassLoader.getSystemClassLoader() : loader).getResource(resourceName);
if (url != null)
{
return getJarSource(url.toURI());
}
return null;
}

public static URI getJarSource(URI uri)
{
try
{
if (!"jar".equals(uri.getScheme()))
return uri;
// Get SSP (retaining encoded form)
String s = uri.getRawSchemeSpecificPart();
int bang_slash = s.indexOf("!/");
if (bang_slash>=0)
s=s.substring(0,bang_slash);
return new URI(s);
}
catch(URISyntaxException e)
{
throw new IllegalArgumentException(e);
}
}

public static String getJarSource(String uri)
{
if (!uri.startsWith("jar:"))
return uri;
int bang_slash = uri.indexOf("!/");
return (bang_slash>=0)?uri.substring(4,bang_slash):uri.substring(4);
}
}
Loading

0 comments on commit 0d6ee39

Please sign in to comment.