224 lines
8.3 KiB
Markdown
224 lines
8.3 KiB
Markdown
# HTTP Trace
|
|
|
|
This document explains tracing of HTTP requests with OpenCensus.
|
|
|
|
## Spans
|
|
|
|
Implementations MUST create a span for outgoing requests at the client and a span for incoming
|
|
requests at the server.
|
|
|
|
Span name is formatted as:
|
|
|
|
* /$path for outgoing requests.
|
|
* /($path|$route) for incoming requests.
|
|
|
|
If route cannot be determined, path is used to name the the span for outgoing requests.
|
|
|
|
Port MUST be omitted if it is 80 or 443.
|
|
|
|
Examples of span names:
|
|
|
|
* /users
|
|
* /messages/[:id]
|
|
* /users/25f4c31d
|
|
|
|
Outgoing requests should be a span kind of CLIENT and
|
|
incoming requests should be a span kind of SERVER.
|
|
|
|
## Propagation
|
|
|
|
Propagation is how SpanContext is transmitted on the wire in an HTTP request.
|
|
|
|
Implementations MUST allow users to set their own propagation format and MUST provide an
|
|
implementation for [B3](https://github.com/openzipkin/b3-propagation/blob/master/README.md#http-encodings)
|
|
and [TraceContext](https://w3c.github.io/trace-context/) at least.
|
|
|
|
If user doesn't set any propagation methods explicitly, TraceContext is used.
|
|
|
|
> In a previous version of this spec, we recommended that B3 be the default. For backwards compatibility,
|
|
implementations may provide a way for users to "opt in" to the new default explicitly, to
|
|
avoid a silent change to defaults that could break existing deployments.
|
|
|
|
The propagation method SHOULD modify a request object to insert a SpanContext or SHOULD be able
|
|
to extract a SpanContext from a request object.
|
|
|
|
## Status
|
|
|
|
Implementations MUST set status if HTTP request or response is not successful (e.g. not 2xx). In
|
|
redirection case, if the client doesn't have autoredirection support, request should be
|
|
considered successful.
|
|
|
|
Set status code to UNKNOWN (2) if the reason cannot be inferred at the callsite or from the HTTP
|
|
status code.
|
|
|
|
Don't set the status message if the reason can be inferred at the callsite of from the HTTP
|
|
status code.
|
|
|
|
### Mapping from HTTP status codes to Trace status codes
|
|
|
|
| HTTP code | Trace status code |
|
|
|-----------------------|------------------------|
|
|
| 0...199 | 2 (UNKNOWN) |
|
|
| 200...399 | 0 (OK) |
|
|
| 400 Bad Request | 3 (INVALID_ARGUMENT) |
|
|
| 504 Gateway Timeout | 4 (DEADLINE_EXCEEDED) |
|
|
| 404 Not Found | 5 (NOT_FOUND) |
|
|
| 403 Forbidden | 7 (PERMISSION_DENIED) |
|
|
| 401 Unauthorized* | 16 (UNAUTHENTICATED) |
|
|
| 429 Too Many Requests | 8 (RESOURCE_EXHAUSTED) |
|
|
| 501 Not Implemented | 12 (UNIMPLEMENTED) |
|
|
| 503 Unavailable | 14 (UNAVAILABLE) |
|
|
|
|
Notes: 401 Unauthorized actually means unauthenticated according to RFC 7235, 3.1.
|
|
|
|
The Status message should be the Reason-Phrase (RFC 2616 6.1.1) from the
|
|
response status line (if available).
|
|
|
|
### Client errors for client HTTP calls
|
|
|
|
There are a number of client errors when trying to access http endpoint. Here
|
|
are examples of mapping those to the OpenCensus status codes.
|
|
|
|
| Client error | Trace status code |
|
|
|------------------------------|-----------------------|
|
|
| DNS resolution failed | 2 (UNKNOWN) |
|
|
| Request cancelled by caller | 1 (CANCELLED) |
|
|
| URL cannot be parsed | 3 (INVALID_ARGUMENT) |
|
|
| Request timed out | 1 (DEADLINE_EXCEEDED) |
|
|
|
|
## Message events
|
|
|
|
In the lifetime of an incoming and outgoing request, the following message events SHOULD be created:
|
|
|
|
* A message event for the request body size if/when determined.
|
|
* A message event for the response size if/when determined.
|
|
|
|
Implementations SHOULD create message event when body size is determined.
|
|
|
|
```
|
|
-> [time], MessageEventTypeSent, UncompressedByteSize, CompressedByteSize
|
|
```
|
|
|
|
Implementations SHOULD create message event when response size is determined.
|
|
|
|
```
|
|
-> [time], MessageEventTypeRecv, UncompressedByteSize, CompressedByteSize
|
|
```
|
|
|
|
## Attributes
|
|
|
|
Implementations SHOULD set the following attributes on the client and server spans. For a server,
|
|
request represents the incoming request. For a client, request represents the outgoing request.
|
|
|
|
All attributes are optional, but collector should make the best effort to
|
|
collect those.
|
|
|
|
> Work in progress! Please note, that the list below only contains attributes that aren't contained in the [OpenTelemetry main spec](../semantic-conventions.md) (yet):
|
|
|
|
| Attribute name | Description | Type |Example value |
|
|
|---------------------------|-----------------------------|--------|---------------------------|
|
|
| "http.host" | Request URL host | string | `example.com:779` |
|
|
| "http.path" | Request URL path. If empty - set to `/` | `/users/25f4c31d` |
|
|
| "http.user_agent" | Request user-agent. Do not inject attribute if user-agent is empty. | string | `HTTPClient/1.2` | |
|
|
|
|
|
|
Exporters should always export the collected attributes. Exporters should map the collected
|
|
attributes to backend's known attributes/labels.
|
|
|
|
The following table summarizes how OpenCensus attributes maps to the
|
|
known attributes/labels on supported tracing backends.
|
|
|
|
| OpenCensus attribute | Zipkin | Jaeger | Stackdriver Trace label |
|
|
|---------------------------|--------------------|--------------------|---------------------------|
|
|
| "http.host" | "http.host" | "http.host" | "/http/host" |
|
|
| "http.method" | "http.method" | "http.method" | "/http/method" |
|
|
| "http.path" | "http.path" | "http.path" | "/http/path" |
|
|
| "http.route" | "http.route" | "http.route" | "/http/route" |
|
|
| "http.user_agent" | "http.user_agent" | "http.user_agent" | "/http/user_agent" |
|
|
| "http.status_code" | "http.status_code" | "http.status_code" | "/http/status_code" |
|
|
| "http.url" | "http.url" | "http.url" | "/http/url" |
|
|
|
|
References:
|
|
|
|
- [Stackdriver Trace
|
|
label](https://cloud.google.com/trace/docs/reference/v1/rest/v1/projects.traces)
|
|
- [Jaeger/Open Tracing](https://github.com/opentracing/specification/blob/master/semantic_conventions.md)
|
|
- [Zipkin](https://github.com/openzipkin/zipkin-api/blob/master/thrift/zipkinCore.thrift)
|
|
|
|
## Test Cases
|
|
|
|
Test cases for outgoing http calls are in the file
|
|
[http-out-test-cases.json](http-out-test-cases.json).
|
|
|
|
File consists of a set of test cases. Each test case represents outgoing http
|
|
call, response it receives and the resulting span properties. It looks like
|
|
this:
|
|
|
|
``` json
|
|
{
|
|
"name": "Name is populated as a path",
|
|
"method": "GET",
|
|
"url": "http://{host}:{port}/path/to/resource/",
|
|
"headers": {
|
|
"User-Agent": "test-user-agent"
|
|
},
|
|
"responseCode": 200,
|
|
"spanName": "/path/to/resource/",
|
|
"spanStatus": "OK",
|
|
"spanKind": "Client",
|
|
"spanAttributes": {
|
|
"http.path": "/path/to/resource/",
|
|
"http.method": "GET",
|
|
"http.host": "{host}:{port}",
|
|
"http.status_code": "200",
|
|
"http.user_agent": "test-user-agent"
|
|
}
|
|
}
|
|
```
|
|
|
|
Where `name` is the name of the test case. Properties `method`, `url` and
|
|
`headers` collection represents the outgoing call. The field `responseCode`
|
|
describes the response status code.
|
|
|
|
The rest of the properties describe the span details of the resulting span -
|
|
it's name, kind, status and attributes.
|
|
|
|
## Sampling
|
|
|
|
There are two ways to control the `Sampler` used:
|
|
* Controlling the global default `Sampler` via [TraceConfig](https://github.com/census-instrumentation/opencensus-specs/blob/master/trace/TraceConfig.md).
|
|
* Pass a specific `Sampler` as an option to the HTTP plugin. Plugins should support setting
|
|
a sampler per HTTP request.
|
|
|
|
Example cases where per-request sampling is useful:
|
|
|
|
- Having different sampling policy per route
|
|
- Having different sampling policy per method
|
|
- Filtering out certain paths (e.g. health endpoints) to disable tracing
|
|
- Always sampling critical paths
|
|
- Sampling based on the custom request header or query parameter
|
|
|
|
In the following Go example, incoming and outgoing request objects can
|
|
dynamically inspected to set a sampler.
|
|
|
|
For outgoing requests:
|
|
|
|
```go
|
|
type Transport struct {
|
|
// GetStartOptions allows to set start options per request.
|
|
GetStartOptions func(*http.Request) trace.StartOptions
|
|
|
|
// ...
|
|
}
|
|
```
|
|
|
|
For incoming requests:
|
|
|
|
```go
|
|
type Handler struct {
|
|
// GetStartOptions allows to set start options per request.
|
|
GetStartOptions func(*http.Request) trace.StartOptions
|
|
|
|
// ...
|
|
}
|
|
``` |