Please take the OpenCensus user survey

Client

Introduction

OpenCensus provides a package go.opencensus.io/plugin/ochttp which has a custom HTTP roundtripper ochttp.Transport that can wrap your HTTP Transport. For example

package main

import (
	"net/http"

	"go.opencensus.io/plugin/ochttp"
)

func main() {
	octr := &ochttp.Transport{}
	client := &http.Client{Transport: octr}
	// Use the client
	_ = client
}

When chaining multiple Transports, please make sure that the ochttp.Transport.Base is the out-most Transport

package main

import (
	"net/http"

	"go.opencensus.io/plugin/ochttp"
)

func main() {
	octr := &ochttp.Transport{Base: &http.Transport{}}
	client := &http.Client{Transport: octr}
	// Use the client
	_ = client
}

Traces

Traces can be continued and used simply by passing the context that contains traces into the request that will then be used to roundtrip the request

package main

import (
	"context"
	"io"
	"io/ioutil"
	"log"
	"net/http"

	"go.opencensus.io/plugin/ochttp"
)

func main() {
	ctx := context.Background() // In other usages, the context would have been passed down after starting some traces.
	req, _ := http.NewRequest("GET", "https://opencensus.io/", nil)

	// It is imperative that req.WithContext is used to
	// propagate context and use it in the request.
	req = req.WithContext(ctx)

	client := &http.Client{Transport: &ochttp.Transport{}}
	res, err := client.Do(req)
	if err != nil {
		log.Fatalf("Failed to make the request: %v", err)
	}

	// Consume the body and close it.
	io.Copy(ioutil.Discard, res.Body)
	_ = res.Body.Close()
}

To examine the traces, please make sure to enable a Trace exporter that will send the data to a Tracing backend.

Metrics

Metrics can be enabled by simply registering the ochttp.DefaultClientViews

        // In our main, register ochttp Client views
        if err := view.Register(ochttp.DefaultClientViews...); err != nil {
                log.Fatalf("Failed to register client views for HTTP metrics: %v", err)
        }

To examine the metrics, please make sure to enable a Stats exporter that will send the data to a Metrics backend.

which provide the following metrics

Metric Prefix Description Tags Aggregation
Requests completed “opencensus.io/http/client/completed_count” The number of requests made “http_client_method”, “http_client_status” Count
Bytes sent “opencensus.io/http/client/sent_bytes” The number of bytes sent “http_client_method”, “http_client_status” Distribution
Bytes received “opencensus.io/http/client/received_bytes” The number of bytes received “http_client_method”, “http_client_status” Distribution
Roundtrip Latency “opencensus.io/http/client/roundtrip_latency” The end-to-end latency “http_client_method”, “http_client_status” Distribution

End to end example

The following example uses the ochttp.Transport to make requests to the OpenCensus website every 5 seconds and exports traces and metrics with our Zipkin trace and Prometheus stats respectively. Of course you can use any other exporters of your choice

For assistance setting up any of the exporters, please refer to:

Exporter URL
Prometheus Prometheus codelab
Zipkin Zipkin codelab
package main

import (
	"context"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"time"

	openzipkin "github.com/openzipkin/zipkin-go"
	zipkinHTTP "github.com/openzipkin/zipkin-go/reporter/http"

	"go.opencensus.io/exporter/prometheus"
	"go.opencensus.io/exporter/zipkin"
	"go.opencensus.io/plugin/ochttp"
	"go.opencensus.io/stats/view"
	"go.opencensus.io/trace"
)

func main() {
	// Firstly, we'll register ochttp Client views
	if err := view.Register(ochttp.DefaultClientViews...); err != nil {
		log.Fatalf("Failed to register client views for HTTP metrics: %v", err)
	}

	// For tracing, let's always sample for the purposes of this demo
	trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()})

	// Enable observability to extract and examine traces and metrics.
	enableObservabilityAndExporters()

	// Create our HTTP client that uses the ochttp.Transport.
	client := &http.Client{Transport: &ochttp.Transport{}}
	i := uint64(0)

	// Then finally do the work every 5 seconds.
	for {
		i += 1
		log.Printf("Performing fetch #%d", i)
		ctx, span := trace.StartSpan(context.Background(), fmt.Sprintf("Fetch-%d", i))
		doWork(ctx, client)
		span.End()

		<-time.After(5 * time.Second)
	}
}

func doWork(ctx context.Context, client *http.Client) {
	req, _ := http.NewRequest("GET", "https://opencensus.io/", nil)

	// It is imperative that req.WithContext is used to
	// propagate context and use it in the request.
	req = req.WithContext(ctx)

	// Now make the request to the remote end.
	res, err := client.Do(req)
	if err != nil {
		log.Printf("Failed to make the request: %v", err)
		return
	}

	// Consume the body and close it.
	io.Copy(ioutil.Discard, res.Body)
	_ = res.Body.Close()

}

func enableObservabilityAndExporters() {
	// Stats exporter: Prometheus
	pe, err := prometheus.NewExporter(prometheus.Options{
		Namespace: "ochttp_tutorial",
	})
	if err != nil {
		log.Fatalf("Failed to create the Prometheus stats exporter: %v", err)
	}

	view.RegisterExporter(pe)
	go func() {
		mux := http.NewServeMux()
		mux.Handle("/metrics", pe)
		log.Fatal(http.ListenAndServe(":8888", mux))
	}()

	// Trace exporter: Zipkin
	localEndpoint, _ := openzipkin.NewEndpoint("ochttp_tutorial", "localhost:0")
	reporter := zipkinHTTP.NewReporter("http://localhost:9411/api/v2/spans")
	ze := zipkin.NewExporter(reporter, localEndpoint)
	trace.RegisterExporter(ze)
}

and to run the example

go run main.go

and then start Prometheus with this configuration file prometheus.yaml with

scrape_configs:
  - job_name: 'ochttp_tutorial'

    scrape_interval: 10s

    static_configs:
      - targets: ['localhost:8888']

by running

prometheus --config.file=prometheus.yaml

Viewing traces

On navigating to the Zipkin UI at http://localhost:9411/zipkin

Viewing metrics

On navigating to the Prometheus UI at http://localhost:9090/graph

References

Resource URL
ochttp.Transport GoDoc https://godoc.org/go.opencensus.io/plugin/ochttp
ochttp.DefaultClientViews https://godoc.org/go.opencensus.io/plugin/ochttp#DefaultClientViews
net/http Godoc https://golang.org/pkg/net/http