diff --git a/metrics.go b/metrics.go index 43c3eb7..6314814 100644 --- a/metrics.go +++ b/metrics.go @@ -83,14 +83,14 @@ func ReportFuncCallAndTimingCtxWithErr(ctx context.Context, tags ...Tags) func(e } } -func ReportFuncCallAndTimingWithErr(tags ...Tags) func(err *error) { +func ReportFuncCallAndTimingWithErr(tags ...Tags) func(err *error, tags ...Tags) { fn := CallerFuncName(1) reportFunc(fn, "called", tags...) _, stop := reportTiming(context.Background(), tags...) - return func(err *error) { - stop() + return func(err *error, stopTags ...Tags) { + stop(stopTags...) if err != nil && *err != nil { - ReportClosureFuncError(fn, tags...) + ReportClosureFuncError(fn, MergeTags(MergeTags(nil, tags...), stopTags...)) } } } @@ -111,7 +111,7 @@ func reportFunc(fn, action string, tags ...Tags) { client.Incr(fmt.Sprintf("func.%v", action), tagArray, 0.77) } -type StopTimerFunc func() +type StopTimerFunc func(tags ...Tags) func ReportFuncTiming(tags ...Tags) StopTimerFunc { _, stopFn := reportTiming(context.Background(), tags...) @@ -127,7 +127,7 @@ func reportTiming(ctx context.Context, tags ...Tags) (context.Context, StopTimer defer clientMux.RUnlock() if client == nil { - return ctx, func() {} + return ctx, func(...Tags) {} } t := time.Now() fn := CallerFuncName(2) @@ -170,13 +170,15 @@ func reportTiming(ctx context.Context, tags ...Tags) (context.Context, StopTimer } }(fn, t) - return spanCtx, func() { + return spanCtx, func(stopTags ...Tags) { d := time.Since(t) close(doneC) + stopTagArray := append(tagArray, JoinTags(stopTags...)...) + clientMux.RLock() defer clientMux.RUnlock() - client.Timing("func.timing", d, tagArray, 1) + client.Timing("func.timing", d, stopTagArray, 1) if span != nil { span.End() } @@ -187,7 +189,7 @@ func ReportClosureFuncTiming(name string, tags ...Tags) StopTimerFunc { clientMux.RLock() defer clientMux.RUnlock() if client == nil { - return func() {} + return func(...Tags) {} } t := time.Now() tagArray := JoinTags(tags...) @@ -212,13 +214,14 @@ func ReportClosureFuncTiming(name string, tags ...Tags) StopTimerFunc { } }(name, t) - return func() { + return func(stopTags ...Tags) { d := time.Since(t) close(doneC) + stopTagArray := append(tagArray, JoinTags(stopTags...)...) clientMux.RLock() defer clientMux.RUnlock() - client.Timing("func.timing", d, tagArray, 1) + client.Timing("func.timing", d, stopTagArray, 1) } } diff --git a/metrics_test.go b/metrics_test.go index 5690825..f185c39 100644 --- a/metrics_test.go +++ b/metrics_test.go @@ -43,7 +43,7 @@ func Test_ReportTimedFuncWithError(t *testing.T) { t.Run("can be deferred and report the error", func(t *testing.T) { rec.reset() exec := func() (err error) { - defer ReportFuncCallAndTimingWithErr(Tags{"foo": "bar"})(&err) + defer ReportFuncCallAndTimingWithErr(Tags{"foo": "bar"})(&err, Tags{"stop": "error"}) time.Sleep(5 * time.Millisecond) return errors.New("this error should be recorder") @@ -55,15 +55,16 @@ func Test_ReportTimedFuncWithError(t *testing.T) { expectedTags := []string{"foo=bar", "func_name=1"} assert.Equal(t, "Incr", rec.calls[0][0]) assert.Equal(t, "func.called", rec.calls[0][1]) - assert.Equal(t, expectedTags, rec.calls[0][2]) + assert.ElementsMatch(t, expectedTags, rec.calls[0][2]) + expectedTags = []string{"foo=bar", "stop=error", "func_name=1"} assert.Equal(t, "Count", rec.calls[1][0]) assert.Equal(t, "func.timing", rec.calls[1][1]) - assert.Equal(t, expectedTags, rec.calls[1][3]) + assert.ElementsMatch(t, expectedTags, rec.calls[1][3]) assert.Equal(t, "Incr", rec.calls[2][0]) assert.Equal(t, "func.error", rec.calls[2][1]) - assert.Equal(t, expectedTags, rec.calls[2][2]) + assert.ElementsMatch(t, expectedTags, rec.calls[2][2]) }) t.Run("can be deferred and skip error reporting if nil", func(t *testing.T) { @@ -79,6 +80,22 @@ func Test_ReportTimedFuncWithError(t *testing.T) { assert.Equal(t, "func.called", rec.calls[0][1]) assert.Equal(t, "func.timing", rec.calls[1][1]) }) + + t.Run("can be deferred with new tags and skip error reporting", func(t *testing.T) { + rec.reset() + exec := func() { + var err error + defer ReportFuncCallAndTimingWithErr(Tags{"foo": "bar"})(&err, Tags{"something": "new"}) + } + + exec() + require.Len(t, rec.calls, 2) + + expectedTags := []string{"foo=bar", "something=new", "func_name=1"} + assert.Equal(t, "func.called", rec.calls[0][1]) + assert.Equal(t, "func.timing", rec.calls[1][1]) + assert.ElementsMatch(t, expectedTags, rec.calls[1][3]) + }) } type statterRecorder struct {