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