| # OpenCensus HTTP Util | |
| [![Build Status][travis-image]][travis-url] | |
| [![Windows Build Status][appveyor-image]][appveyor-url] | |
| [![Maven Central][maven-image]][maven-url] | |
| The *OpenCensus HTTP Util for Java* is a collection of utilities for trace instrumentation when | |
| working with HTTP. | |
| ## Quickstart | |
| ### Add the dependencies to your project | |
| For Maven add to your `pom.xml`: | |
| ```xml | |
| <dependencies> | |
| <dependency> | |
| <groupId>io.opencensus</groupId> | |
| <artifactId>opencensus-api</artifactId> | |
| <version>0.28.3</version> | |
| </dependency> | |
| <dependency> | |
| <groupId>io.opencensus</groupId> | |
| <artifactId>opencensus-contrib-http-util</artifactId> | |
| <version>0.28.3</version> | |
| </dependency> | |
| </dependencies> | |
| ``` | |
| For Gradle add to your dependencies: | |
| ```groovy | |
| compile 'io.opencensus:opencensus-api:0.28.3' | |
| compile 'io.opencensus:opencensus-contrib-http-util:0.28.3' | |
| ``` | |
| ## Instrumenting HTTP libraries/frameworks | |
| ### customization for libraries/frameworks | |
| Users can implement `HttpExtractor` to customize what information are extracted from the HTTP | |
| request/response entity. | |
| If context propagation is enabled, users need to provide framework specific `TextFormat.Setter` | |
| and `TextFormat.Getter`. They are used to inject/extract information into/from the `Carrier` of | |
| the request. The `Carrier` can be the request itself or other objects, as long as it provides | |
| functionalities of setting/getting HTTP attributes. | |
| Below is an example of how the customization for libraries/frameworks should be done: | |
| ```java | |
| // // Http request entity in the library/framework. | |
| // public class HttpRequest { | |
| // ... | |
| // } | |
| // | |
| // // Http response entity in the library/framework. | |
| // public class HttpResponse { | |
| // ... | |
| // } | |
| // use the HttpRequest itself as Carrier. | |
| TextFormat.Setter<HttpRequest> myTextFormatSetter = | |
| new TextFormat.Setter<HttpRequest>() { | |
| @Override | |
| public void put(HttpRequest carrier, String key, String value) { | |
| carrier.setHeader(key, value); | |
| } | |
| }; | |
| TextFormat.Getter<HttpRequest> myTextFormatGetter = | |
| new TextFormat.Getter<HttpRequest>() { | |
| @Override | |
| public String get(HttpRequest carrier, String key) { | |
| return carrier.getHeader(key); | |
| } | |
| }; | |
| HttpExtractor<HttpRequest, HttpResponse> extractor = | |
| new HttpExtractor<HttpRequest, HttpResponse>() { | |
| @Override | |
| public Integer getStatusCode(HttpResponse response) { | |
| return response.getStatusCode(); | |
| } | |
| // other methods that need to be overridden | |
| // ... | |
| }; | |
| ``` | |
| ### Client | |
| Users can create a `HttpClientHandler` to help instrument client-side HTTP request/response. | |
| An example usage of the handler would be: | |
| ```java | |
| HttpClientHandler<HttpRequest, HttpResponse, HttpRequest> handler = | |
| new HttpClientHandler<HttpRequest, HttpResponse>( | |
| tracer, extractor, myTextFormat, myTextFormatSetter); | |
| // Use #handleStart in client to start a new span. | |
| // Use `null` if you want to use current Span as the parent Span. | |
| HttpRequestContext context = handler.handleStart(null, request, request); | |
| HttpResponse response = null; | |
| Throwable error = null; | |
| try { | |
| // Do something to send the request, and get response code from the server | |
| response = getResponse(request); | |
| // Optionally, use #handleMessageSent in client to log a SENT event and its size. | |
| handler.handleMessageSent(context, request.getContentLength()); | |
| // Optionally, use #handleMessageReceived in client to log a RECEIVED event and message size. | |
| handler.handleMessageReceived(context, response.getContentLength()); | |
| } catch (Throwable e) { | |
| error = e; | |
| } finally { | |
| // Use #handleEnd in client to close the span. | |
| handler.handleEnd(context, request, response, error); | |
| } | |
| ``` | |
| ### Server | |
| Users can create a `HttpServerHandler` to help instrument server-side HTTP request/response. | |
| An example usage of the handler would be: | |
| ```java | |
| HttpServerHandler<HttpRequest, HttpResponse> handler = | |
| new HttpServerHandler<HttpRequest, HttpResponse, HttpRequest>( | |
| tracer, extractor, myTextFormat, myTextFormatGetter, | |
| false /* true if it is public endpoint */); | |
| // Use #handleStart in server to start a new span. | |
| HttpRequestContext context = handler.handleStart(request, request); | |
| HttpResponse response = constructResponse(); | |
| Throwable error = null; | |
| try (Scope scope = tracer.withSpan(handler.getSpanFromContext(context))) { | |
| // Do something to decide whether to serve the request or early exit. | |
| // For example, client may expect a 100 Continue before sending the message body. | |
| if (extractor.getRequestSize(request) > REQUEST_LIMIT) { | |
| response.setStatus(413); | |
| } else { | |
| response.setStatus(100); | |
| String content = request.getContent(); | |
| // Optionally, use #handleMessageReceived in server to log a RECEIVED event and its size. | |
| handler.handleMessageReceived(context, request.getContentLength()); | |
| // Do something to prepare the response or exception. | |
| response.setStatus(201); | |
| response.write("OK"); | |
| response.flush(); | |
| // Optionally, use #handleMessageSent in server to log a SENT message event and its message size. | |
| handler.handleMessageSent(context, response.getContentLength()); | |
| } catch (Throwable e) { | |
| error = e; | |
| } finally { | |
| // Use #handleEnd in server to close the span. | |
| handler.handleEnd(context, request, response, error); | |
| } | |
| } | |
| ``` | |
| ### handling async calls | |
| In asynchronous HTTP calls, message receiving and sending may happen in different | |
| threads. Users need to ensure the started span (as well as scope, if any) is | |
| closed or ended no matter the call is successful or not. | |
| To do that, store current scope and span somewhere, e.g. the context of the channel, | |
| and close them before the channel exits. | |
| [travis-image]: https://travis-ci.org/census-instrumentation/opencensus-java.svg?branch=master | |
| [travis-url]: https://travis-ci.org/census-instrumentation/opencensus-java | |
| [appveyor-image]: https://ci.appveyor.com/api/projects/status/hxthmpkxar4jq4be/branch/master?svg=true | |
| [appveyor-url]: https://ci.appveyor.com/project/opencensusjavateam/opencensus-java/branch/master | |
| [maven-image]: https://maven-badges.herokuapp.com/maven-central/io.opencensus/opencensus-contrib-grpc-util/badge.svg | |
| [maven-url]: https://maven-badges.herokuapp.com/maven-central/io.opencensus/opencensus-contrib-grpc-util | |
| [grpc-url]: https://github.com/grpc/grpc-java |