Skip to content

Commit

Permalink
Merge pull request #27 from StephanHCB/issue-26-too-many-warns
Browse files Browse the repository at this point in the history
feat(#26): allow squelching warn logs
  • Loading branch information
StephanHCB committed Feb 20, 2024
2 parents 177d92f + affb835 commit 7cf1a5e
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 5 deletions.
60 changes: 56 additions & 4 deletions implementation/requestlogging/requestlogging.go
Expand Up @@ -3,34 +3,86 @@ package aurestlogging
import (
"context"
aulogging "github.com/StephanHCB/go-autumn-logging"
auloggingapi "github.com/StephanHCB/go-autumn-logging/api"
aurestclientapi "github.com/StephanHCB/go-autumn-restclient/api"
aurestnontripping "github.com/StephanHCB/go-autumn-restclient/implementation/errors/nontrippingerror"
"time"
)

// RequestLoggingOptions allows overriding the log functions used.
//
// This allows easily changing the log level when setting up request logging.
//
// important: do not cache the LeveledLoggingImplementation, create one each time, or some loggers may use
// cached values.
type RequestLoggingOptions struct {
BeforeRequest func(ctx context.Context) auloggingapi.LeveledLoggingImplementation
Success func(ctx context.Context) auloggingapi.LeveledLoggingImplementation
Failure func(ctx context.Context) auloggingapi.LeveledLoggingImplementation
}

func Debug(ctx context.Context) auloggingapi.LeveledLoggingImplementation {
return aulogging.Logger.Ctx(ctx).Debug()
}

func Info(ctx context.Context) auloggingapi.LeveledLoggingImplementation {
return aulogging.Logger.Ctx(ctx).Info()
}

func Warn(ctx context.Context) auloggingapi.LeveledLoggingImplementation {
return aulogging.Logger.Ctx(ctx).Warn()
}

type RequestLoggingImpl struct {
Wrapped aurestclientapi.Client
Options RequestLoggingOptions
}

func NewWithOptions(wrapped aurestclientapi.Client, opts RequestLoggingOptions) aurestclientapi.Client {
instance := &RequestLoggingImpl{
Wrapped: wrapped,
Options: RequestLoggingOptions{
BeforeRequest: Debug,
Success: Info,
Failure: Warn,
},
}
if opts.BeforeRequest != nil {
instance.Options.BeforeRequest = opts.BeforeRequest
}
if opts.Success != nil {
instance.Options.Success = opts.Success
}
if opts.Failure != nil {
instance.Options.Failure = opts.Failure
}
return instance
}

func New(wrapped aurestclientapi.Client) aurestclientapi.Client {
return &RequestLoggingImpl{
Wrapped: wrapped,
Options: RequestLoggingOptions{
BeforeRequest: Debug,
Success: Info,
Failure: Warn,
},
}
}

func (c *RequestLoggingImpl) Perform(ctx context.Context, method string, requestUrl string, requestBody interface{}, response *aurestclientapi.ParsedResponse) error {
aulogging.Logger.Ctx(ctx).Debug().Printf("downstream %s %s...", method, requestUrl)
c.Options.BeforeRequest(ctx).Printf("downstream %s %s...", method, requestUrl)
before := time.Now()
err := c.Wrapped.Perform(ctx, method, requestUrl, requestBody, response)
millis := time.Now().Sub(before).Milliseconds()
if err != nil {
if aurestnontripping.Is(err) {
aulogging.Logger.Ctx(ctx).Warn().WithErr(err).Printf("downstream %s %s -> %d FAILED (%d ms) (nontripping)", method, requestUrl, response.Status, millis)
c.Options.Failure(ctx).WithErr(err).Printf("downstream %s %s -> %d FAILED (%d ms) (nontripping)", method, requestUrl, response.Status, millis)
} else {
aulogging.Logger.Ctx(ctx).Warn().WithErr(err).Printf("downstream %s %s -> %d FAILED (%d ms)", method, requestUrl, response.Status, millis)
c.Options.Failure(ctx).WithErr(err).Printf("downstream %s %s -> %d FAILED (%d ms)", method, requestUrl, response.Status, millis)
}
} else {
aulogging.Logger.Ctx(ctx).Info().Printf("downstream %s %s -> %d OK (%d ms)", method, requestUrl, response.Status, millis)
c.Options.Success(ctx).Printf("downstream %s %s -> %d OK (%d ms)", method, requestUrl, response.Status, millis)
}
return err
}
34 changes: 33 additions & 1 deletion implementation/retry/retry.go
Expand Up @@ -7,6 +7,14 @@ import (
"time"
)

type RetryOptions struct {
RepeatCount uint8

BeforeRetryOrNil aurestclientapi.BeforeRetryCallback

SilenceGivingUp bool
}

type RetryImpl struct {
Wrapped aurestclientapi.Client
RepeatCount uint8
Expand All @@ -16,6 +24,28 @@ type RetryImpl struct {

RetryingMetricsCallback aurestclientapi.MetricsCallbackFunction
GivingUpMetricsCallback aurestclientapi.MetricsCallbackFunction

SilenceGivingUp bool
}

func NewWithOptions(
wrapped aurestclientapi.Client,
condition aurestclientapi.RetryConditionCallback,
opts RetryOptions,
) aurestclientapi.Client {
repeatCount := uint8(2)
if opts.RepeatCount > 0 {
repeatCount = opts.RepeatCount
}
return &RetryImpl{
Wrapped: wrapped,
RepeatCount: repeatCount,
RetryCondition: condition,
BeforeRetry: opts.BeforeRetryOrNil,
RetryingMetricsCallback: doNothingMetricsCallback,
GivingUpMetricsCallback: doNothingMetricsCallback,
SilenceGivingUp: opts.SilenceGivingUp,
}
}

func New(
Expand Down Expand Up @@ -69,7 +99,9 @@ func (c *RetryImpl) Perform(ctx context.Context, method string, requestUrl strin
// (*)
if attempt == c.RepeatCount+1 {
c.GivingUpMetricsCallback(ctx, method, requestUrl, response.Status, err, 0, 0)
aulogging.Logger.Ctx(ctx).Warn().WithErr(err).Printf("giving up on %s %s after attempt %d", method, requestUrl, attempt)
if !c.SilenceGivingUp {
aulogging.Logger.Ctx(ctx).Warn().WithErr(err).Printf("giving up on %s %s after attempt %d", method, requestUrl, attempt)
}
return err
}
} else {
Expand Down
22 changes: 22 additions & 0 deletions implementation/retry/retry_test.go
Expand Up @@ -127,6 +127,28 @@ func TestFailWithRetry(t *testing.T) {
require.Equal(t, []string{r, r, r, r}, aurestcapture.GetRecording(mock))
}

func TestFailWithRetryWithOpts(t *testing.T) {
aulogging.SetupNoLoggerForTesting()

mock := tstMock()
cut := NewWithOptions(mock,
func(ctx context.Context, response *aurestclientapi.ParsedResponse, err error) bool {
return true
},
RetryOptions{
BeforeRetryOrNil: nil,
SilenceGivingUp: true,
},
)

response := &aurestclientapi.ParsedResponse{}
err := cut.Perform(context.Background(), "GET", "http://err", nil, response)
require.NotNil(t, err)
require.Equal(t, "some transport error", err.Error())
r := "GET http://err <nil>"
require.Equal(t, []string{r, r, r}, aurestcapture.GetRecording(mock))
}

func TestAbortRetry(t *testing.T) {
aulogging.SetupNoLoggerForTesting()

Expand Down

0 comments on commit 7cf1a5e

Please sign in to comment.