Wednesday, May 09, 2012

Extra S3 log parameters with AWS Java SDK

Amazon web services' S3 REST API supports custom access log information by adding custom query string parameters beginning with "x-" that S3 ignores but logs. Unfortunately custom query parameters are not directly supported in the AWS Java SDK, so we were planning to drop down to writing HTTP REST code for a recent project that required logging of some custom client-session parameters.

I hate working with HTTP, so I was glad when we figured out a workaround. The trick we came up with was to register a custom RequestHandler with our instance of the SDK's AmazonS3Client. The RequestHandler is an internal class in the API, so it's not included in the API documentation, but you can download the source code to see its simple interface:

/**
 * Interface for addition request handling in clients. A request handler is
 * executed on a request object before it is sent to the client runtime
 * to be executed.
 */
public interface RequestHandler {

    /**
     * Runs any additional processing logic on the specified request (before it
     * is executed by the client runtime).
     *
     * @param request
     *            The low level request being processed.
     */
    public void beforeRequest(Request request);

 /**
  * Runs any additional processing logic on the specified request (after is
  * has been executed by the client runtime).
  *
  * @param request
  *            The low level request being processed.
  * @param response
  *            The response generated from the specified request.
  * @param timingInfo
  *            Timing information on the request's processing.
  */
    public void afterResponse(Request request, Object response, TimingInfo timingInfo);

 /**
  * Runs any additional processing logic on a request after it has failed.
  *
  * @param request
  *            The request that generated an error.
  * @param e
  *            The error that resulted from executing the request.
  */
    public void afterError(Request request, Exception e);

}

So the RequestHandler's beforeRequest method can add parameters to a Request before it is processed by the underlying HTTP engine. The only trick is to determine which parameters to add to a particular Request, but it's easy to extend the SDK's API-level request objects (like S3's GetObjectRequest) with subtypes that add application-specific properties, then check for for those subtypes in the RequestHandler via the getOriginalRequest accessor.

No comments: