logger.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. package client
  2. import (
  3. "bytes"
  4. "fmt"
  5. "io"
  6. "io/ioutil"
  7. "net/http/httputil"
  8. "github.com/aws/aws-sdk-go/aws"
  9. "github.com/aws/aws-sdk-go/aws/request"
  10. )
  11. const logReqMsg = `DEBUG: Request %s/%s Details:
  12. ---[ REQUEST POST-SIGN ]-----------------------------
  13. %s
  14. -----------------------------------------------------`
  15. const logReqErrMsg = `DEBUG ERROR: Request %s/%s:
  16. ---[ REQUEST DUMP ERROR ]-----------------------------
  17. %s
  18. ------------------------------------------------------`
  19. type logWriter struct {
  20. // Logger is what we will use to log the payload of a response.
  21. Logger aws.Logger
  22. // buf stores the contents of what has been read
  23. buf *bytes.Buffer
  24. }
  25. func (logger *logWriter) Write(b []byte) (int, error) {
  26. return logger.buf.Write(b)
  27. }
  28. type teeReaderCloser struct {
  29. // io.Reader will be a tee reader that is used during logging.
  30. // This structure will read from a body and write the contents to a logger.
  31. io.Reader
  32. // Source is used just to close when we are done reading.
  33. Source io.ReadCloser
  34. }
  35. func (reader *teeReaderCloser) Close() error {
  36. return reader.Source.Close()
  37. }
  38. // LogHTTPRequestHandler is a SDK request handler to log the HTTP request sent
  39. // to a service. Will include the HTTP request body if the LogLevel of the
  40. // request matches LogDebugWithHTTPBody.
  41. var LogHTTPRequestHandler = request.NamedHandler{
  42. Name: "awssdk.client.LogRequest",
  43. Fn: logRequest,
  44. }
  45. func logRequest(r *request.Request) {
  46. logBody := r.Config.LogLevel.Matches(aws.LogDebugWithHTTPBody)
  47. bodySeekable := aws.IsReaderSeekable(r.Body)
  48. b, err := httputil.DumpRequestOut(r.HTTPRequest, logBody)
  49. if err != nil {
  50. r.Config.Logger.Log(fmt.Sprintf(logReqErrMsg,
  51. r.ClientInfo.ServiceName, r.Operation.Name, err))
  52. return
  53. }
  54. if logBody {
  55. if !bodySeekable {
  56. r.SetReaderBody(aws.ReadSeekCloser(r.HTTPRequest.Body))
  57. }
  58. // Reset the request body because dumpRequest will re-wrap the r.HTTPRequest's
  59. // Body as a NoOpCloser and will not be reset after read by the HTTP
  60. // client reader.
  61. r.ResetBody()
  62. }
  63. r.Config.Logger.Log(fmt.Sprintf(logReqMsg,
  64. r.ClientInfo.ServiceName, r.Operation.Name, string(b)))
  65. }
  66. // LogHTTPRequestHeaderHandler is a SDK request handler to log the HTTP request sent
  67. // to a service. Will only log the HTTP request's headers. The request payload
  68. // will not be read.
  69. var LogHTTPRequestHeaderHandler = request.NamedHandler{
  70. Name: "awssdk.client.LogRequestHeader",
  71. Fn: logRequestHeader,
  72. }
  73. func logRequestHeader(r *request.Request) {
  74. b, err := httputil.DumpRequestOut(r.HTTPRequest, false)
  75. if err != nil {
  76. r.Config.Logger.Log(fmt.Sprintf(logReqErrMsg,
  77. r.ClientInfo.ServiceName, r.Operation.Name, err))
  78. return
  79. }
  80. r.Config.Logger.Log(fmt.Sprintf(logReqMsg,
  81. r.ClientInfo.ServiceName, r.Operation.Name, string(b)))
  82. }
  83. const logRespMsg = `DEBUG: Response %s/%s Details:
  84. ---[ RESPONSE ]--------------------------------------
  85. %s
  86. -----------------------------------------------------`
  87. const logRespErrMsg = `DEBUG ERROR: Response %s/%s:
  88. ---[ RESPONSE DUMP ERROR ]-----------------------------
  89. %s
  90. -----------------------------------------------------`
  91. // LogHTTPResponseHandler is a SDK request handler to log the HTTP response
  92. // received from a service. Will include the HTTP response body if the LogLevel
  93. // of the request matches LogDebugWithHTTPBody.
  94. var LogHTTPResponseHandler = request.NamedHandler{
  95. Name: "awssdk.client.LogResponse",
  96. Fn: logResponse,
  97. }
  98. func logResponse(r *request.Request) {
  99. lw := &logWriter{r.Config.Logger, bytes.NewBuffer(nil)}
  100. logBody := r.Config.LogLevel.Matches(aws.LogDebugWithHTTPBody)
  101. if logBody {
  102. r.HTTPResponse.Body = &teeReaderCloser{
  103. Reader: io.TeeReader(r.HTTPResponse.Body, lw),
  104. Source: r.HTTPResponse.Body,
  105. }
  106. }
  107. handlerFn := func(req *request.Request) {
  108. b, err := httputil.DumpResponse(req.HTTPResponse, false)
  109. if err != nil {
  110. lw.Logger.Log(fmt.Sprintf(logRespErrMsg,
  111. req.ClientInfo.ServiceName, req.Operation.Name, err))
  112. return
  113. }
  114. lw.Logger.Log(fmt.Sprintf(logRespMsg,
  115. req.ClientInfo.ServiceName, req.Operation.Name, string(b)))
  116. if logBody {
  117. b, err := ioutil.ReadAll(lw.buf)
  118. if err != nil {
  119. lw.Logger.Log(fmt.Sprintf(logRespErrMsg,
  120. req.ClientInfo.ServiceName, req.Operation.Name, err))
  121. return
  122. }
  123. lw.Logger.Log(string(b))
  124. }
  125. }
  126. const handlerName = "awsdk.client.LogResponse.ResponseBody"
  127. r.Handlers.Unmarshal.SetBackNamed(request.NamedHandler{
  128. Name: handlerName, Fn: handlerFn,
  129. })
  130. r.Handlers.UnmarshalError.SetBackNamed(request.NamedHandler{
  131. Name: handlerName, Fn: handlerFn,
  132. })
  133. }
  134. // LogHTTPResponseHeaderHandler is a SDK request handler to log the HTTP
  135. // response received from a service. Will only log the HTTP response's headers.
  136. // The response payload will not be read.
  137. var LogHTTPResponseHeaderHandler = request.NamedHandler{
  138. Name: "awssdk.client.LogResponseHeader",
  139. Fn: logResponseHeader,
  140. }
  141. func logResponseHeader(r *request.Request) {
  142. if r.Config.Logger == nil {
  143. return
  144. }
  145. b, err := httputil.DumpResponse(r.HTTPResponse, false)
  146. if err != nil {
  147. r.Config.Logger.Log(fmt.Sprintf(logRespErrMsg,
  148. r.ClientInfo.ServiceName, r.Operation.Name, err))
  149. return
  150. }
  151. r.Config.Logger.Log(fmt.Sprintf(logRespMsg,
  152. r.ClientInfo.ServiceName, r.Operation.Name, string(b)))
  153. }