-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #9 from mittwald/feat/logging
feat: add option to log all executed requests
- Loading branch information
Showing
2 changed files
with
80 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package mittwaldv2 | ||
|
||
import ( | ||
"context" | ||
"log/slog" | ||
|
||
"github.com/mittwald/api-client-go/pkg/httpclient" | ||
) | ||
|
||
// WithRequestLogging adds a logging middleware to the request runner chain | ||
// allowing you to log all executed HTTP requests in a slog.Logger of your | ||
// choice. | ||
// | ||
// Be mindful of the log{Request,Response}Bodies parameters; these will cause | ||
// the logger to print the full request bodies without redaction, which may | ||
// easily leak sensitive data. | ||
func WithRequestLogging(logger *slog.Logger, logRequestBodies, logResponseBodies bool) ClientOption { | ||
return func(ctx context.Context, runner httpclient.RequestRunner) (httpclient.RequestRunner, error) { | ||
return httpclient.NewLoggingClient(runner, logger, logRequestBodies, logResponseBodies), nil | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
package httpclient | ||
|
||
import ( | ||
"bytes" | ||
"io" | ||
"log/slog" | ||
"net/http" | ||
) | ||
|
||
type loggingClient struct { | ||
inner RequestRunner | ||
logger *slog.Logger | ||
logRequestBodies bool | ||
logResponseBodies bool | ||
} | ||
|
||
func NewLoggingClient(inner RequestRunner, logger *slog.Logger, logRequestBodies, logResponseBodies bool) RequestRunner { | ||
return &loggingClient{ | ||
inner: inner, | ||
logger: logger, | ||
logRequestBodies: logRequestBodies, | ||
logResponseBodies: logResponseBodies, | ||
} | ||
} | ||
|
||
func (c *loggingClient) Do(request *http.Request) (*http.Response, error) { | ||
l := c.logger.With("req.method", request.Method, "req.url", request.URL.String()) | ||
|
||
if c.logRequestBodies && request.Body != nil { | ||
body, err := io.ReadAll(request.Body) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
request.Body = io.NopCloser(bytes.NewBuffer(body)) | ||
l = l.With("req.body", string(body)) | ||
} | ||
|
||
l.Debug("executing request") | ||
|
||
response, err := c.inner.Do(request) | ||
|
||
if response != nil { | ||
l = l.With("res.status", response.StatusCode) | ||
if c.logResponseBodies && response.Body != nil { | ||
body, err := io.ReadAll(response.Body) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
response.Body = io.NopCloser(bytes.NewBuffer(body)) | ||
l = l.With("res.body", string(body)) | ||
} | ||
} | ||
|
||
l.Debug("received response") | ||
|
||
return response, err | ||
} |