Skip to content

Commit

Permalink
Add OpenCensus tracing instrument.
Browse files Browse the repository at this point in the history
  • Loading branch information
HailongWen authored and mattwhisenhunt committed Jan 29, 2018
1 parent d2d73b1 commit 2f67205
Show file tree
Hide file tree
Showing 4 changed files with 386 additions and 0 deletions.
10 changes: 10 additions & 0 deletions google-http-client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -164,5 +164,15 @@
<artifactId>commons-codec</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.opencensus</groupId>
<artifactId>opencensus-api</artifactId>
<version>0.11.1</version>
</dependency>
<dependency>
<groupId>io.opencensus</groupId>
<artifactId>opencensus-contrib-http-util</artifactId>
<version>0.11.1</version>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,16 @@
import com.google.api.client.util.IOUtils;
import com.google.api.client.util.LoggingStreamingContent;
import com.google.api.client.util.ObjectParser;
import com.google.api.client.util.OpenCensusUtils;
import com.google.api.client.util.Preconditions;
import com.google.api.client.util.Sleeper;
import com.google.api.client.util.StreamingContent;
import com.google.api.client.util.StringUtils;

import io.opencensus.common.Scope;
import io.opencensus.trace.Span;
import io.opencensus.trace.Tracer;

import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.Callable;
Expand Down Expand Up @@ -210,6 +215,12 @@ static String executeAndGetValueOfSomeCustomHeader(HttpRequest request) {
/** Sleeper. */
private Sleeper sleeper = Sleeper.DEFAULT;

/** OpenCensus tracing component. */
private Tracer tracer = OpenCensusUtils.getTracer();

/** Prefix for tracing span name. */
private static final String traceSpanNamePrefix = "Sent." + HttpRequest.class.getName() + ".";

/**
* @param transport HTTP transport
* @param requestMethod HTTP request method or {@code null} for none
Expand Down Expand Up @@ -854,7 +865,9 @@ public HttpResponse execute() throws IOException {
Preconditions.checkNotNull(requestMethod);
Preconditions.checkNotNull(url);

Span span = tracer.spanBuilder(traceSpanNamePrefix + "execute").startSpan();
do {
span.addAnnotation("retry #" + numRetries);
// Cleanup any unneeded response from a previous iteration
if (response != null) {
response.ignore();
Expand Down Expand Up @@ -898,6 +911,8 @@ public HttpResponse execute() throws IOException {
headers.setUserAgent(originalUserAgent + " " + USER_AGENT_SUFFIX);
}
}
OpenCensusUtils.propagateTracingContext(headers);

// headers
HttpHeaders.serializeHeaders(headers, logbuf, curlbuf, logger, lowLevelHttpRequest);
if (!suppressUserAgentSuffix) {
Expand Down Expand Up @@ -977,6 +992,8 @@ public HttpResponse execute() throws IOException {

// execute
lowLevelHttpRequest.setTimeout(connectTimeout, readTimeout);
// switch tracing scope to current span
Scope ws = tracer.withSpan(span);
try {
LowLevelHttpResponse lowLevelHttpResponse = lowLevelHttpRequest.execute();
// Flag used to indicate if an exception is thrown before the response is constructed.
Expand All @@ -1002,6 +1019,8 @@ public HttpResponse execute() throws IOException {
if (loggable) {
logger.log(Level.WARNING, "exception thrown while executing request", e);
}
} finally {
ws.close();
}

// Flag used to indicate if an exception is thrown before the response has completed
Expand Down Expand Up @@ -1057,6 +1076,7 @@ public HttpResponse execute() throws IOException {
}
}
} while (retryRequest);
span.end(OpenCensusUtils.getEndSpanOptions(response == null ? null : response.getStatusCode()));

if (response == null) {
// Retries did not help resolve the execute exception, re-throw it.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
/*
* Copyright (c) 2018 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/

package com.google.api.client.util;

import com.google.api.client.http.HttpHeaders;
import com.google.api.client.http.HttpResponse;
import com.google.api.client.http.HttpStatusCodes;

import io.opencensus.contrib.http.util.HttpPropagationUtil;
import io.opencensus.trace.BlankSpan;
import io.opencensus.trace.EndSpanOptions;
import io.opencensus.trace.Span;
import io.opencensus.trace.Status;
import io.opencensus.trace.Tracer;
import io.opencensus.trace.Tracing;
import io.opencensus.trace.propagation.TextFormat;

import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Nullable;

/**
* Utilities for Census monitoring and tracing.
*
* @since 1.24
* @author Hailong Wen
*/
public class OpenCensusUtils {

private static final Logger LOGGER = Logger.getLogger(OpenCensusUtils.class.getName());

/**
* OpenCensus tracing component.
* When no OpenCensus implementation is provided, it will return a no-op tracer.
*/
static Tracer tracer = Tracing.getTracer();

/**
* {@link TextFormat} used in tracing context propagation.
*/
@Nullable
static TextFormat propagationTextFormat = null;

/**
* {@link TextFormat.Setter} for {@link activeTextFormat}.
*/
@Nullable
static TextFormat.Setter propagationTextFormatSetter = null;

/**
* Sets the {@link TextFormat} used in context propagation.
* @param textFormat the text format.
*/
public static void setPropagationTextFormat(@Nullable TextFormat textFormat) {
propagationTextFormat = textFormat;
}

/**
* Sets the {@link TextFormat.Setter} used in context propagation.
* @param textFormatSetter the {@code TextFormat.Setter} for the text format.
*/
public static void setPropagationTextFormatSetter(@Nullable TextFormat.Setter textFormatSetter) {
propagationTextFormatSetter = textFormatSetter;
}

/**
* Returns the tracing component of OpenCensus.
*
* @return the tracing component of OpenCensus.
*/
public static Tracer getTracer() {
return tracer;
}

/**
* Propagate information of current tracing context. This information will be injected into HTTP
* header.
*/
public static void propagateTracingContext(HttpHeaders headers) {
Preconditions.checkNotNull(headers);
if (propagationTextFormat != null && propagationTextFormatSetter != null) {
Span span = tracer.getCurrentSpan();
if (span != null && !span.equals(BlankSpan.INSTANCE)) {
propagationTextFormat.inject(span.getContext(), headers, propagationTextFormatSetter);
}
}
}

/**
* Returns an {@link EndSpanOptions} to end a http span according to the status code.
*
* @param statusCode the status code, can be null to represent no valid response is returned.
* @return an {@code EndSpanOptions} that best suits the status code.
*/
public static EndSpanOptions getEndSpanOptions(@Nullable Integer statusCode) {
// Always sample the span, but optionally export it.
EndSpanOptions.Builder builder = EndSpanOptions.builder().setSampleToLocalSpanStore(true);
if (statusCode == null) {
builder.setStatus(Status.UNKNOWN);
} else if (!HttpStatusCodes.isSuccess(statusCode)) {
switch (statusCode) {
case HttpStatusCodes.STATUS_CODE_BAD_REQUEST:
builder.setStatus(Status.INVALID_ARGUMENT);
break;
case HttpStatusCodes.STATUS_CODE_UNAUTHORIZED:
builder.setStatus(Status.UNAUTHENTICATED);
break;
case HttpStatusCodes.STATUS_CODE_FORBIDDEN:
builder.setStatus(Status.PERMISSION_DENIED);
break;
case HttpStatusCodes.STATUS_CODE_NOT_FOUND:
builder.setStatus(Status.NOT_FOUND);
break;
case HttpStatusCodes.STATUS_CODE_PRECONDITION_FAILED:
builder.setStatus(Status.FAILED_PRECONDITION);
break;
case HttpStatusCodes.STATUS_CODE_SERVER_ERROR:
builder.setStatus(Status.UNAVAILABLE);
break;
default:
builder.setStatus(Status.UNKNOWN);
}
} else {
builder.setStatus(Status.OK);
}
return builder.build();
}

static {
try {
propagationTextFormat = HttpPropagationUtil.getCloudTraceFormat();
propagationTextFormatSetter = new TextFormat.Setter<HttpHeaders>() {
@Override
public void put(HttpHeaders carrier, String key, String value) {
carrier.set(key, value);
}
};
} catch (Exception e) {
LOGGER.log(Level.WARNING, "Cannot initiate OpenCensus modules, tracing disabled", e);
}
}

private OpenCensusUtils() {}
}
Loading

0 comments on commit 2f67205

Please sign in to comment.