View on GitHub

Gae-java-mini-profiler

A mini-profiler for the Google App Engine Java runtime

Download this project as a .zip file Download this project as a tar.gz file

Google App Engine Mini Profiler for Java

About

This is a "mini profiler" for the Google App Engine Java runtime.

It's heavily inspired by

It's released under the MIT license.

Features

Demo

A demo app (with profiling enabled for anyone) is at http://gae-java-mini-profiler.appspot.com/.

Example Screenshot

Getting Started

Dependencies

Installation

Clone the source from here and build it using maven.

Then copy the gae-mini-profiler-1.0.0.jar file (and the two Jackson jars) to your WEB-INF/lib folder.

Configuration

Add the ca.jimr.gae.profiler.MiniProfilerServlet and ca.jimr.gae.profiler.MiniProfilerFilter to your web.xml.

<servlet>
  <servlet-name>miniprofiler</servlet-name>
  <servlet-class>ca.jimr.gae.profiler.MiniProfilerServlet</servlet-class>
</servlet>
<servlet-mapping>
  <servlet-name>miniprofiler</servlet-name>
  <url-pattern>/gae_mini_profile/*</url-pattern>
</servlet-mapping>
<filter>
  <filter-name>miniprofiler-filter</filter-name>
  <filter-class>ca.jimr.gae.profiler.MiniProfilerFilter</filter-class>
</filter>
<filter-mapping>
  <filter-name>miniprofiler-filter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

Note: The MiniProfilerFilter MUST be before the AppstatsFilter if you want to have Appstats show up.

There are a bunch of initParameter params you can set to configure the profiler:

Servlet Parameters

Parameter Description
maxStackFrames The maximum number of stack frames to show in the Appstats stack traces. The default is to show all of them.
htmlIdPrefix Prefix to use for HTML ids generated by the profiler. This MUST match the htmlIdPrefix in the filter definition. The default is "mp".
resourceCacheHours Number of hours to cache the static resources generated by the profiler in the browser. The default is not to cache at all (0 hours).

Filter Parameters

Parameter Description
servletURL The base URL that the servlet is mapped to. This MUST match the URL in the <servlet-mapping> specified for the MiniProfilerServlet. The default is /gae_mini_profile/.
restrictToAdmins Whether to restrict profiling to app admins. The default is false.
restrictToEmails Comma-delimited list of emails of app users to restrict profiling to. The default is no restriction.
restrictToURLs Comma-delimited list of regular expressions of URL patterns that profiling should be done on. This can be used to further limit the scope of the filter mapping specified in the web.xml. The default is no restriction.
dataExpiry How many seconds to keep profile data around in Memcache. The default is 30 seconds.
htmlIdPrefix Prefix to use for HTML ids generated by the profiler. This MUST match the htmlIdPrefix in the servlet definition. The default is "mp".

At the bottom of the <head> in your page (usually in whatever global template you are using), you must output the contents of the mini_profile_includes request attribute. This attribute will be null if the profiler did not run for this request. E.g.

<head>
  <!-- Other Stuff would go here -->
  ${mini_profile_includes}
</head> 

If you are already including jQuery and/or jQuery Templates on your page, this include needs to happen after them. If jQuery or jQuery Templates are not already included on the page, they will be.

Start up your app!

And that's it. When you run your application, depending on what restrictions you have set, you will see profiling stats showing up in the left-hand corner of the page.

Instrumenting your code

Odds are you will want more than just the elapsed time for the entire request.

You can use the MiniProfiler class to record execution times for sections of your code.

The main method to call is MiniProfiler.step( String stepName ). This will start a new profiling step, and return an object that you can later call the close() method on to finish the step. These steps can be nested to create a tree-structure.

If the profiler is inactive, the steps won't do anything.

Step step1 = MiniProfiler.step("Big things happening");
try
{
  Step step2 = MiniProfiler.step("Sub-Step 1");
  try
  {
    // Do some work
  }
  finally
  {
    step2.close();
  }
  Step step3 = MiniProfiler.step("Sub-Step 2");
  try
  {
    // Do some work
  }
  finally
  {
    step3.close();
  }
}
finally
{
  step.close();
}

This will show up in the profiler UI as something like (different numbers obviously):

Name                        Duration (ms)   Self (ms)   Offset (ms)
-------------------------------------------------------------------
Request                     100.00          10.00       0 
  Big things happening      90.00           15.00       10.00
    Sub-Step 1              35.00           35.00       15.00
    Sub-Step 2              40.00           40.00       50.00