logger.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  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. func logRequest(r *request.Request) {
  39. logBody := r.Config.LogLevel.Matches(aws.LogDebugWithHTTPBody)
  40. dumpedBody, err := httputil.DumpRequestOut(r.HTTPRequest, logBody)
  41. if err != nil {
  42. r.Config.Logger.Log(fmt.Sprintf(logReqErrMsg, r.ClientInfo.ServiceName, r.Operation.Name, err))
  43. return
  44. }
  45. if logBody {
  46. // Reset the request body because dumpRequest will re-wrap the r.HTTPRequest's
  47. // Body as a NoOpCloser and will not be reset after read by the HTTP
  48. // client reader.
  49. r.ResetBody()
  50. }
  51. r.Config.Logger.Log(fmt.Sprintf(logReqMsg, r.ClientInfo.ServiceName, r.Operation.Name, string(dumpedBody)))
  52. }
  53. const logRespMsg = `DEBUG: Response %s/%s Details:
  54. ---[ RESPONSE ]--------------------------------------
  55. %s
  56. -----------------------------------------------------`
  57. const logRespErrMsg = `DEBUG ERROR: Response %s/%s:
  58. ---[ RESPONSE DUMP ERROR ]-----------------------------
  59. %s
  60. -----------------------------------------------------`
  61. func logResponse(r *request.Request) {
  62. lw := &logWriter{r.Config.Logger, bytes.NewBuffer(nil)}
  63. r.HTTPResponse.Body = &teeReaderCloser{
  64. Reader: io.TeeReader(r.HTTPResponse.Body, lw),
  65. Source: r.HTTPResponse.Body,
  66. }
  67. handlerFn := func(req *request.Request) {
  68. body, err := httputil.DumpResponse(req.HTTPResponse, false)
  69. if err != nil {
  70. lw.Logger.Log(fmt.Sprintf(logRespErrMsg, req.ClientInfo.ServiceName, req.Operation.Name, err))
  71. return
  72. }
  73. b, err := ioutil.ReadAll(lw.buf)
  74. if err != nil {
  75. lw.Logger.Log(fmt.Sprintf(logRespErrMsg, req.ClientInfo.ServiceName, req.Operation.Name, err))
  76. return
  77. }
  78. lw.Logger.Log(fmt.Sprintf(logRespMsg, req.ClientInfo.ServiceName, req.Operation.Name, string(body)))
  79. if req.Config.LogLevel.Matches(aws.LogDebugWithHTTPBody) {
  80. lw.Logger.Log(string(b))
  81. }
  82. }
  83. const handlerName = "awsdk.client.LogResponse.ResponseBody"
  84. r.Handlers.Unmarshal.SetBackNamed(request.NamedHandler{
  85. Name: handlerName, Fn: handlerFn,
  86. })
  87. r.Handlers.UnmarshalError.SetBackNamed(request.NamedHandler{
  88. Name: handlerName, Fn: handlerFn,
  89. })
  90. }