Skip to content
Snippets Groups Projects
Unverified Commit 1f0e0f16 authored by Will McCutchen's avatar Will McCutchen Committed by GitHub
Browse files

Add example demonstrating custom instrumentation (#75)

parent 32c0e07c
No related branches found
No related tags found
No related merge requests found
......@@ -54,8 +54,8 @@ $ docker run -e HTTPS_CERT_FILE='/tmp/server.crt' -e HTTPS_KEY_FILE='/tmp/server
```
The `github.com/mccutchen/go-httpbin/httpbin/v2` package can also be used as a
library for testing an applications interactions with an upstream HTTP service,
like so:
library for testing an application's interactions with an upstream HTTP
service, like so:
```go
package httpbin_test
......@@ -87,6 +87,17 @@ func TestSlowResponse(t *testing.T) {
```
## Custom instrumentation
If you're running go-httpbin in your own infrastructure and would like custom
instrumentation (metrics, structured logging, request tracing, etc), you'll
need to wrap this package in your own code and use the included
[Observer][observer] mechanism to instrument requests as necessary.
See [examples/custom-instrumentation][custom-instrumentation] for an example
that instruments every request using DataDog.
## Installation
To add go-httpbin to an existing golang project:
......@@ -147,3 +158,5 @@ make imagepush
[httpbin-repo]: https://github.com/kennethreitz/httpbin
[ahmet]: https://github.com/ahmetb/go-httpbin
[docker-hub]: https://hub.docker.com/r/mccutchen/go-httpbin/
[observer]: https://pkg.go.dev/github.com/mccutchen/go-httpbin/v2/httpbin#Observer
[custom-instrumentation]: ./examples/custom-instrumentation/
# Custom Instrumentation
This example demonstrates how to use go-httpbin's [`Observer`][1] mechanism to
add custom instrumentation to a go-httpbin instance.
An _observer_ is a function that will be called with an [`httpbin.Result`][2]
struct after every request, which provides a hook for custom logging, metrics,
or other instrumentation.
Note: This does require building your own small wrapper around go-httpbin, as
you can see in [main.go](./main.go) here. That's because go-httpbin has no
dependencies outside of the Go stdlib, to make sure that it is as
safe/lightweight as possible to include as a dependency in other applications'
test suites where useful.
[1]: https://pkg.go.dev/github.com/mccutchen/go-httpbin/v2/httpbin#Observer
[2]: https://pkg.go.dev/github.com/mccutchen/go-httpbin/v2/httpbin#Result
module httpbin-instrumentation
go 1.18
require (
github.com/DataDog/datadog-go v4.8.3+incompatible
github.com/mccutchen/go-httpbin/v2 v2.3.0
)
require (
github.com/Microsoft/go-winio v0.5.2 // indirect
github.com/stretchr/objx v0.3.0 // indirect
github.com/stretchr/testify v1.3.0 // indirect
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c // indirect
)
github.com/DataDog/datadog-go v4.8.3+incompatible h1:fNGaYSuObuQb5nzeTQqowRAd9bpDIRRV4/gUtIBjh8Q=
github.com/DataDog/datadog-go v4.8.3+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA=
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/mccutchen/go-httpbin/v2 v2.3.0 h1:NqVqPVI8Ushb/YJIe9bXiruBl0CDBSvp7BQSPXrY5qs=
github.com/mccutchen/go-httpbin/v2 v2.3.0/go.mod h1:+DBHcmg6EOeoizuiOI8iL12VIHXx+9YQNlz+gjB9uxk=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.3.0 h1:NGXK3lHquSN08v5vWalVI/L8XU9hdzE/G6xsrze47As=
github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
package main
import (
"fmt"
"log"
"net/http"
"github.com/DataDog/datadog-go/statsd"
"github.com/mccutchen/go-httpbin/v2/httpbin"
)
func main() {
statsdClient, _ := statsd.New("")
h := httpbin.New(
httpbin.WithObserver(datadogObserver(statsdClient)),
)
listenAddr := "0.0.0.0:8080"
http.ListenAndServe(listenAddr, h.Handler())
}
func datadogObserver(client statsd.ClientInterface) httpbin.Observer {
return func(result httpbin.Result) {
// Log the request
log.Printf("%d %s %s %s", result.Status, result.Method, result.URI, result.Duration)
// Submit a new distribution metric to datadog with tags that allow
// graphing request rate, timing, errors broken down by
// method/status/path.
tags := []string{
fmt.Sprintf("method:%s", result.Method),
fmt.Sprintf("status_code:%d", result.Status),
fmt.Sprintf("status_class:%dxx", result.Status/100),
fmt.Sprintf("uri:%s", result.URI),
}
client.Distribution("httpbin.request", float64(result.Duration.Milliseconds()), tags, 1.0)
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment