Skip to content

Commit ea689a0

Browse files
authored
Merge pull request #47 from deploymenttheory/dev
Add performance metrics and request logging
2 parents 625aa09 + 97fe973 commit ea689a0

File tree

2 files changed

+95
-33
lines changed

2 files changed

+95
-33
lines changed

httpclient/httpclient_concurrency_management.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,22 @@ func (c *Client) AcquireConcurrencyToken(ctx context.Context, log logger.Logger)
8888
return ctxWithRequestID, nil
8989
}
9090

91+
// updatePerformanceMetrics updates the client's performance metrics by recording the duration
92+
// of the HTTP request and incrementing the total request count. This function is thread-safe
93+
// and uses a mutex to synchronize updates to the performance metrics.
94+
//
95+
// Parameters:
96+
// - duration: The time duration it took for an HTTP request to complete.
97+
//
98+
// This function should be called after each HTTP request to keep track of the client's
99+
// performance over time.
100+
func (c *Client) updatePerformanceMetrics(duration time.Duration) {
101+
c.PerfMetrics.lock.Lock()
102+
defer c.PerfMetrics.lock.Unlock()
103+
c.PerfMetrics.TotalResponseTime += duration
104+
c.PerfMetrics.TotalRequests++
105+
}
106+
91107
// NewConcurrencyManager initializes a new ConcurrencyManager with the given concurrency limit, logger, and debug mode.
92108
// The ConcurrencyManager ensures no more than a certain number of concurrent requests are made.
93109
// It uses a semaphore to control concurrency.

httpclient/httpclient_request.go

Lines changed: 79 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,40 @@ import (
1414
"go.uber.org/zap"
1515
)
1616

17-
// updatePerformanceMetrics updates the client's performance metrics by recording the duration
18-
// of the HTTP request and incrementing the total request count. This function is thread-safe
19-
// and uses a mutex to synchronize updates to the performance metrics.
17+
// executeHTTPRequest sends an HTTP request using the client's HTTP client. It logs the request and error details, if any, using structured logging with zap fields.
2018
//
2119
// Parameters:
22-
// - duration: The time duration it took for an HTTP request to complete.
20+
// - req: The *http.Request object that contains all the details of the HTTP request to be sent.
21+
// - log: An instance of a logger (conforming to the logger.Logger interface) used for logging the request details and any errors.
22+
// - method: The HTTP method used for the request, used for logging.
23+
// - endpoint: The API endpoint the request is being sent to, used for logging.
2324
//
24-
// This function should be called after each HTTP request to keep track of the client's
25-
// performance over time.
26-
func (c *Client) updatePerformanceMetrics(duration time.Duration) {
27-
c.PerfMetrics.lock.Lock()
28-
defer c.PerfMetrics.lock.Unlock()
29-
c.PerfMetrics.TotalResponseTime += duration
30-
c.PerfMetrics.TotalRequests++
25+
// Returns:
26+
// - *http.Response: The HTTP response from the server.
27+
// - error: An error object if an error occurred while sending the request or nil if no error occurred.
28+
//
29+
// Usage:
30+
// This function should be used whenever the client needs to send an HTTP request. It abstracts away the common logic of request execution and error handling, providing detailed logs for debugging and monitoring.
31+
func (c *Client) executeHTTPRequest(req *http.Request, log logger.Logger, method, endpoint string) (*http.Response, error) {
32+
resp, err := c.httpClient.Do(req)
33+
if err != nil {
34+
// Log the error with structured logging, including method, endpoint, and the error itself
35+
log.Error("Failed to send request",
36+
zap.String("method", method),
37+
zap.String("endpoint", endpoint),
38+
zap.Error(err),
39+
)
40+
return nil, err
41+
}
42+
43+
// Log the response status code for successful requests
44+
log.Info("Request sent successfully",
45+
zap.String("method", method),
46+
zap.String("endpoint", endpoint),
47+
zap.Int("status_code", resp.StatusCode),
48+
)
49+
50+
return resp, nil
3151
}
3252

3353
// DoRequest constructs and executes a standard HTTP request with support for retry logic.
@@ -149,16 +169,24 @@ func (c *Client) DoRequest(method, endpoint string, body, out interface{}, log l
149169
responseTimeStart := time.Now()
150170

151171
// Execute the request
152-
resp, err := c.httpClient.Do(req)
172+
/*
173+
resp, err := c.httpClient.Do(req)
174+
if err != nil {
175+
log.Error("Failed to send retryable request",
176+
zap.String("method", method),
177+
zap.String("endpoint", endpoint),
178+
zap.Int("status_code", resp.StatusCode),
179+
zap.String("status_text", http.StatusText(resp.StatusCode)),
180+
)
181+
return nil, err
182+
}*/
183+
184+
// Execute the request
185+
resp, err := c.executeHTTPRequest(req, log, method, endpoint)
153186
if err != nil {
154-
log.Error("Failed to send retryable request",
155-
zap.String("method", method),
156-
zap.String("endpoint", endpoint),
157-
zap.Int("status_code", resp.StatusCode),
158-
zap.String("status_text", http.StatusText(resp.StatusCode)),
159-
)
160187
return nil, err
161188
}
189+
162190
// After each request, compute and update response time
163191
responseDuration := time.Since(responseTimeStart)
164192
c.updatePerformanceMetrics(responseDuration)
@@ -264,27 +292,37 @@ func (c *Client) DoRequest(method, endpoint string, body, out interface{}, log l
264292
responseTimeStart := time.Now()
265293
// For non-retryable HTTP Methods (POST - Create)
266294
req = req.WithContext(ctx)
295+
267296
// Execute the request
268-
resp, err := c.httpClient.Do(req)
297+
/*
298+
resp, err := c.httpClient.Do(req)
299+
if err != nil {
300+
log.Error("Failed to send request",
301+
zap.String("method", method),
302+
zap.String("endpoint", endpoint),
303+
zap.Int("status_code", resp.StatusCode),
304+
zap.String("status_text", http.StatusText(resp.StatusCode)),
305+
)
306+
return nil, err
307+
}
308+
*/
309+
// Execute the request
310+
resp, err := c.executeHTTPRequest(req, log, method, endpoint)
269311
if err != nil {
270-
log.Error("Failed to send request",
271-
zap.String("method", method),
272-
zap.String("endpoint", endpoint),
273-
zap.Int("status_code", resp.StatusCode),
274-
zap.String("status_text", http.StatusText(resp.StatusCode)),
275-
)
276312
return nil, err
277313
}
278-
279314
// After each request, compute and update response time
280315
responseDuration := time.Since(responseTimeStart)
281316
c.updatePerformanceMetrics(responseDuration)
317+
282318
/*
283319
responseDuration := time.Since(responseTimeStart)
284320
c.PerfMetrics.lock.Lock()
285321
c.PerfMetrics.TotalResponseTime += responseDuration
286322
c.PerfMetrics.lock.Unlock()
287323
*/
324+
325+
// Checks for the presence of a deprecation header in the HTTP response and logs if found.
288326
CheckDeprecationHeader(resp, log)
289327

290328
// Handle (unmarshal) response with API Handler
@@ -394,14 +432,22 @@ func (c *Client) DoMultipartRequest(method, endpoint string, fields map[string]s
394432
c.SetRequestHeaders(req, contentType, acceptHeader, log)
395433

396434
// Execute the request
397-
resp, err := c.httpClient.Do(req)
435+
/*
436+
resp, err := c.httpClient.Do(req)
437+
if err != nil {
438+
log.Error("Failed to send multipart request",
439+
zap.String("method", method),
440+
zap.String("endpoint", endpoint),
441+
zap.Int("status_code", resp.StatusCode),
442+
zap.String("status_text", http.StatusText(resp.StatusCode)),
443+
)
444+
return nil, err
445+
}
446+
*/
447+
448+
// Execute the request
449+
resp, err := c.executeHTTPRequest(req, log, method, endpoint)
398450
if err != nil {
399-
log.Error("Failed to send multipart request",
400-
zap.String("method", method),
401-
zap.String("endpoint", endpoint),
402-
zap.Int("status_code", resp.StatusCode),
403-
zap.String("status_text", http.StatusText(resp.StatusCode)),
404-
)
405451
return nil, err
406452
}
407453

0 commit comments

Comments
 (0)