1# OpenCensus HTTP Util 2[![Build Status][travis-image]][travis-url] 3[![Windows Build Status][appveyor-image]][appveyor-url] 4[![Maven Central][maven-image]][maven-url] 5 6The *OpenCensus HTTP Util for Java* is a collection of utilities for trace instrumentation when 7working with HTTP. 8 9## Quickstart 10 11### Add the dependencies to your project 12 13For Maven add to your `pom.xml`: 14```xml 15<dependencies> 16 <dependency> 17 <groupId>io.opencensus</groupId> 18 <artifactId>opencensus-api</artifactId> 19 <version>0.28.3</version> 20 </dependency> 21 <dependency> 22 <groupId>io.opencensus</groupId> 23 <artifactId>opencensus-contrib-http-util</artifactId> 24 <version>0.28.3</version> 25 </dependency> 26</dependencies> 27``` 28 29For Gradle add to your dependencies: 30```groovy 31compile 'io.opencensus:opencensus-api:0.28.3' 32compile 'io.opencensus:opencensus-contrib-http-util:0.28.3' 33``` 34 35## Instrumenting HTTP libraries/frameworks 36 37### customization for libraries/frameworks 38 39Users can implement `HttpExtractor` to customize what information are extracted from the HTTP 40request/response entity. 41 42If context propagation is enabled, users need to provide framework specific `TextFormat.Setter` 43and `TextFormat.Getter`. They are used to inject/extract information into/from the `Carrier` of 44the request. The `Carrier` can be the request itself or other objects, as long as it provides 45functionalities of setting/getting HTTP attributes. 46 47Below is an example of how the customization for libraries/frameworks should be done: 48 49```java 50// // Http request entity in the library/framework. 51// public class HttpRequest { 52// ... 53// } 54// 55// // Http response entity in the library/framework. 56// public class HttpResponse { 57// ... 58// } 59 60// use the HttpRequest itself as Carrier. 61TextFormat.Setter<HttpRequest> myTextFormatSetter = 62 new TextFormat.Setter<HttpRequest>() { 63 @Override 64 public void put(HttpRequest carrier, String key, String value) { 65 carrier.setHeader(key, value); 66 } 67 }; 68TextFormat.Getter<HttpRequest> myTextFormatGetter = 69 new TextFormat.Getter<HttpRequest>() { 70 @Override 71 public String get(HttpRequest carrier, String key) { 72 return carrier.getHeader(key); 73 } 74 }; 75HttpExtractor<HttpRequest, HttpResponse> extractor = 76 new HttpExtractor<HttpRequest, HttpResponse>() { 77 @Override 78 public Integer getStatusCode(HttpResponse response) { 79 return response.getStatusCode(); 80 } 81 82 // other methods that need to be overridden 83 // ... 84 }; 85``` 86 87### Client 88 89Users can create a `HttpClientHandler` to help instrument client-side HTTP request/response. 90 91An example usage of the handler would be: 92 93```java 94HttpClientHandler<HttpRequest, HttpResponse, HttpRequest> handler = 95 new HttpClientHandler<HttpRequest, HttpResponse>( 96 tracer, extractor, myTextFormat, myTextFormatSetter); 97 98// Use #handleStart in client to start a new span. 99// Use `null` if you want to use current Span as the parent Span. 100HttpRequestContext context = handler.handleStart(null, request, request); 101HttpResponse response = null; 102Throwable error = null; 103try { 104 // Do something to send the request, and get response code from the server 105 response = getResponse(request); 106 107 // Optionally, use #handleMessageSent in client to log a SENT event and its size. 108 handler.handleMessageSent(context, request.getContentLength()); 109 110 // Optionally, use #handleMessageReceived in client to log a RECEIVED event and message size. 111 handler.handleMessageReceived(context, response.getContentLength()); 112} catch (Throwable e) { 113 error = e; 114} finally { 115 // Use #handleEnd in client to close the span. 116 handler.handleEnd(context, request, response, error); 117} 118``` 119 120### Server 121 122Users can create a `HttpServerHandler` to help instrument server-side HTTP request/response. 123 124An example usage of the handler would be: 125 126```java 127HttpServerHandler<HttpRequest, HttpResponse> handler = 128 new HttpServerHandler<HttpRequest, HttpResponse, HttpRequest>( 129 tracer, extractor, myTextFormat, myTextFormatGetter, 130 false /* true if it is public endpoint */); 131 132// Use #handleStart in server to start a new span. 133HttpRequestContext context = handler.handleStart(request, request); 134HttpResponse response = constructResponse(); 135Throwable error = null; 136try (Scope scope = tracer.withSpan(handler.getSpanFromContext(context))) { 137 // Do something to decide whether to serve the request or early exit. 138 // For example, client may expect a 100 Continue before sending the message body. 139 if (extractor.getRequestSize(request) > REQUEST_LIMIT) { 140 response.setStatus(413); 141 } else { 142 response.setStatus(100); 143 String content = request.getContent(); 144 145 // Optionally, use #handleMessageReceived in server to log a RECEIVED event and its size. 146 handler.handleMessageReceived(context, request.getContentLength()); 147 148 // Do something to prepare the response or exception. 149 response.setStatus(201); 150 response.write("OK"); 151 response.flush(); 152 153 // Optionally, use #handleMessageSent in server to log a SENT message event and its message size. 154 handler.handleMessageSent(context, response.getContentLength()); 155 } catch (Throwable e) { 156 error = e; 157 } finally { 158 // Use #handleEnd in server to close the span. 159 handler.handleEnd(context, request, response, error); 160 } 161} 162``` 163 164### handling async calls 165 166In asynchronous HTTP calls, message receiving and sending may happen in different 167threads. Users need to ensure the started span (as well as scope, if any) is 168closed or ended no matter the call is successful or not. 169 170To do that, store current scope and span somewhere, e.g. the context of the channel, 171and close them before the channel exits. 172 173[travis-image]: https://travis-ci.org/census-instrumentation/opencensus-java.svg?branch=master 174[travis-url]: https://travis-ci.org/census-instrumentation/opencensus-java 175[appveyor-image]: https://ci.appveyor.com/api/projects/status/hxthmpkxar4jq4be/branch/master?svg=true 176[appveyor-url]: https://ci.appveyor.com/project/opencensusjavateam/opencensus-java/branch/master 177[maven-image]: https://maven-badges.herokuapp.com/maven-central/io.opencensus/opencensus-contrib-grpc-util/badge.svg 178[maven-url]: https://maven-badges.herokuapp.com/maven-central/io.opencensus/opencensus-contrib-grpc-util 179[grpc-url]: https://github.com/grpc/grpc-java 180