Re: Making RPC access logs intelligible

2011-03-30 Thread Kelsey Francis
Jeff,

You could create a common subclass (let's call it JeffRemoteServiceServlet) 
of RemoteServiceServlet that overrides the 
onAfterRequestDeserialized(RPCRequest) method. That method is called, as the 
name implies, everytime the servlet receives an RPC request, so it's the 
perfect spot to collect information for logging.

That doesn't get you the timing information you're after, though, so you 
could instead override RemoteServiceServlet.processCall(String) to
1. Start a timer (i.e., record System.nanoTime() or whatever)
2. Call super.processCall
3. Stop the timer

Now, so long as all of your service implementations override 
JeffRemoteServiceServlet, you've got the desired behavior everywhere. I'm 
not sure where the best spot to do the actual averaging would be, but this 
should at least let you hook in at the right spot.

Another (much more difficult) option, that you and Philippe have alluded to, 
is to call setServiceEntryPoint client-side and pipe all of your RPC 
requests through a single servlet. You can make this happen automatically, 
or even completely take over the RPC transport process by creating a custom 
proxy generator. We've done this, and as you mentioned, it's a little 
difficult to wrap your head around at first, but once you have, the changes 
are actually pretty minor (unless you decide to start adding features like 
batching, etc.). You'd need:
1. A new subclass of RemoteServiceProxy (let's call it 
DispatchedRemoteServiceProxy) that overrides doInvoke() to take control of 
the transport of the request
2. A new subclass of ProxyCreator (let's call it 
DispatchedRemoteProxyCreator) that overrides getProxySupertype() to 
return DispatchedRemoteServiceProxy.class
3. A new subclass of ServiceInterfaceProxyGenerator (let's call it 
DispatchedRemoteServiceGenerator) that overrides createProxyCreator() to 
return a new DispatchedRemoteProxyCreator
4. Have your services inherit a new interface (DispatchedRemoteService) and 
set up your .gwt.xml file generate impls of that interface with 
DispatchedRemoteServiceGenerator.

The trickiest part is what to do in DispatchedRemoteServiceProxy.doInvoke(). 
You'll want to make a request to your special dispatch servlet, of course, 
and then decode it once you get a response. RequestCallbackAdapter holds the 
keys to making this happen. Dispatching the request server-side is 
relatively trivial once you have the decoded RPCRequest.

The point of all this is of course to have all your requests one through a 
single servlet, which would, among other things, probably make collecting 
information about requests a little easier.

-Kelsey

-- 
You received this message because you are subscribed to the Google Groups 
Google Web Toolkit group.
To post to this group, send email to google-web-toolkit@googlegroups.com.
To unsubscribe from this group, send email to 
google-web-toolkit+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/google-web-toolkit?hl=en.



Re: Making RPC access logs intelligible

2011-03-30 Thread Jeff Schnitzer
Philippe, Kelsey - thanks for the very helpful responses.  This sort
of additional proxy behavior feels like something that would be of
considerable value as a standard part of GWT.  I'm surprised there
aren't considerably more complaints in this group.

setServiceEntryPoint() was the magic button I was looking for.
However, I ended up coming up with an alternative that fits my
(heavily Guice-dependent) architecture a little better.  Since your
responses were so good (I wish I could give you stackoverflow points),
I feel obligated explain what I did.

This involves a larger number of artifacts than I would prefer, but it
feels fairly natural to me:

 * I derived a new GuiceRemoteServiceServlet that overrides
processCall() to look up the interface in the Guice injector and
execute code on throwaway objects.
 * I created separate interface, interfaceAsync, and implementation
classes for every single method.  Each interface has a different
@RemoteServiceRelativePath.  Some of the impl classes handle multiple
interfaces when there is appropriate shared logic.
 * I map the interfaces to implementation in GuiceConfig.
 * I created a Gin singleton that implements all the async interfaces
and proxies to the individual gwt-rpc proxies; this keeps my client
code blissfully ignorant of the complexity.

It's a little painful to add an RPC method:

 * Create new interface and interfaceAsync
 * Implement the interface with a new impl class or on an existing impl class
 * Map the interface to impl in Guice
 * Add the async interface to the Gin singleton proxy

On the other hand my biz logic is now the way I want it to be -
wrapped up in small, modular, reusable, appropriately scoped,
guice-injected chunks.  Parameter/method changes refactor nicely with
Eclipse.  I could eliminate the mapping step with annotations if I was
willing to accept the startup time penalty of classpath scanning, and
I could probably even generate the Gin singleton if I wanted.  But my
remote interface doesn't change that often.

This may not be for everyone, but for a DI addict like me it seems
pretty reasonable.  And my appengine logs are now beautiful again -
current load, errors, and individual log entries are now broken down
by method call.

Jeff

On Wed, Mar 30, 2011 at 4:33 AM, Kelsey Francis kelseyfran...@gmail.com wrote:
 Jeff,
 You could create a common subclass (let's call it JeffRemoteServiceServlet)
 of RemoteServiceServlet that overrides the
 onAfterRequestDeserialized(RPCRequest) method. That method is called, as the
 name implies, everytime the servlet receives an RPC request, so it's the
 perfect spot to collect information for logging.
 That doesn't get you the timing information you're after, though, so you
 could instead override RemoteServiceServlet.processCall(String) to
 1. Start a timer (i.e., record System.nanoTime() or whatever)
 2. Call super.processCall
 3. Stop the timer
 Now, so long as all of your service implementations override
 JeffRemoteServiceServlet, you've got the desired behavior everywhere. I'm
 not sure where the best spot to do the actual averaging would be, but this
 should at least let you hook in at the right spot.
 Another (much more difficult) option, that you and Philippe have alluded to,
 is to call setServiceEntryPoint client-side and pipe all of your RPC
 requests through a single servlet. You can make this happen automatically,
 or even completely take over the RPC transport process by creating a custom
 proxy generator. We've done this, and as you mentioned, it's a little
 difficult to wrap your head around at first, but once you have, the changes
 are actually pretty minor (unless you decide to start adding features like
 batching, etc.). You'd need:
 1. A new subclass of RemoteServiceProxy (let's call it
 DispatchedRemoteServiceProxy) that overrides doInvoke() to take control of
 the transport of the request
 2. A new subclass of ProxyCreator (let's call it
 DispatchedRemoteProxyCreator) that overrides getProxySupertype() to
 return DispatchedRemoteServiceProxy.class
 3. A new subclass of ServiceInterfaceProxyGenerator (let's call it
 DispatchedRemoteServiceGenerator) that overrides createProxyCreator() to
 return a new DispatchedRemoteProxyCreator
 4. Have your services inherit a new interface (DispatchedRemoteService) and
 set up your .gwt.xml file generate impls of that interface with
 DispatchedRemoteServiceGenerator.
 The trickiest part is what to do in DispatchedRemoteServiceProxy.doInvoke().
 You'll want to make a request to your special dispatch servlet, of course,
 and then decode it once you get a response. RequestCallbackAdapter holds the
 keys to making this happen. Dispatching the request server-side is
 relatively trivial once you have the decoded RPCRequest.
 The point of all this is of course to have all your requests one through a
 single servlet, which would, among other things, probably make collecting
 information about requests a little easier.
 -Kelsey

 --
 You received 

Making RPC access logs intelligible

2011-03-29 Thread Jeff Schnitzer
GWT's RPC system produces distinctly unfriendly access logs.  When I
look at my logs (especially the GAE dashboard), every RPC basically
boils down to a single line item for the whole servlet (and all the
various RPC methods):

/mymodule/myservletNNN requests avg MMM ms each

I really want this broken down by the method that gets called:

/mymodule/myservlet/login   NNN requests avg MMM ms each
/mymodule/myservlet/doSomething   NNN requests avg MMM ms each
/mymoudle/myservlet/doOtherThing   NNN requests avg MMM ms each

How can I make this happen elegantly?

All I can think of is to make separate servlets for each method.  This
is tedious.  Even my minimal API still has 14 different methods.
Create 14 servlets, 14 RemoteService interfaces, 14 Async interfaces?
Yuck.  Even if I made a single servlet that implemented all those
interfaces and was mapped to 14 different URLs, it's still a PITA.

Is there any other solution?  It may seem trivial, but this is really
a critical issue.  It's hard enough to measure that an application is
doing even with well-organized log messages.  GAE's Appstats is almost
unreadable right now.

Thanks in advance,
Jeff

-- 
You received this message because you are subscribed to the Google Groups 
Google Web Toolkit group.
To post to this group, send email to google-web-toolkit@googlegroups.com.
To unsubscribe from this group, send email to 
google-web-toolkit+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/google-web-toolkit?hl=en.



Re: Making RPC access logs intelligible

2011-03-29 Thread Jeff Schnitzer
Browsing through the GWT code some more, it doesn't look promising.
Is there any way to look at the output of the RpcProxyCreator?
Reading code is ok, reading code that generates code tortures my
brainmeats.

Jeff

On Tue, Mar 29, 2011 at 2:28 PM, Jeff Schnitzer j...@infohazard.org wrote:
 GWT's RPC system produces distinctly unfriendly access logs.  When I
 look at my logs (especially the GAE dashboard), every RPC basically
 boils down to a single line item for the whole servlet (and all the
 various RPC methods):

 /mymodule/myservlet    NNN requests avg MMM ms each

 I really want this broken down by the method that gets called:

 /mymodule/myservlet/login   NNN requests avg MMM ms each
 /mymodule/myservlet/doSomething   NNN requests avg MMM ms each
 /mymoudle/myservlet/doOtherThing   NNN requests avg MMM ms each

 How can I make this happen elegantly?

 All I can think of is to make separate servlets for each method.  This
 is tedious.  Even my minimal API still has 14 different methods.
 Create 14 servlets, 14 RemoteService interfaces, 14 Async interfaces?
 Yuck.  Even if I made a single servlet that implemented all those
 interfaces and was mapped to 14 different URLs, it's still a PITA.

 Is there any other solution?  It may seem trivial, but this is really
 a critical issue.  It's hard enough to measure that an application is
 doing even with well-organized log messages.  GAE's Appstats is almost
 unreadable right now.

 Thanks in advance,
 Jeff


-- 
You received this message because you are subscribed to the Google Groups 
Google Web Toolkit group.
To post to this group, send email to google-web-toolkit@googlegroups.com.
To unsubscribe from this group, send email to 
google-web-toolkit+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/google-web-toolkit?hl=en.



Re: Making RPC access logs intelligible

2011-03-29 Thread Philippe Beaudoin
The command pattern included in GWT-Platform gives a different path to each 
command and yield very readable logs in GAE.

The trick is to call setServiceEntryPoint from the client async service 
implementation. If you want to see how we do it in GWTP check out:
  
http://code.google.com/p/gwt-platform/source/browse/gwtp-core/gwtp-dispatch-client/src/main/java/com/gwtplatform/dispatch/client/DefaultDispatchAsync.java#70

Cheers!

   Philippe

-- 
You received this message because you are subscribed to the Google Groups 
Google Web Toolkit group.
To post to this group, send email to google-web-toolkit@googlegroups.com.
To unsubscribe from this group, send email to 
google-web-toolkit+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/google-web-toolkit?hl=en.