Skip to content

Commit 815d3fe

Browse files
authored
feat(GEN-95|HELIX-1134): add datadog and mixpanel support (#6)
* feat(GEN-95): add datadog support feat(HELIX-1134): add mixpanel support * feat(HELIX-1134): Counter generics * feat(HELIX-1134): remove threshold from count metric using mock
1 parent c71af53 commit 815d3fe

5 files changed

Lines changed: 255 additions & 29 deletions

File tree

client.go

Lines changed: 100 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
package metrics
22

33
import (
4-
"fmt"
4+
"runtime"
55
"sync"
66
"time"
77

88
dogstatsd "github.com/DataDog/datadog-go/v5/statsd"
9-
statsd "github.com/alexcesaro/statsd"
9+
"github.com/alexcesaro/statsd"
10+
"github.com/mixpanel/mixpanel-go"
1011
"github.com/pkg/errors"
1112
"go.opentelemetry.io/otel"
1213
"go.opentelemetry.io/otel/trace"
1314
ddotel "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/opentelemetry"
15+
"gopkg.in/DataDog/dd-trace-go.v1/profiler"
16+
17+
log "github.com/InjectiveLabs/suplog"
1418
)
1519

1620
const (
@@ -25,8 +29,9 @@ var (
2529
clientMux = new(sync.RWMutex)
2630
config *StatterConfig
2731

28-
traceProvider *ddotel.TracerProvider
29-
tracer trace.Tracer
32+
traceProvider *ddotel.TracerProvider
33+
tracer trace.Tracer
34+
mixPanelClient *mixpanel.ApiClient
3035
)
3136

3237
type StatterConfig struct {
@@ -35,10 +40,15 @@ type StatterConfig struct {
3540
Agent string // telegraf/datadog
3641
EnvName string // dev/test/staging/prod
3742
HostName string // hostname
43+
Version string // version
3844
StuckFunctionTimeout time.Duration // stuck time
45+
MockingThreshold time.Duration // mocking threshold
3946
MockingEnabled bool // whether to enable mock statter, which only produce logs
4047
Disabled bool // whether to disable metrics completely
4148
TracingEnabled bool // whether DataDog tracing should be enabled (via OpenTelemetry)
49+
ProfilingEnabled bool // whether Datadog profiling should be enabled
50+
MixPanelEnabled bool // whether MixPanel should be enabled
51+
MixPanelProjectToken string // MixPanel project token
4252
}
4353

4454
func (m *StatterConfig) BaseTags() []string {
@@ -82,35 +92,15 @@ func Close() {
8292
if client == nil {
8393
return
8494
}
85-
if traceProvider != nil {
86-
traceProvider.Shutdown()
87-
}
8895
client.Close()
8996
}
9097

91-
func Disable() {
92-
config = checkConfig(nil)
93-
clientMux.Lock()
94-
client = newMockStatter(true)
95-
clientMux.Unlock()
96-
tracer = nil
97-
}
98-
99-
func InitWithConfig(cfg *StatterConfig) error {
100-
return Init(cfg.Addr, cfg.Prefix, cfg)
101-
}
102-
10398
func Init(addr string, prefix string, cfg *StatterConfig) error {
104-
if cfg.Disabled {
105-
Disable()
106-
return nil
107-
}
108-
10999
config = checkConfig(cfg)
110100
if config.MockingEnabled {
111101
// init a mock statter instead of real statsd client
112102
clientMux.Lock()
113-
client = newMockStatter(false)
103+
client = newMockStatter(cfg)
114104
clientMux.Unlock()
115105
return nil
116106
}
@@ -150,12 +140,51 @@ func Init(addr string, prefix string, cfg *StatterConfig) error {
150140
clientMux.Unlock()
151141

152142
// OpenTelemetry tracing via DataDog provider
153-
if cfg.TracingEnabled {
143+
if cfg.Agent == DatadogAgent && cfg.TracingEnabled {
154144
traceProvider = ddotel.NewTracerProvider()
155145
otel.SetTracerProvider(traceProvider)
156146
tracer = otel.Tracer("")
157147
}
158148

149+
if cfg.Agent == DatadogAgent && cfg.ProfilingEnabled {
150+
err = setupProfiler(cfg)
151+
if err != nil {
152+
return err
153+
}
154+
}
155+
156+
if cfg.MixPanelEnabled {
157+
StartMixPanel(cfg.MixPanelProjectToken)
158+
}
159+
160+
return nil
161+
}
162+
163+
func StartMixPanel(projectToken string) {
164+
clientMux.Lock()
165+
defer clientMux.Unlock()
166+
mixPanelClient = mixpanel.NewApiClient(projectToken)
167+
}
168+
169+
func setupProfiler(cfg *StatterConfig) error {
170+
runtime.SetMutexProfileFraction(5)
171+
runtime.SetBlockProfileRate(5)
172+
173+
err := profiler.Start(
174+
profiler.WithService(cfg.Prefix),
175+
profiler.WithEnv(cfg.EnvName),
176+
profiler.WithHostname(cfg.HostName),
177+
profiler.WithVersion(cfg.Version),
178+
profiler.WithProfileTypes(
179+
profiler.CPUProfile,
180+
profiler.HeapProfile,
181+
profiler.BlockProfile,
182+
profiler.MutexProfile,
183+
),
184+
)
185+
if err != nil {
186+
return errors.Wrap(err, "profiler start failed")
187+
}
159188
return nil
160189
}
161190

@@ -173,44 +202,86 @@ func checkConfig(cfg *StatterConfig) *StatterConfig {
173202
}
174203

175204
func errHandler(err error) {
176-
fmt.Printf("statsd error, err: %v\n", err)
205+
log.WithError(err).Errorln("statsd error")
177206
}
178207

179-
func newMockStatter(noop bool) Statter {
180-
return &mockStatter{}
208+
func newMockStatter(cfg *StatterConfig) Statter {
209+
return &mockStatter{
210+
l: log.WithFields(log.Fields{
211+
"module": "mock_statter",
212+
}),
213+
threshold: cfg.MockingThreshold,
214+
}
181215
}
182216

183217
type mockStatter struct {
218+
l log.Logger
219+
threshold time.Duration
184220
}
185221

186222
func (s *mockStatter) Count(name string, value int64, tags []string, rate float64) error {
223+
s.l.WithFields(s.withTagFields(tags)).Debugf("Count %s: %v", name, value)
187224
return nil
188225
}
189226

190227
func (s *mockStatter) Incr(name string, tags []string, rate float64) error {
228+
if s.threshold > 0 {
229+
return nil
230+
}
231+
s.l.WithFields(s.withTagFields(tags)).Debugf("Incr %s", name)
191232
return nil
192233
}
193234

194235
func (s *mockStatter) Decr(name string, tags []string, rate float64) error {
236+
if s.threshold > 0 {
237+
return nil
238+
}
239+
s.l.WithFields(s.withTagFields(tags)).Debugf("Decr %s", name)
195240
return nil
196241
}
197242

198243
func (s *mockStatter) Gauge(name string, value float64, tags []string, rate float64) error {
244+
if s.threshold > 0 {
245+
return nil
246+
}
247+
s.l.WithFields(s.withTagFields(tags)).Debugf("Gauge %s: %v", name, value)
199248
return nil
200249
}
201250

202251
func (s *mockStatter) Timing(name string, value time.Duration, tags []string, rate float64) error {
252+
if value > s.threshold {
253+
s.l.WithFields(s.withTagFields(tags)).Debugf("Timing %s: %v", name, value)
254+
}
203255
return nil
204256
}
205257

206258
func (s *mockStatter) Histogram(name string, value float64, tags []string, rate float64) error {
259+
if value > float64(s.threshold.Milliseconds()) {
260+
s.l.WithFields(s.withTagFields(tags)).Debugf("Histogram %s: %v", name, value)
261+
}
207262
return nil
208263
}
209264

210265
func (s *mockStatter) Unique(bucket string, value string) error {
266+
if s.threshold > 0 {
267+
return nil
268+
}
269+
s.l.Debugf("Unique %s: %v", bucket, value)
211270
return nil
212271
}
213272

214273
func (s *mockStatter) Close() error {
274+
s.l.Debugf("closed at %s", time.Now())
215275
return nil
216276
}
277+
278+
func (s *mockStatter) withTagFields(tags []string) log.Fields {
279+
fields := make(log.Fields)
280+
for i := 0; i < len(tags); i += 2 {
281+
if i+1 >= len(tags) { // protect against odd number of tags
282+
break
283+
}
284+
fields[tags[i]] = tags[i+1]
285+
}
286+
return fields
287+
}

go.mod

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ go 1.22
44

55
require (
66
github.com/DataDog/datadog-go/v5 v5.3.0
7+
github.com/InjectiveLabs/suplog v1.3.3
78
github.com/alexcesaro/statsd v2.0.0+incompatible
89
github.com/cosmos/cosmos-sdk v0.50.6
10+
github.com/mixpanel/mixpanel-go v1.2.1
911
github.com/pkg/errors v0.9.1
1012
github.com/stretchr/testify v1.9.0
1113
go.opentelemetry.io/otel v1.24.0
@@ -29,11 +31,16 @@ require (
2931
github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.48.1 // indirect
3032
github.com/DataDog/go-libddwaf/v2 v2.3.2 // indirect
3133
github.com/DataDog/go-tuf v1.0.2-0.5.2 // indirect
34+
github.com/DataDog/gostackparse v0.7.0 // indirect
3235
github.com/DataDog/sketches-go v1.4.2 // indirect
3336
github.com/DataDog/zstd v1.5.5 // indirect
3437
github.com/Microsoft/go-winio v0.6.1 // indirect
38+
github.com/aws/aws-sdk-go v1.44.327 // indirect
3539
github.com/beorn7/perks v1.0.1 // indirect
40+
github.com/bitly/go-simplejson v0.5.1 // indirect
3641
github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect
42+
github.com/bugsnag/bugsnag-go v1.5.3 // indirect
43+
github.com/bugsnag/panicwrap v1.3.4 // indirect
3744
github.com/cespare/xxhash v1.1.0 // indirect
3845
github.com/cespare/xxhash/v2 v2.3.0 // indirect
3946
github.com/cockroachdb/errors v1.11.1 // indirect
@@ -61,12 +68,14 @@ require (
6168
github.com/go-logfmt/logfmt v0.6.0 // indirect
6269
github.com/go-logr/logr v1.4.1 // indirect
6370
github.com/go-logr/stdr v1.2.2 // indirect
71+
github.com/gofrs/uuid v4.4.0+incompatible // indirect
6472
github.com/gogo/protobuf v1.3.2 // indirect
6573
github.com/golang/glog v1.2.0 // indirect
6674
github.com/golang/protobuf v1.5.4 // indirect
6775
github.com/golang/snappy v0.0.4 // indirect
6876
github.com/google/btree v1.1.2 // indirect
6977
github.com/google/go-cmp v0.6.0 // indirect
78+
github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b // indirect
7079
github.com/google/uuid v1.6.0 // indirect
7180
github.com/hashicorp/errwrap v1.1.0 // indirect
7281
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
@@ -75,7 +84,9 @@ require (
7584
github.com/hashicorp/golang-lru v1.0.2 // indirect
7685
github.com/iancoleman/strcase v0.3.0 // indirect
7786
github.com/inconshreveable/mousetrap v1.1.0 // indirect
87+
github.com/jmespath/go-jmespath v0.4.0 // indirect
7888
github.com/jmhodges/levigo v1.0.0 // indirect
89+
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect
7990
github.com/klauspost/compress v1.17.7 // indirect
8091
github.com/kr/pretty v0.3.1 // indirect
8192
github.com/kr/text v0.2.0 // indirect
@@ -84,6 +95,7 @@ require (
8495
github.com/mattn/go-colorable v0.1.13 // indirect
8596
github.com/mattn/go-isatty v0.0.20 // indirect
8697
github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a // indirect
98+
github.com/oklog/ulid v1.3.1 // indirect
8799
github.com/outcaste-io/ristretto v0.2.3 // indirect
88100
github.com/petermattis/goid v0.0.0-20231207134359-e60b3f734c67 // indirect
89101
github.com/philhofer/fwd v1.1.2 // indirect
@@ -92,10 +104,13 @@ require (
92104
github.com/prometheus/client_model v0.6.1 // indirect
93105
github.com/prometheus/common v0.52.2 // indirect
94106
github.com/prometheus/procfs v0.13.0 // indirect
107+
github.com/richardartoul/molecule v1.0.1-0.20221107223329-32cfee06a052 // indirect
95108
github.com/rogpeppe/go-internal v1.12.0 // indirect
96109
github.com/rs/zerolog v1.32.0 // indirect
97110
github.com/sasha-s/go-deadlock v0.3.1 // indirect
98111
github.com/secure-systems-lab/go-securesystemslib v0.7.0 // indirect
112+
github.com/sirupsen/logrus v1.9.3 // indirect
113+
github.com/spaolacci/murmur3 v1.1.0 // indirect
99114
github.com/spf13/cast v1.6.0 // indirect
100115
github.com/spf13/cobra v1.8.0 // indirect
101116
github.com/spf13/pflag v1.0.5 // indirect

0 commit comments

Comments
 (0)