<commit_before>package cloudwatch

import (
	"sync"

	"github.com/aws/aws-sdk-go/service/cloudwatch"
	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/metrics"
	"github.com/go-kit/kit/metrics/generic"
)

// CloudWatch ...
type CloudWatch struct {
	mtx      sync.RWMutex
	prefix   string
	svc      *cloudwatch.CloudWatch
	counters map[string]*Counter
	//gauges     map[string]*Gauge
	//histograms map[string]*Histogram
	logger log.Logger
}

func New(prefix string, logger log.Logger, svc *cloudwatch.CloudWatch) *CloudWatch {
	return &CloudWatch{
		prefix:   prefix,
		svc:      svc,
		counters: map[string]*Counter{},
		logger:   logger,
	}
}

func (cw *CloudWatch) NewCounter(name string) *Counter {
	c := NewCounter(cw.prefix, name)
	cw.mtx.Lock()
	cw.counters[cw.prefix+name] = c
	cw.mtx.Unlock()
	return c
}

// Counter is a Graphite counter metric.
type Counter struct {
	namespace string
	c         *generic.Counter
}

// NewCounter returns a new usable counter metric.
func NewCounter(namespace, name string) *Counter {
	return &Counter{
		namespace: namespace,
		c:         generic.NewCounter(name),
	}
}

// With is a no-op.
func (c *Counter) With(labelValues ...string) metrics.Counter {
	return c.c.With(labelValues...)
}

// Add implements counter.
func (c *Counter) Add(delta float64) {
	c.c.Add(delta)
}
<commit_msg>Use WriteLoop approach to reduce api overhead.<commit_after>package cloudwatch

import (
	"sync"

	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/cloudwatch"
	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/metrics"
	"github.com/go-kit/kit/metrics/generic"
)

// CloudWatch ...
type CloudWatch struct {
	mtx      sync.RWMutex
	prefix   string
	svc      *cloudwatch.CloudWatch
	counters map[string]*Counter
	logger   log.Logger
}

// New ...
func New(prefix string, logger log.Logger, svc *cloudwatch.CloudWatch) *CloudWatch {
	return &CloudWatch{
		prefix:   prefix,
		svc:      svc,
		counters: map[string]*Counter{},
		logger:   logger,
	}
}

func (cw *CloudWatch) NewCounter(name string) *Counter {
	c := NewCounter(name)
	cw.mtx.Lock()
	cw.counters[cw.prefix+name] = c
	cw.mtx.Unlock()
	return c
}

// WriteLoop is a helper method that invokes WriteTo to the passed writer every
// time the passed channel fires. This method blocks until the channel is
// closed, so clients probably want to run it in its own goroutine. For typical
// usage, create a time.Ticker and pass its C channel to this method.
func (cw *CloudWatch) WriteLoop(c <-chan time.Time) {
	for range c {
		cw.mtx.RLock()
		defer cw.mtx.RUnlock()
		now := time.Now()

		for name, c := range cw.counters {
			_, err := cw.svc.PutMetricData(&cloudwatch.PutMetricDataInput{
				Namespace: aws.String(cw.prefix),
				MetricData: []*cloudwatch.MetricDatum{
					{
						MetricName: aws.String(name),
						Dimensions: makeDimensions(c.c.LabelValues()...),
						Value:      aws.Float64(c.c.Value()),
						Timestamp:  aws.Time(now),
					},
				},
			})
			if err != nil {
				cw.logger.Log("during", "WriteLoop", "err", err)
			}
		}
	}
}

// Counter is a CloudWatch counter metric.
type Counter struct {
	c *generic.Counter
}

// NewCounter returns a new usable counter metric.
func NewCounter(name string) *Counter {
	return &Counter{
		c: generic.NewCounter(name),
	}
}

// With is a no-op.
func (c *Counter) With(labelValues ...string) metrics.Counter {
	return c.c.With(labelValues...)
}

// Add implements counter.
func (c *Counter) Add(delta float64) {
	c.c.Add(delta)
}

func makeDimensions(labelValues ...string) []*cloudwatch.Dimension {
	dimensions := make([]*cloudwatch.Dimension, len(labelValues)/2)
	for i, j := 0, 0; i < len(labelValues); i, j := i+2, j+1 {
		dimensions[j] = &cloudwatch.Dimension{
			Name:  aws.String(labelValues[i]),
			Value: aws.String(labelValues[i+1]),
		}
	}
	return dimensions
}

{'fraction_non_alphanumeric': 0.13985469641930462, 'fraction_numerical': 0.0031136481577581734, 'mean_word_length': 3.4310344827586206, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1985979', 'n_tokens_mistral': 1454, 'n_tokens_neox': 1375, 'n_words': 338}