Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Sergei Malafeev <sergeymalafeev@gmail.com>
- Loading branch information
Showing
6 changed files
with
277 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
# Binaries for programs and plugins | ||
*.exe | ||
*.exe~ | ||
*.dll | ||
*.so | ||
*.dylib | ||
|
||
# Test binary, build with `go test -c` | ||
*.test | ||
|
||
# Output of the go coverage tool, specifically when used with LiteIDE | ||
*.out |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,46 @@ | ||
# go-aws | ||
[![Apache-2.0 license](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) | ||
|
||
# OpenTracing support for AWS SDK in Go | ||
|
||
The `otaws` package makes it easy to add OpenTracing support for AWS SDK in Go. | ||
|
||
## Installation | ||
|
||
``` | ||
go get github.com/opentracing-contrib/go-aws | ||
``` | ||
|
||
## Documentation | ||
|
||
See the basic usage examples below and the [package documentation on | ||
godoc.org](https://godoc.org/github.com/opentracing-contrib/go-aws). | ||
|
||
## Usage | ||
|
||
```go | ||
// You must have some sort of OpenTracing Tracer instance on hand | ||
var tracer opentracing.Tracer = ... | ||
|
||
// Optionally set Tracer as global | ||
opentracing.SetGlobalTracer(tracer) | ||
|
||
// Create AWS Session | ||
sess := session.NewSession(...) | ||
|
||
// Create AWS service client e.g. DynamoDB client | ||
dbCient := dynamodb.New(sess) | ||
|
||
// Add OpenTracing handlers using global tracer | ||
AddOTHandlers(dbClient.Client) | ||
|
||
// Or specify tracer explicitly | ||
AddOTHandlers(dbClient.Client, WithTracer(tracer)) | ||
|
||
// Call AWS client | ||
result, err := dbClient.ListTables(&dynamodb.ListTablesInput{}) | ||
|
||
``` | ||
|
||
## License | ||
|
||
[Apache 2.0 License](./LICENSE). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package otaws | ||
|
||
import ( | ||
"github.com/aws/aws-sdk-go/aws/client" | ||
"github.com/aws/aws-sdk-go/aws/request" | ||
"github.com/opentracing/opentracing-go" | ||
"github.com/opentracing/opentracing-go/ext" | ||
"github.com/opentracing/opentracing-go/log" | ||
"net/http" | ||
) | ||
|
||
func AddOTHandlers(cl *client.Client, opts ...Option) { | ||
c := defaultConfig() | ||
for _, opt := range opts { | ||
opt(c) | ||
} | ||
|
||
handler := otHandler(c) | ||
cl.Handlers.Build.PushFront(handler) | ||
} | ||
|
||
func otHandler(c *config) func(*request.Request) { | ||
tracer := c.tracer | ||
|
||
return func(r *request.Request) { | ||
sp := tracer.StartSpan(r.Operation.Name) | ||
ext.SpanKindRPCClient.Set(sp) | ||
ext.Component.Set(sp, "go-aws") | ||
ext.HTTPMethod.Set(sp, r.Operation.HTTPMethod) | ||
ext.HTTPUrl.Set(sp, r.HTTPRequest.URL.String()) | ||
ext.PeerService.Set(sp, r.ClientInfo.ServiceName) | ||
|
||
_ = inject(tracer, sp, r.HTTPRequest.Header) | ||
|
||
r.Handlers.Complete.PushBack(func(req *request.Request) { | ||
if req.HTTPResponse != nil { | ||
ext.HTTPStatusCode.Set(sp, uint16(req.HTTPResponse.StatusCode)) | ||
} else { | ||
ext.Error.Set(sp, true) | ||
} | ||
sp.Finish() | ||
}) | ||
|
||
r.Handlers.Retry.PushBack(func(req *request.Request) { | ||
sp.LogFields(log.String("event", "retry")) | ||
}) | ||
} | ||
} | ||
|
||
func inject(tracer opentracing.Tracer, span opentracing.Span, header http.Header) error { | ||
return tracer.Inject(span.Context(), opentracing.HTTPHeaders, opentracing.HTTPHeadersCarrier(header)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
package otaws | ||
|
||
import ( | ||
"errors" | ||
"github.com/aws/aws-sdk-go/aws" | ||
"github.com/aws/aws-sdk-go/aws/credentials" | ||
"github.com/aws/aws-sdk-go/aws/request" | ||
"github.com/aws/aws-sdk-go/aws/session" | ||
"github.com/aws/aws-sdk-go/awstesting/mock" | ||
"github.com/aws/aws-sdk-go/service/dynamodb" | ||
"github.com/opentracing/opentracing-go" | ||
"github.com/opentracing/opentracing-go/ext" | ||
"github.com/opentracing/opentracing-go/mocktracer" | ||
"strings" | ||
"testing" | ||
) | ||
|
||
// Test requires running local instance of DynamoDB | ||
func TestAWS(t *testing.T) { | ||
tracer := mocktracer.New() | ||
opentracing.InitGlobalTracer(tracer) | ||
|
||
client := mock.NewMockClient(&aws.Config{ | ||
Region: aws.String("us-west-2"), | ||
}) | ||
|
||
AddOTHandlers(client) | ||
|
||
req := client.NewRequest(&request.Operation{ | ||
Name: "Test Operation", | ||
HTTPMethod: "POST", | ||
HTTPPath: "/foo/bar", | ||
}, nil, nil) | ||
|
||
err := req.Send() | ||
if err != nil { | ||
t.Fatal("Expected request to succeed but failed:", err) | ||
} | ||
|
||
spans := tracer.FinishedSpans() | ||
|
||
if numSpans := len(spans); numSpans != 1 { | ||
t.Fatalf("Expected 1 span but found %d spans", numSpans) | ||
} | ||
|
||
span := spans[0] | ||
|
||
if span.OperationName != "Test Operation" { | ||
t.Errorf("Expected span to have operation name 'Test Operation' but was '%s'", span.OperationName) | ||
} | ||
|
||
expectedTags := map[string]interface{}{ | ||
"span.kind": ext.SpanKindRPCClientEnum, | ||
"component": "go-aws", | ||
"http.method": "POST", | ||
"http.status_code": uint16(200), | ||
"peer.service": "Mock", | ||
} | ||
|
||
for tag, expected := range expectedTags { | ||
if actual := span.Tag(tag); actual != expected { | ||
t.Errorf("Expected tag '%s' to have value '%v' but was '%v'", tag, expected, actual) | ||
} | ||
} | ||
|
||
url, ok := span.Tag("http.url").(string) | ||
if !ok { | ||
t.Errorf("Expected span to have tag 'http.url' of type string") | ||
} | ||
if !strings.HasSuffix(url, "/foo/bar") { | ||
t.Error("Expected tag 'http.url' to end with '/foo/bar' but was", url) | ||
} | ||
} | ||
|
||
func TestNilResponse(t *testing.T) { | ||
tracer := mocktracer.New() | ||
opentracing.InitGlobalTracer(tracer) | ||
|
||
sess, err := session.NewSession(&aws.Config{ | ||
Region: aws.String("us-west-2"), | ||
Credentials: credentials.NewCredentials(credentials.ErrorProvider{ | ||
Err: errors.New("error credentials for test"), | ||
ProviderName: "test error provider", | ||
}), | ||
}) | ||
if err != nil { | ||
t.Fatal("Failed to instantiate session:", err) | ||
} | ||
|
||
dbClient := dynamodb.New(sess) | ||
|
||
AddOTHandlers(dbClient.Client) | ||
|
||
_, err = dbClient.ListTables(&dynamodb.ListTablesInput{}) | ||
if err == nil { | ||
t.Fatal("Expected error but request succeeded") | ||
} | ||
|
||
spans := tracer.FinishedSpans() | ||
if len(spans) != 1 { | ||
t.Fatalf("Expected 1 span but saw %d spans", len(spans)) | ||
} | ||
|
||
errTag, ok := spans[0].Tag("error").(bool) | ||
if !ok { | ||
t.Fatal("Expected span to have an 'error' tag of type bool") | ||
} else if errTag != true { | ||
t.Fatal("Expected span's 'error' tag to be true but was false") | ||
} | ||
} | ||
|
||
func TestNonGlobalTracer(t *testing.T) { | ||
tracer := mocktracer.New() | ||
|
||
client := mock.NewMockClient(&aws.Config{ | ||
Region: aws.String("us-west-2"), | ||
}) | ||
|
||
AddOTHandlers(client, WithTracer(tracer)) | ||
|
||
req := client.NewRequest(&request.Operation{ | ||
Name: "Test Operation", | ||
HTTPMethod: "POST", | ||
}, nil, nil) | ||
|
||
err := req.Send() | ||
if err != nil { | ||
t.Fatal("Expected request to succeed but failed:", err) | ||
} | ||
|
||
spans := tracer.FinishedSpans() | ||
|
||
if numSpans := len(spans); numSpans != 1 { | ||
t.Fatalf("Expected 1 span but found %d spans", numSpans) | ||
} | ||
|
||
span := spans[0] | ||
if span.OperationName != "Test Operation" { | ||
t.Errorf("Expected span to have operation name 'Test Operation' but was '%s'", span.OperationName) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package otaws | ||
|
||
import "github.com/opentracing/opentracing-go" | ||
|
||
type Option func(*config) | ||
|
||
func WithTracer(tracer opentracing.Tracer) Option { | ||
return func(c *config) { | ||
c.tracer = tracer | ||
} | ||
} | ||
|
||
type config struct { | ||
tracer opentracing.Tracer | ||
} | ||
|
||
func defaultConfig() *config { | ||
return &config{ | ||
tracer: opentracing.GlobalTracer(), | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
// Package otaws provides OpenTracing support for AWS SDK. | ||
// | ||
// See the README for simple usage examples: | ||
// https://github.com/opentracing-contrib/go-aws/README.md | ||
package otaws |