diff --git a/docker-compose.yml b/docker-compose.yml index 4e4b117..0b47dc5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,12 +7,12 @@ services: - SERVICE_BASE_URL=http://fake-service:9090/service - ENV_NAME=local - LOG_LEVEL=debug - - HTTP_CLIENT_MAX_IDLE_CONNS_PER_HOST=1 - - HTTP_CLIENT_MAX_IDLE_CONNS=1 - - HTTP_CLIENT_DIALER_TIMEOUT_MS=30000 + - HTTP_CLIENT_MAX_IDLE_CONNS_PER_HOST=100 + - HTTP_CLIENT_MAX_IDLE_CONNS=100 + - HTTP_CLIENT_DIALER_TIMEOUT_MS=500 - HTTP_CLIENT_DIALER_KEEPALIVE_MS=30000 - - HTTP_CLIENT_IDLE_CONN_TIMEOUT_MS=90000 - - HTTP_CLIENT_TLS_HANDSHAKE_TIMEOUT_MS=10000 + - HTTP_CLIENT_IDLE_CONN_TIMEOUT_MS=60000 + - HTTP_CLIENT_TLS_HANDSHAKE_TIMEOUT_MS=1000 - HTTP_CLIENT_EXPECT_CONTINUE_TIMEOUT_MS=1000 - HTTP_CLIENT_TIMEOUT_MS=1500 diff --git a/fakes/fake-service.yml b/fakes/fake-service.yml index 4326663..e327a20 100644 --- a/fakes/fake-service.yml +++ b/fakes/fake-service.yml @@ -6,7 +6,7 @@ method: POST headers: content-type: application/json - body: '{"foo":"abc","bar":"def"}' + body: '*' response: code: 200 - body: '{"qux":"flubber"}' + body: '{"uuid":"6ba7b810-9dad-11d1-80b4-00c04fd430c8","qux":"flubber"}' diff --git a/handler.go b/handler.go index fe63fb7..0c59375 100644 --- a/handler.go +++ b/handler.go @@ -4,6 +4,7 @@ import ( "fmt" log "github.com/sirupsen/logrus" "net/http" + "github.com/satori/go.uuid" ) // Handler handles requests @@ -13,10 +14,13 @@ type Handler struct { // ServeHTTP serves HTTP func (handler Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - serviceRequest := &ServiceRequest{Foo:"abc", Bar:"def"} + u1 := uuid.NewV4() + serviceRequest := &ServiceRequest{UUID: u1.String()} + log.WithField("uuid", serviceRequest.UUID).Info("About to do service.Call") serviceResponse, err := handler.Service.Call(*serviceRequest) + log.WithField("uuid", serviceRequest.UUID).Info("Got response from service.Call") if err != nil { - log.Error("Error calling service", err) + log.WithField("uuid", serviceRequest.UUID).Error("Error calling service", err) w.WriteHeader(500) return } diff --git a/service.go b/service.go index 2e8788f..45110f0 100644 --- a/service.go +++ b/service.go @@ -22,75 +22,88 @@ type HttpClient interface { } func (svc Service) Call(serviceRequest ServiceRequest) (serviceResponse ServiceResponse, err error) { - - trace := &httptrace.ClientTrace{ - GetConn: func(hostPort string) { - log.Info("About to get connection") - }, - PutIdleConn: func(err error) { - if err != nil { - log.Info(fmt.Sprintf("Put idle connection failed. err=%v", err)) - } else { - log.Info("Put idle connection succeeded.") - } - }, - Got100Continue : func() { - log.Info("Got 100 Continue") - }, - GotConn: func(connInfo httptrace.GotConnInfo) { - log.Info("Got connection") - }, - ConnectStart: func(network, addr string) { - log.Info("Dial start") - }, - DNSStart: func(info httptrace.DNSStartInfo) { - log.Info("DNS start", info.Host) - }, - DNSDone: func(info httptrace.DNSDoneInfo) { - log.Info("DNS done") - }, - ConnectDone: func(network, addr string, err error) { - log.Info("Dial done") - }, - GotFirstResponseByte: func() { - log.Info("First response byte!") - }, - WroteHeaders: func() { - log.Info("Wrote headers") - }, - WroteRequest: func(wr httptrace.WroteRequestInfo) { - log.Info("Wrote request") - }, - } var resp *http.Response - log.Info(fmt.Sprintf("About to send request: POST %s with body %s", svc.BaseURL, serviceRequest.String())) req, err := http.NewRequest("POST", svc.BaseURL, strings.NewReader(serviceRequest.String())) if err != nil { - log.Error("Error creating request to service", err) + log.WithField("uuid", serviceRequest.UUID).Error("Error creating request to service", err) return } req.Header.Set("Content-type", "application/json") - req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace)) + req = req.WithContext(httptrace.WithClientTrace(req.Context(), clientTrace(serviceRequest))) + log.WithField("uuid", serviceRequest.UUID).Info("About to send request to service") resp, err = svc.HttpClient.Do(req) if err != nil { - log.Error("Error sending request to service", err) + log.WithField("uuid", serviceRequest.UUID).Error("Error sending request to service", err) return } + defer resp.Body.Close() if resp.StatusCode != 200 { var respBody string if resp.Body != nil { respErrorBody, _ := ioutil.ReadAll(resp.Body) respBody = string(respErrorBody) - resp.Body.Close() } errorMsg := fmt.Sprintf("Request to service returned status: %d and body: %s ", resp.StatusCode, respBody) - log.Error(errorMsg) + log.WithField("uuid", serviceRequest.UUID).Error(errorMsg) return serviceResponse, errors.New(errorMsg) } err = json.NewDecoder(resp.Body).Decode(&serviceResponse) - resp.Body.Close() if err != nil { - log.Error("Error parsing response from Service.", err) + log.WithField("uuid", serviceRequest.UUID).Error("Error parsing response from Service.", err) } + serviceResponse.UUID = serviceRequest.UUID return } + +func clientTrace(serviceRequest ServiceRequest) *httptrace.ClientTrace { + return &httptrace.ClientTrace{ + GetConn: func(hostPort string) { + log.WithField("uuid", serviceRequest.UUID).Info("About to get connection") + }, + PutIdleConn: func(err error) { + log.WithFields(map[string]interface{}{ + "uuid": serviceRequest.UUID, + "err": err, + }).Info("Put idle connection") + }, + Got100Continue : func() { + log.WithField("uuid", serviceRequest.UUID).Info("Got 100 Continue") + }, + GotConn: func(connInfo httptrace.GotConnInfo) { + log.WithFields(map[string]interface{}{ + "uuid": serviceRequest.UUID, + "reused": connInfo.Reused, + "idletime": connInfo.IdleTime, + "wasidle": connInfo.WasIdle, + }).Info("Got connection") + }, + ConnectStart: func(network, addr string) { + log.WithField("uuid", serviceRequest.UUID).Info("Dial start") + }, + DNSStart: func(info httptrace.DNSStartInfo) { + log.WithField("uuid", serviceRequest.UUID).Info("DNS start", info.Host) + }, + DNSDone: func(info httptrace.DNSDoneInfo) { + log.WithFields(map[string]interface{}{ + "uuid": serviceRequest.UUID, + "coalesced": info.Coalesced, + "err": info.Err, + }).Info("DNS done") + }, + ConnectDone: func(network, addr string, err error) { + log.WithFields(map[string]interface{}{ + "uuid": serviceRequest.UUID, + "err": err, + }).Info("Dial done") + }, + GotFirstResponseByte: func() { + log.WithField("uuid", serviceRequest.UUID).Info("First response byte!") + }, + WroteHeaders: func() { + log.WithField("uuid", serviceRequest.UUID).Info("Wrote headers") + }, + WroteRequest: func(wr httptrace.WroteRequestInfo) { + log.WithField("uuid", serviceRequest.UUID).Info("Wrote request") + }, + } +} \ No newline at end of file diff --git a/servicerequest.go b/servicerequest.go index 3ac4c49..73ca23f 100644 --- a/servicerequest.go +++ b/servicerequest.go @@ -5,8 +5,7 @@ import ( ) type ServiceRequest struct { - Foo string `json:"foo,omitempty"` - Bar string `json:"bar,omitempty"` + UUID string `json:"uuid,omitempty"` } func (req ServiceRequest) String() string { diff --git a/serviceresponse.go b/serviceresponse.go index 05efd22..cd9f887 100644 --- a/serviceresponse.go +++ b/serviceresponse.go @@ -6,6 +6,7 @@ import ( type ServiceResponse struct { Qux string `json:"qux"` + UUID string `json:"uuid"` } func (sr ServiceResponse) String() string { diff --git a/vendor/github.com/nu7hatch/gouuid/COPYING b/vendor/github.com/nu7hatch/gouuid/COPYING new file mode 100644 index 0000000..d7849fd --- /dev/null +++ b/vendor/github.com/nu7hatch/gouuid/COPYING @@ -0,0 +1,19 @@ +Copyright (C) 2011 by Krzysztof Kowalik + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/vendor/github.com/nu7hatch/gouuid/README.md b/vendor/github.com/nu7hatch/gouuid/README.md new file mode 100644 index 0000000..e3d025d --- /dev/null +++ b/vendor/github.com/nu7hatch/gouuid/README.md @@ -0,0 +1,21 @@ +# Pure Go UUID implementation + +This package provides immutable UUID structs and the functions +NewV3, NewV4, NewV5 and Parse() for generating versions 3, 4 +and 5 UUIDs as specified in [RFC 4122](http://www.ietf.org/rfc/rfc4122.txt). + +## Installation + +Use the `go` tool: + + $ go get github.com/nu7hatch/gouuid + +## Usage + +See [documentation and examples](http://godoc.org/github.com/nu7hatch/gouuid) +for more information. + +## Copyright + +Copyright (C) 2011 by Krzysztof Kowalik . See [COPYING](https://github.com/nu7hatch/gouuid/tree/master/COPYING) +file for details. diff --git a/vendor/github.com/nu7hatch/gouuid/uuid.go b/vendor/github.com/nu7hatch/gouuid/uuid.go new file mode 100644 index 0000000..ac9623b --- /dev/null +++ b/vendor/github.com/nu7hatch/gouuid/uuid.go @@ -0,0 +1,173 @@ +// This package provides immutable UUID structs and the functions +// NewV3, NewV4, NewV5 and Parse() for generating versions 3, 4 +// and 5 UUIDs as specified in RFC 4122. +// +// Copyright (C) 2011 by Krzysztof Kowalik +package uuid + +import ( + "crypto/md5" + "crypto/rand" + "crypto/sha1" + "encoding/hex" + "errors" + "fmt" + "hash" + "regexp" +) + +// The UUID reserved variants. +const ( + ReservedNCS byte = 0x80 + ReservedRFC4122 byte = 0x40 + ReservedMicrosoft byte = 0x20 + ReservedFuture byte = 0x00 +) + +// The following standard UUIDs are for use with NewV3() or NewV5(). +var ( + NamespaceDNS, _ = ParseHex("6ba7b810-9dad-11d1-80b4-00c04fd430c8") + NamespaceURL, _ = ParseHex("6ba7b811-9dad-11d1-80b4-00c04fd430c8") + NamespaceOID, _ = ParseHex("6ba7b812-9dad-11d1-80b4-00c04fd430c8") + NamespaceX500, _ = ParseHex("6ba7b814-9dad-11d1-80b4-00c04fd430c8") +) + +// Pattern used to parse hex string representation of the UUID. +// FIXME: do something to consider both brackets at one time, +// current one allows to parse string with only one opening +// or closing bracket. +const hexPattern = "^(urn\\:uuid\\:)?\\{?([a-z0-9]{8})-([a-z0-9]{4})-" + + "([1-5][a-z0-9]{3})-([a-z0-9]{4})-([a-z0-9]{12})\\}?$" + +var re = regexp.MustCompile(hexPattern) + +// A UUID representation compliant with specification in +// RFC 4122 document. +type UUID [16]byte + +// ParseHex creates a UUID object from given hex string +// representation. Function accepts UUID string in following +// formats: +// +// uuid.ParseHex("6ba7b814-9dad-11d1-80b4-00c04fd430c8") +// uuid.ParseHex("{6ba7b814-9dad-11d1-80b4-00c04fd430c8}") +// uuid.ParseHex("urn:uuid:6ba7b814-9dad-11d1-80b4-00c04fd430c8") +// +func ParseHex(s string) (u *UUID, err error) { + md := re.FindStringSubmatch(s) + if md == nil { + err = errors.New("Invalid UUID string") + return + } + hash := md[2] + md[3] + md[4] + md[5] + md[6] + b, err := hex.DecodeString(hash) + if err != nil { + return + } + u = new(UUID) + copy(u[:], b) + return +} + +// Parse creates a UUID object from given bytes slice. +func Parse(b []byte) (u *UUID, err error) { + if len(b) != 16 { + err = errors.New("Given slice is not valid UUID sequence") + return + } + u = new(UUID) + copy(u[:], b) + return +} + +// Generate a UUID based on the MD5 hash of a namespace identifier +// and a name. +func NewV3(ns *UUID, name []byte) (u *UUID, err error) { + if ns == nil { + err = errors.New("Invalid namespace UUID") + return + } + u = new(UUID) + // Set all bits to MD5 hash generated from namespace and name. + u.setBytesFromHash(md5.New(), ns[:], name) + u.setVariant(ReservedRFC4122) + u.setVersion(3) + return +} + +// Generate a random UUID. +func NewV4() (u *UUID, err error) { + u = new(UUID) + // Set all bits to randomly (or pseudo-randomly) chosen values. + _, err = rand.Read(u[:]) + if err != nil { + return + } + u.setVariant(ReservedRFC4122) + u.setVersion(4) + return +} + +// Generate a UUID based on the SHA-1 hash of a namespace identifier +// and a name. +func NewV5(ns *UUID, name []byte) (u *UUID, err error) { + u = new(UUID) + // Set all bits to truncated SHA1 hash generated from namespace + // and name. + u.setBytesFromHash(sha1.New(), ns[:], name) + u.setVariant(ReservedRFC4122) + u.setVersion(5) + return +} + +// Generate a MD5 hash of a namespace and a name, and copy it to the +// UUID slice. +func (u *UUID) setBytesFromHash(hash hash.Hash, ns, name []byte) { + hash.Write(ns[:]) + hash.Write(name) + copy(u[:], hash.Sum([]byte{})[:16]) +} + +// Set the two most significant bits (bits 6 and 7) of the +// clock_seq_hi_and_reserved to zero and one, respectively. +func (u *UUID) setVariant(v byte) { + switch v { + case ReservedNCS: + u[8] = (u[8] | ReservedNCS) & 0xBF + case ReservedRFC4122: + u[8] = (u[8] | ReservedRFC4122) & 0x7F + case ReservedMicrosoft: + u[8] = (u[8] | ReservedMicrosoft) & 0x3F + } +} + +// Variant returns the UUID Variant, which determines the internal +// layout of the UUID. This will be one of the constants: RESERVED_NCS, +// RFC_4122, RESERVED_MICROSOFT, RESERVED_FUTURE. +func (u *UUID) Variant() byte { + if u[8]&ReservedNCS == ReservedNCS { + return ReservedNCS + } else if u[8]&ReservedRFC4122 == ReservedRFC4122 { + return ReservedRFC4122 + } else if u[8]&ReservedMicrosoft == ReservedMicrosoft { + return ReservedMicrosoft + } + return ReservedFuture +} + +// Set the four most significant bits (bits 12 through 15) of the +// time_hi_and_version field to the 4-bit version number. +func (u *UUID) setVersion(v byte) { + u[6] = (u[6] & 0xF) | (v << 4) +} + +// Version returns a version number of the algorithm used to +// generate the UUID sequence. +func (u *UUID) Version() uint { + return uint(u[6] >> 4) +} + +// Returns unparsed version of the generated UUID sequence. +func (u *UUID) String() string { + return fmt.Sprintf("%x-%x-%x-%x-%x", u[0:4], u[4:6], u[6:8], u[8:10], u[10:]) +} diff --git a/vendor/vendor.json b/vendor/vendor.json index 3631986..6ffa135 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -8,6 +8,12 @@ "revision": "70f0258d44cbaa3b6a2581d82f58da01a38e4de4", "revisionTime": "2017-05-23T19:07:22Z" }, + { + "checksumSHA1": "gcLub3oB+u4QrOJZcYmk/y2AP4k=", + "path": "github.com/nu7hatch/gouuid", + "revision": "179d4d0c4d8d407a32af483c2354df1d2c91e6c3", + "revisionTime": "2013-12-21T20:05:32Z" + }, { "checksumSHA1": "BYvROBsiyAXK4sq6yhDe8RgT4LM=", "path": "github.com/sirupsen/logrus",