Monday, June 29, 2009

Dumpcatcher: Uncaught Exceptions and Client IDs

Alright, about halfway through my flight and I now have an Uncaught exception handler that will post messages to dumpcatcher.

It doesn't work with android at the momement... There is a thread I know I have to read on android-developers. I think I starred it because I knew I'd find it uuseful.

The first user of this class was going to be Foursquared, but it turns out the code I wrote doesn't work.

I quickly added the ability to create a client id attached to each crash in order to allow me track each individual client and in the process refactored a bit of the code here and there. I'll have to remeber to update the design doc as I have made some changes to the design after noticing flaws in my original work.

Labels: , ,

Sunday, June 28, 2009

Dumpcatcher: Java Client

I'm on my way back from Cambodia... More on that later...

After spending about two-three hours working on hmac signing with Java I now have a working Dumpcatcher client for Java, this is similar to the python client

clients/python/logging/handler.py:Dumpcatcher
in that its usage is:
Dumpcatcher dc = new Dumpcatcher(PRODUCT_KEY, SECRET, "http://localhost:8080/add", 2);
HttpResponse response = dc.sendCrash(
    new NameValuePair("short", "Some short dump"),
    new NameValuePair("long", "some long dump")
)
    assertNotNull(response);
    assertEquals(200, response.getStatusLine().getStatusCode());

Have a look: http://code.google.com/p/dumpcatcher/source/browse/clients/java/src/com/googlecode/dumpcatcher/logging/Dumpcatcher.java?r=20090629r0

Now onto making a logging client for this guy.

Labels: ,

Monday, June 22, 2009

Dumpcatcher: Design Doc

As I do with any project at work, I want to put together a short doc describing the scope and scale at which I will write this app.

Summary

Dumpcatcher is a simple web service that takes authorized requests from remote clients and logs key-value pairs in its datastore for future analysis. These pairs are typically an aribitrary identifier and an exception/stack-trace.

Features

  • Crash Stack Message storage
  • Clients must be able to submit stack traces (well, arbitrary strings) along with various bits of meta-data. Version, app name, etc.
  • Client libraries for Python, Java
  • I am targeting my <a href="http://joelapenna.com/git/foursquared.git">Foursquared Android Client

    Unknown end tag for </a>

    as well as any other pet projects I may use in the future.
  • Data Aggregation
  • I plan on allowing data aggregation by exception type, custom label and line.
  • Authenticated Client Requests
  • All requests by clients must be sent by authorized clients to prevent the service from becoming a black hole for spam. Design:

Design

App Engine has a very simple data store and webapp framework that I intend to utiltize for the basic functionality of the app.

Users

Users represent a single Google Id and a particular developer using the system.

Products

A product is an application that uses the dumpcatcher to log crashes. A user may have multiple products.

Each product registered will have two values associated with it, a productKey which will be passed as a paramter in all HTTP requests to the server and a secret which will be used to HMAC sign a request.

Product secrets will be randomly generated UUIDs.

HTTP Request

All requests to the dumpcatcher service will be secured with an HMAC hash. The hash will be keyed by a unique identifier provided to the client

productKey

Each client -> server request will include a productKey, an identifier used to differentiate between different products using the service.

HMAC

All requests must be submitted with an HMAC-SHA1 hex digest of the request query paramters as well as an increasing "request" identifer. The message consists of a standard http "query", sorted by keyname and quoted, request

For: http://localhost/add?product_keyd=1234&some=pair&other=pair we would construct the digest like so:

TODO(jlapenna): Probably don't want to split on & if the contents of the request might contain one though, they should already be encoded. Something like that...

sorted_query = ''.join(sorted(request.query_string.split('&'))) hash = hmac.new('SOME KEY', sorted_query, hashlib.SHA1)

And, as such, the actual request made to the server will be:

'http://localhost/add?product_key=12345&some=pair&other=pair&hmac=%(hash)s'

On the backend the server will take the reverse steps and using the secret associated with the provided productKey, will verify the authenticity of the request by encoding the query paramters the same way it is done on the client, keying the result by secret associated with the provided productKey.

Datastore

Initially there will be three models, one corresponding to "crashes," another to "users" and the third to "products."

Each user will be associated with a specific Google ID but a single Google ID can have many products.

Security

Security and validity of client-> server requests will be handled via the usage of HTTPS for securing communications and for HMAC to verify authenticity of a client request.

Replay Attack

An attacker with access to the HTTP stream a client -> server request is sent over will be able to execute a replay attack by capturing the HTTP post made by the client and submitting it as its own, at any rate he so desires.

The solution as such is to only allow requests over HTTPS. This gains the added advantage of preventing any private data from leaking via a network observer packet sniffing.

Caveats

It is likely and highly reasonable that an app like this exists in a highly more polished and featureful way. I chose this project because I felt like it would be a good way to explore some new technologies and have a fun time; not because this is in any way "new" or "exciting"

Labels: , , , ,

Thursday, October 2, 2008

Catchup with two hands

its been six days and its time again to leave SF for a new place. I'm going to be in Toronto until the 15th. I'm in for work but ahould have plenty of time for fun. Heck, as I'm good at doing, I am in Toronto over a 3 day weekend too.

I have taken this whole week off of work, including Friday but excluding part of monday. In that time I have  been able to catch up on several months of life. I got a haircut, went clothes shopping and had several Hendricks (great gin, thanks for the recommendation josebiro) Martinis. I have also added a few more needed features to the top-secret prokect and am still looking for someone to do some UI design work, I could also use someone who is interested in mobile applications, python, java and/or javascript because I think I need more people to work on this if I'm going to get this completed in any reasonable amount of time.

On one hand, I see that I am making steady progress. Every day that I sit down and focus on it, I walk away at the end with something newer and better than before. On the otherhand, some of the ideas that propelled me to work on this project seem so far away in the future that I'm worried ill never get to the cool problems that will make this project stand out. Heck, I've no doubt pumped some people (including myself) up about this and I'm sure it won't meet anyone's expectations.

On the other hand, I'm still happy about the work that I have completed, I just wish it hadn't taken four months to get here. My thought is that in the next few days ill start using the app on my own and see if in its current state it is usable. If not, I'm going to have to take a hard look at what it will take to make my project get there. if not I will have several months of rewrite ahead of me and I will surely have lost the first to market edge.

Labels: , , , ,

Saturday, September 27, 2008

Top Secret Project Update


I've spent another weekend hacking away at my top secret project and I feel that every day I work on it that I am getting closer to being able to use it. In fact, I'm just a few major-usability bugs away from using it day to day! After I spend a few weeks working on it, then a few more weeks fixing what I see as show stoppers I hope to be able to show it off to a couple of people.

Looking at what I've done so far this summer leaves me both depressed and excited. I'm a bit sad because I am so far away from what I hoped to have accomplished by this point. At the same time, I'm excited about what I have been able to do. I've learned a ton about Java and realized that it is a pretty awesome language. I feel it is a good way for me to stretch my brain. With python you can throw everything against a wall, 'import antigravity' and have the crap float away, leaving you with something usable. With Java, I feel I have to plan things out a bit better. I have to live with the consequences of my decisions and deal with every shortcut I inevitable take. As a result I'm much more careful about what I do. Even if I do take a shortcut, these days they don't tend to last very long as I get irritated with the way my code looks or interacts and I refactor until I'm happy.

One thing I haven't gotten around to learning is unit testing. I thought I would have more time to work on the project this summer and fully expected to be twice as far along as I am today, with solid unit testing coverage. Instead I'm not even at a usable point with my project and I've not written one Java unit test. The python side of my app has a few tests but still nothing worthy of being called "coverage."

Labels: , , ,

Sunday, August 31, 2008

Android/App Engine prototyping problems

Almost a year ago, Google unleashed its Android SDK in a preview capacity. One of the pain points I experienced with it was the tedium in creating ContentProviders. Today, I'm feeling the same tedium. A ContentProvider is the sole mechanism for an android application to share information with external packages. ContentProviders can be backed by any kind of data, file, database or live server with custom backend. The popular method is creating a ContentProvider that is backed by a database. Creating such a beast is a time consuming operation and making it with a SQL database is quite contrary to the BigTable based datastore API in Google App Engine (GAE).
In my top secret project, I'm using the HttpClientService api that I've defined in my Missing SVN repository (the top-secret project is indeed different than Missing) to interface with my server. Currently, the client does no caching of data -- all information it needs is pulled at user request, from the interwebs. When testing on my local machine, this is not a problem. I have a fast workstation and there isn't much packet loss or latency on a loopback interface.

Unfortunately, this won't work in the "real world." I'm now at the point where I have to implement a sql-lite backed ContentProvider that tries to model a table-based GAE datastore api. Not only does this mean I have to keep track of two different schema, one for GAE and one for Android, but it means I have to implement the same "get my data" api twice, with a layer of abstraction between the android UI and the ContentProvider I'm resenting having to create.

What I'm considering doing is using something like Google's Protocol Buffers or Facebook's Thrift to define my data model and create stub interfaces for both GAE and Android. This seems like a bit of overkill for the current state of my project but even in the not-yet-ready-to-show-anyone stage of this project I'm having to consider these very-high-time-cost coding excersizes. This is going to consume time when I should be iterating on features and trying to get the app in a state where I can finally start to use it. I think I've proto-typed the android app as far as I can go but I don't want to start spending hordes of time on this when I have several core concepts not-yet-implemented.

I'm also feeling the pain of knowing that the stuff I prototyped at the beginning of the project are going to have to be fully re-written and if I don't provide a more featureful content provider.

One of the ways you can provide an abstracted interface to the ContentProvider is by wrapping it in a Service, which of course requires yet another interface declaration, this one with java primatives and simple classes using the AIDL interface spec provided by Android. I figure I'll have to cross that bridge some day, I'm just glad I don't have to do it right now.

Labels: , , , , , ,

Sunday, July 20, 2008

Design Patterns... BAH!

I started reading "Head First Design Patterns" last week, and taking advantage of my new-found knowledge I tried to refactor Missing's http client stack. Its taken me about eight hours and it works again. Its as ugly as it was before, maybe even more so.

The kookiness of the design stems from the fact that I want the ability to respond to an HTTP response, possibly from a different thread. Android has a cool thread/message-queuing class called a Handler, that allows you to post a Runnable to the handler and it will get executed on the thread in which the handler was instantiated.

Because I wanted to keep my http stack android-agnostic (not that I had a good reason for it, in fact I didn't even think of doing it at first.) I removed the knowledge of the Handler from the .http package.

Instead I created a decorator for the HttpResponseRunnable that does know about Android's handlers. For the sake of re-use on another project, I put it in the .http package... DOH!

On the positive side, I did manage to implement a design that allows me to dynamically create http requests and responses without having to subclass all the time. I don't know if in the long run that will be better.

Things I need to think about:
  1. What is the best way to chain http operations where each request depends on data from the previous request?
  2. How would I design the HttpService from the ground up? Where can I look at code that has similar features to the ones I'm coding up to see what design they used.
  3. Why am I constantly re-writing this stack?
  4. If I am going to have a large number of http callbacks, if there are many types of end points, do I want keep the ability to define them quickly, or do I go with something more verbose and more abstract?

Do you know Java? Want to discuss some of this with me? I'm a newb and could use insight from someone with more experience than I.

Labels: , , , ,

Sunday, April 8, 2007

Whew . . .

I struggled through it but for the first time in three years I wrote Java. It was simple . . . Tic Tac Toe, but I feel so satisfied. I've been struggling unsuccessfully for the past few months on dead-from-the-start personal projects. Some were python, heck one was C# but I never got anywhere more than a random hundred lines of programming-equivalent chicken scratch.

Now I can write very, very verbose chicken scratch.

The most interesting thing in this adventure to relearn Java was the realization I had about my own skills as a programmer. Four and a half years ago I took two semesters worth of Java classes and learned a small subset of the language. At the time I was a bit cocky but more so I was nave. I thought that those classes had taught me programming and that damn it, I knew what I was doing. Three years of a break from Java and two years of immersion into programming . . . in a different language . . . for Google has made me realize how uninformed and unskilled I was.

I had learned Visual Basic and dabbled in php when I was in High School then c and c++ during my year at Purdue but never at any point do I feel (looking back) that I got anywhere past the point of simply learning the language. I never pushed myself to the point wher I was actually learning to program. I've been fortunate enough to have that experience working at Google and now am taking advantage of it daily as I spend my work day at the job I dreamed about in High School.

I thought it would be fun at this point to excerpt some of my old code and comment on it here, but it seems my terrible internet connection is refusing to allow me the pleasure.

[jlapenna@zane 130] traceroute joelapenna.com
traceroute to joelapenna.com (205.234.239.111), 30 hops max, 40 byte packets
 1  c-71-202-127-212.hsd1.ca.comcast.net (71.202.127.212)  2.810 ms  3.187 ms  2.993 ms
 2  * * *
 3  ge-1-3-ur01.sf19th.ca.sfba.comcast.net (68.87.199.241)  15.014 ms  22.287 ms  13.962 ms
 4  te-9-3-ur02.sfmission.ca.sfba.comcast.net (68.87.192.221)  14.332 ms  16.152 ms  16.999 ms
 5  te-9-3-ur01.sfmission.ca.sfba.comcast.net (68.87.192.217)  38.520 ms  16.269 ms  16.496 ms
 6  * te-8-3-ur02.sffolsom.ca.sfba.comcast.net (68.87.192.213)  11.335 ms *
 7  te-9-1-ur01.sffolsom.ca.sfba.comcast.net (68.87.192.205)  19.770 ms  16.349 ms  17.258 ms
 8  te-9-1-ur02.sfsutro.ca.sfba.comcast.net (68.87.192.201)  18.287 ms  19.217 ms *
 9  te-8-1-ur01.sfsutro.ca.sfba.comcast.net (68.87.226.45)  22.241 ms  17.933 ms  14.214 ms
10  * * te-9-2-ar01.sfsutro.ca.sfba.comcast.net (68.87.192.197)  15.430 ms
11  68.86.143.9 (68.86.143.9)  17.122 ms  11.585 ms  11.790 ms

Labels:

The views and opinions expressed in the blog are of Joe LaPenna. Google has nothing to do with these pages.
For information about Google please visit: Google Press Center