Skip to content

Commit

Permalink
Use scope for statsd_collector
Browse files Browse the repository at this point in the history
  • Loading branch information
albertus.raharja authored and ajatprabha committed Jul 1, 2019
1 parent 1850b93 commit 312118a
Show file tree
Hide file tree
Showing 9 changed files with 131 additions and 36 deletions.
5 changes: 4 additions & 1 deletion internal/handler/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@ func ImageHandler(deps *service.Dependencies) http.HandlerFunc {
params[v] = values.Get(v)
}
}
data, err = deps.Manipulator.Process(r.Context(), data, params)
data, err = deps.Manipulator.Process(service.ProcessSpec{
ImageData: data,
Params: params,
})
if err != nil {
l.Errorf("error from Manipulator.Process: %s", err)
metrics.Update(metrics.UpdateOption{Name: ProcessorErrorKey, Type: metrics.Count})
Expand Down
8 changes: 4 additions & 4 deletions internal/handler/image_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func (s *ImageHandlerTestSuite) TestImageHandlerWithQueryParameters() {
params["w"] = "100"
params["h"] = "100"
s.storage.On("Get", mock.Anything, "/image-valid").Return([]byte("validData"), http.StatusOK, nil)
s.manipulator.On("Process", mock.Anything, []byte("validData"), params).Return([]byte("processedData"), nil)
s.manipulator.On("Process", mock.AnythingOfType("ProcessSpec")).Return([]byte("processedData"), nil)

ImageHandler(s.deps).ServeHTTP(rr, r)

Expand All @@ -79,7 +79,7 @@ func (s *ImageHandlerTestSuite) TestImageHandlerWithQueryParametersAndProcessing
params["w"] = "100"
params["h"] = "100"
s.storage.On("Get", mock.Anything, "/image-valid").Return([]byte("validData"), http.StatusOK, nil)
s.manipulator.On("Process", mock.Anything, []byte("validData"), params).Return([]byte(nil), errors.New("error"))
s.manipulator.On("Process", mock.AnythingOfType("ProcessSpec")).Return([]byte(nil), errors.New("error"))

ImageHandler(s.deps).ServeHTTP(rr, r)

Expand All @@ -91,8 +91,8 @@ type mockManipulator struct {
mock.Mock
}

func (m *mockManipulator) Process(ctx context.Context, data []byte, params map[string]string) ([]byte, error) {
args := m.Called(ctx, data, params)
func (m *mockManipulator) Process(spec service.ProcessSpec) ([]byte, error) {
args := m.Called(spec)
return args.Get(0).([]byte), args.Error(1)
}

Expand Down
1 change: 1 addition & 0 deletions pkg/metrics/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const (
)

type UpdateOption struct {
Scope string
Name string
Type Type
NumValue float64
Expand Down
25 changes: 15 additions & 10 deletions pkg/metrics/statsd_collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"github.com/cactus/go-statsd-client/statsd"
"***REMOVED***/darkroom/core/pkg/logger"
"strings"
"time"
)

Expand All @@ -12,14 +13,14 @@ const (
WANStatsdFlushBytes = 512
LANStatsdFlushBytes = 1432
GigabitStatsdFlushBytes = 8932
DefaultScope = "default"
)

var instance *statsdClient

type statsdClient struct {
client statsd.Statter
collectorName string
sampleRate float32
client statsd.Statter
sampleRate float32
}

// StatsdCollectorConfig provides configuration that the Statsd client will need.
Expand All @@ -35,7 +36,7 @@ type StatsdCollectorConfig struct {
}

// InitializeStatsdCollector will start publishing metrics in the form {config.Prefix}.{name}.{updateOption.Name}
func InitializeStatsdCollector(config *StatsdCollectorConfig, collectorName string) error {
func InitializeStatsdCollector(config *StatsdCollectorConfig) error {
flushBytes := config.FlushBytes
if flushBytes == 0 {
flushBytes = LANStatsdFlushBytes
Expand All @@ -51,12 +52,16 @@ func InitializeStatsdCollector(config *StatsdCollectorConfig, collectorName stri
// TODO Add logger for error
c = &statsd.NoopClient{}
}
instance = &statsdClient{client: c, collectorName: collectorName, sampleRate: sampleRate}
instance = &statsdClient{client: c, sampleRate: sampleRate}
return nil
}

func formatter(on string) string {
return fmt.Sprintf("%s.%s", instance.collectorName, on)
func formatter(updateOption UpdateOption) string {
scope := strings.Trim(updateOption.Scope, ".")
if updateOption.Scope == "" {
scope = DefaultScope
}
return fmt.Sprintf("%s.%s", scope, strings.Trim(updateOption.Name, "."))
}

func Update(updateOption UpdateOption) {
Expand All @@ -66,13 +71,13 @@ func Update(updateOption UpdateOption) {
var err error
switch updateOption.Type {
case Duration:
err = instance.client.TimingDuration(formatter(updateOption.Name), updateOption.Duration, instance.sampleRate)
err = instance.client.TimingDuration(formatter(updateOption), updateOption.Duration, instance.sampleRate)
break
case Gauge:
err = instance.client.Gauge(formatter(updateOption.Name), int64(updateOption.NumValue), instance.sampleRate)
err = instance.client.Gauge(formatter(updateOption), int64(updateOption.NumValue), instance.sampleRate)
break
case Count:
err = instance.client.Inc(formatter(updateOption.Name), 1, instance.sampleRate)
err = instance.client.Inc(formatter(updateOption), 1, instance.sampleRate)
break
}
if err != nil {
Expand Down
67 changes: 63 additions & 4 deletions pkg/metrics/statsd_collector_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package metrics

import (
"errors"
"fmt"
"github.com/cactus/go-statsd-client/statsd"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
Expand All @@ -11,17 +12,17 @@ import (

func TestInitializeStatsdCollector(t *testing.T) {
// Test Statter client
err := InitializeStatsdCollector(&StatsdCollectorConfig{FlushBytes: 0}, "app-name")
err := InitializeStatsdCollector(&StatsdCollectorConfig{FlushBytes: 0})
assert.Nil(t, err)
assert.NotNil(t, instance)
assert.NotNil(t, instance.client)

// Test sampleRate
err = InitializeStatsdCollector(&StatsdCollectorConfig{SampleRate: 5}, "app-name")
err = InitializeStatsdCollector(&StatsdCollectorConfig{SampleRate: 5})
assert.Nil(t, err)
assert.Equal(t, float32(5), instance.sampleRate)

err = InitializeStatsdCollector(&StatsdCollectorConfig{}, "app-name")
err = InitializeStatsdCollector(&StatsdCollectorConfig{})
assert.Nil(t, err)
assert.Equal(t, float32(1), instance.sampleRate)
}
Expand All @@ -31,7 +32,7 @@ func TestUpdate(t *testing.T) {
instance = nil
Update(UpdateOption{})

_ = InitializeStatsdCollector(&StatsdCollectorConfig{}, "app-name")
_ = InitializeStatsdCollector(&StatsdCollectorConfig{})

mc := &mockStatsdClient{}
instance.client = mc
Expand Down Expand Up @@ -59,6 +60,64 @@ func TestUpdate(t *testing.T) {
mc.AssertExpectations(t)
}

func TestFormatter(t *testing.T) {
cases := []struct {
updateOption UpdateOption
expectedOutput string
}{
{
updateOption: UpdateOption{
Scope: "process_image",
Name: "duration",
Type: Duration,
},
expectedOutput: "process_image.duration",
},
{
updateOption: UpdateOption{
Name: "duration",
Type: Duration,
},
expectedOutput: fmt.Sprintf("%s.%s", DefaultScope, "duration"),
},
{
updateOption: UpdateOption{
Scope: ".scope",
Name: "duration",
Type: Duration,
},
expectedOutput: "scope.duration",
},
{
updateOption: UpdateOption{
Scope: ".scope.",
Name: "duration",
Type: Duration,
},
expectedOutput: "scope.duration",
},
{
updateOption: UpdateOption{
Scope: "scope.name",
Name: "duration",
Type: Duration,
},
expectedOutput: "scope.name.duration",
},
{
updateOption: UpdateOption{
Scope: ".scope.name.",
Name: ".duration.time.",
Type: Duration,
},
expectedOutput: "scope.name.duration.time",
},
}
for _, c := range cases {
assert.Equal(t, c.expectedOutput, formatter(c.updateOption))
}
}

type mockStatsdClient struct {
mock.Mock
}
Expand Down
9 changes: 0 additions & 9 deletions pkg/processor/native/processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,7 @@ const (
pngType = "png"
jpgType = "jpeg"

cropDurationKey = "cropDuration"
resizeDurationKey = "resizeDuration"
watermarkDurationKey = "watermarkDuration"
grayScaleDurationKey = "grayScaleDuration"
decodeDurationKey = "decodeDuration"
encodeDurationKey = "encodeDuration"
)
Expand All @@ -39,12 +36,10 @@ func (bp *BildProcessor) Crop(input []byte, width, height int, point processor.C

w, h := getResizeWidthAndHeightForCrop(width, height, img.Bounds().Dx(), img.Bounds().Dy())

t := time.Now()
img = transform.Resize(img, w, h, transform.Linear)
x0, y0 := getStartingPointForCrop(w, h, width, height, point)
rect := image.Rect(x0, y0, width+x0, height+y0)
img = (clone.AsRGBA(img)).SubImage(rect)
metrics.Update(metrics.UpdateOption{Name: cropDurationKey, Type: metrics.Duration, Duration: time.Since(t)})

return bp.encode(img, f)
}
Expand All @@ -60,9 +55,7 @@ func (bp *BildProcessor) Resize(input []byte, width, height int) ([]byte, error)

w, h := getResizeWidthAndHeight(width, height, initW, initH)
if w != initW || h != initH {
t := time.Now()
img = transform.Resize(img, w, h, transform.Linear)
metrics.Update(metrics.UpdateOption{Name: resizeDurationKey, Type: metrics.Duration, Duration: time.Since(t)})
}

return bp.encode(img, f)
Expand Down Expand Up @@ -106,9 +99,7 @@ func (bp *BildProcessor) GrayScale(input []byte) ([]byte, error) {
return nil, err
}

t := time.Now()
img = effect.Grayscale(img)
metrics.Update(metrics.UpdateOption{Name: grayScaleDurationKey, Type: metrics.Duration, Duration: time.Since(t)})

return bp.encode(img, f)
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/router/routes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,6 @@ func (m *mockStorage) Get(ctx context.Context, path string) storage.IResponse {
type mockManipulator struct {
}

func (m *mockManipulator) Process(ctx context.Context, data []byte, params map[string]string) ([]byte, error) {
func (m *mockManipulator) Process(spec service.ProcessSpec) ([]byte, error) {
return nil, nil
}
34 changes: 31 additions & 3 deletions pkg/service/manipulator.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package service

import (
"context"
"***REMOVED***/darkroom/core/pkg/metrics"
"***REMOVED***/darkroom/core/pkg/processor"
"strconv"
"time"
)

const (
Expand All @@ -13,25 +14,52 @@ const (
crop = "crop"
mono = "mono"
blackHexCode = "000000"

cropDurationKey = "cropDuration"
resizeDurationKey = "resizeDuration"
watermarkDurationKey = "watermarkDuration"
grayScaleDurationKey = "grayScaleDuration"
decodeDurationKey = "decodeDuration"
encodeDurationKey = "encodeDuration"
)

type Manipulator interface {
Process(ctx context.Context, data []byte, params map[string]string) ([]byte, error)
Process(spec ProcessSpec) ([]byte, error)
}

type manipulator struct {
processor processor.Processor
}

func (m *manipulator) Process(ctx context.Context, data []byte, params map[string]string) ([]byte, error) {
type ProcessSpec struct {
Scope string
ImageData []byte
Params map[string]string
}

func (m *manipulator) Process(spec ProcessSpec) ([]byte, error) {
params := spec.Params
data := spec.ImageData
var err error
if params[fit] == crop {
t := time.Now()
data, err = m.processor.Crop(data, CleanInt(params[width]), CleanInt(params[height]), GetCropPoint(params[crop]))
if err == nil {
metrics.Update(metrics.UpdateOption{Name: cropDurationKey, Type: metrics.Duration, Duration: time.Since(t), Scope: spec.Scope})
}
} else if len(params[fit]) == 0 && (CleanInt(params[width]) != 0 || CleanInt(params[height]) != 0) {
t := time.Now()
data, err = m.processor.Resize(data, CleanInt(params[width]), CleanInt(params[height]))
if err == nil {
metrics.Update(metrics.UpdateOption{Name: resizeDurationKey, Type: metrics.Duration, Duration: time.Since(t), Scope: spec.Scope})
}
}
if params[mono] == blackHexCode {
t := time.Now()
data, err = m.processor.GrayScale(data)
if err == nil {
metrics.Update(metrics.UpdateOption{Name: grayScaleDurationKey, Type: metrics.Duration, Duration: time.Since(t), Scope: spec.Scope})
}
}
return data, err
}
Expand Down
16 changes: 12 additions & 4 deletions pkg/service/manipulator_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package service

import (
"context"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"***REMOVED***/darkroom/core/pkg/processor"
Expand All @@ -24,7 +23,10 @@ func TestManipulator_Process(t *testing.T) {
params[fit] = crop
params[width] = "100"
params[height] = "100"
data, err := m.Process(context.TODO(), []byte("toCrop"), params)
data, err := m.Process(ProcessSpec{
ImageData: []byte("toCrop"),
Params: params,
})
assert.Nil(t, err)
assert.Equal(t, []byte("cropped"), data)

Expand All @@ -33,15 +35,21 @@ func TestManipulator_Process(t *testing.T) {
params = make(map[string]string)
params[width] = "100"
params[height] = "100"
data, err = m.Process(context.TODO(), []byte("toResize"), params)
data, err = m.Process(ProcessSpec{
ImageData: []byte("toResize"),
Params: params,
})
assert.Nil(t, err)
assert.Equal(t, []byte("reSized"), data)

mp.On("GrayScale", []byte("toGrayScale")).Return([]byte("grayScaled"), nil)

params = make(map[string]string)
params[mono] = blackHexCode
data, err = m.Process(context.TODO(), []byte("toGrayScale"), params)
data, err = m.Process(ProcessSpec{
ImageData: []byte("toGrayScale"),
Params: params,
})
assert.Nil(t, err)
assert.Equal(t, []byte("grayScaled"), data)
}
Expand Down

0 comments on commit 312118a

Please sign in to comment.