From ea1dcf9cc8942c03fcf972c82c715c20a07c3ba6 Mon Sep 17 00:00:00 2001 From: Mirac Kara <55501260+mirackara@users.noreply.github.com> Date: Wed, 29 Jun 2022 15:02:23 -0500 Subject: [PATCH] Custom Events Limiter (#524) Allows custom events to be configured by users and adds tests to verify changes. --- v3/internal/connect_reply.go | 8 ++++---- v3/internal/connect_reply_test.go | 2 +- v3/newrelic/config.go | 21 +++++++++++++++++---- v3/newrelic/config_options.go | 7 +++++++ v3/newrelic/config_test.go | 20 ++++++++++++++++++-- 5 files changed, 47 insertions(+), 11 deletions(-) diff --git a/v3/internal/connect_reply.go b/v3/internal/connect_reply.go index 342c140d5..caea20ccf 100644 --- a/v3/internal/connect_reply.go +++ b/v3/internal/connect_reply.go @@ -137,11 +137,11 @@ func (r *ConnectReply) ConfigurablePeriod() time.Duration { func uintPtr(x uint) *uint { return &x } // DefaultEventHarvestConfig provides faster event harvest defaults. -func DefaultEventHarvestConfig(maxTxnEvents, maxLogEvents int) EventHarvestConfig { +func DefaultEventHarvestConfig(maxTxnEvents, maxLogEvents, maxCustomEvents int) EventHarvestConfig { cfg := EventHarvestConfig{} cfg.ReportPeriodMs = DefaultConfigurableEventHarvestMs cfg.Limits.TxnEvents = uintPtr(uint(maxTxnEvents)) - cfg.Limits.CustomEvents = uintPtr(uint(MaxCustomEvents)) + cfg.Limits.CustomEvents = uintPtr(uint(maxCustomEvents)) cfg.Limits.LogEvents = uintPtr(uint(maxLogEvents)) cfg.Limits.ErrorEvents = uintPtr(uint(MaxErrorEvents)) return cfg @@ -149,8 +149,8 @@ func DefaultEventHarvestConfig(maxTxnEvents, maxLogEvents int) EventHarvestConfi // DefaultEventHarvestConfigWithDT is an extended version of DefaultEventHarvestConfig, // with the addition that it takes into account distributed tracer span event harvest limits. -func DefaultEventHarvestConfigWithDT(maxTxnEvents, maxLogEvents, spanEventLimit int, dtEnabled bool) EventHarvestConfig { - cfg := DefaultEventHarvestConfig(maxTxnEvents, maxLogEvents) +func DefaultEventHarvestConfigWithDT(maxTxnEvents, maxLogEvents, maxCustomEvents, spanEventLimit int, dtEnabled bool) EventHarvestConfig { + cfg := DefaultEventHarvestConfig(maxTxnEvents, maxLogEvents, maxCustomEvents) if dtEnabled { cfg.Limits.SpanEvents = uintPtr(uint(spanEventLimit)) } diff --git a/v3/internal/connect_reply_test.go b/v3/internal/connect_reply_test.go index eb9711354..d21366baf 100644 --- a/v3/internal/connect_reply_test.go +++ b/v3/internal/connect_reply_test.go @@ -173,7 +173,7 @@ func TestNegativeHarvestLimits(t *testing.T) { } func TestDefaultEventHarvestConfigJSON(t *testing.T) { - js, err := json.Marshal(DefaultEventHarvestConfig(MaxTxnEvents, MaxLogEvents)) + js, err := json.Marshal(DefaultEventHarvestConfig(MaxTxnEvents, MaxLogEvents, MaxCustomEvents)) if err != nil { t.Error(err) } diff --git a/v3/newrelic/config.go b/v3/newrelic/config.go index 1abf253a7..ecf7ff45b 100644 --- a/v3/newrelic/config.go +++ b/v3/newrelic/config.go @@ -71,6 +71,8 @@ type Config struct { // custom analytics events. High security mode overrides this // setting. Enabled bool + // MaxSamplesStored sets the desired maximum custom event samples stored + MaxSamplesStored int } // TransactionEvents controls the behavior of transaction analytics @@ -408,6 +410,7 @@ func defaultConfig() Config { c.Enabled = true c.Labels = make(map[string]string) c.CustomInsightsEvents.Enabled = true + c.CustomInsightsEvents.MaxSamplesStored = internal.MaxCustomEvents c.TransactionEvents.Enabled = true c.TransactionEvents.Attributes.Enabled = true c.TransactionEvents.MaxSamplesStored = internal.MaxTxnEvents @@ -545,12 +548,22 @@ func (c Config) maxTxnEvents() int { return configured } -// maxTxnEvents returns the configured maximum number of Transaction Events if it has been configured +// maxCustomEvents returns the configured maximum number of Custom Events if it has been configured +// and is less than the default maximum; otherwise it returns the default max. +func (c Config) maxCustomEvents() int { + configured := c.CustomInsightsEvents.MaxSamplesStored + if configured < 0 || configured > internal.MaxCustomEvents { + return internal.MaxCustomEvents + } + return configured +} + +// maxLogEvents returns the configured maximum number of Log Events if it has been configured // and is less than the default maximum; otherwise it returns the default max. func (c Config) maxLogEvents() int { configured := c.ApplicationLogging.Forwarding.MaxSamplesStored - if configured < 0 || configured > internal.MaxTxnEvents { - return internal.MaxTxnEvents + if configured < 0 || configured > internal.MaxLogEvents { + return internal.MaxLogEvents } return configured } @@ -709,7 +722,7 @@ func configConnectJSONInternal(c Config, pid int, util *utilization.Data, e envi Util: util, SecurityPolicies: securityPolicies, Metadata: metadata, - EventData: internal.DefaultEventHarvestConfigWithDT(c.maxTxnEvents(), c.maxLogEvents(), c.DistributedTracer.ReservoirLimit, c.DistributedTracer.Enabled), + EventData: internal.DefaultEventHarvestConfigWithDT(c.maxTxnEvents(), c.maxLogEvents(), c.maxCustomEvents(), c.DistributedTracer.ReservoirLimit, c.DistributedTracer.Enabled), }}) } diff --git a/v3/newrelic/config_options.go b/v3/newrelic/config_options.go index 55ec64823..dbcb666a3 100644 --- a/v3/newrelic/config_options.go +++ b/v3/newrelic/config_options.go @@ -36,6 +36,13 @@ func ConfigDistributedTracerEnabled(enabled bool) ConfigOption { return func(cfg *Config) { cfg.DistributedTracer.Enabled = enabled } } +// ConfigCustomInsightsEventsMaxSamplesStored alters the sample size allowing control +// of how many custom events are stored in an agent for a given harvest cycle. +// Alters the CustomInsightsEvents.MaxSamplesStored setting. +func ConfigCustomInsightsEventsMaxSamplesStored(limit int) ConfigOption { + return func(cfg *Config) { cfg.CustomInsightsEvents.MaxSamplesStored = limit } +} + // ConfigDistributedTracerReservoirLimit alters the sample reservoir size (maximum // number of span events to be collected) for distributed tracing instead of // using the built-in default. diff --git a/v3/newrelic/config_test.go b/v3/newrelic/config_test.go index 6b159976a..2d77efe8a 100644 --- a/v3/newrelic/config_test.go +++ b/v3/newrelic/config_test.go @@ -145,7 +145,10 @@ func TestCopyConfigReferenceFieldsPresent(t *testing.T) { "Enabled":true }, "CrossApplicationTracer":{"Enabled":false}, - "CustomInsightsEvents":{"Enabled":true}, + "CustomInsightsEvents":{ + "Enabled":true, + "MaxSamplesStored":10000 + }, "DatastoreTracer":{ "DatabaseNameReporting":{"Enabled":true}, "InstanceReporting":{"Enabled":true}, @@ -333,7 +336,10 @@ func TestCopyConfigReferenceFieldsAbsent(t *testing.T) { "Enabled":true }, "CrossApplicationTracer":{"Enabled":false}, - "CustomInsightsEvents":{"Enabled":true}, + "CustomInsightsEvents":{ + "Enabled":true, + "MaxSamplesStored":10000 + }, "DatastoreTracer":{ "DatabaseNameReporting":{"Enabled":true}, "InstanceReporting":{"Enabled":true}, @@ -797,3 +803,13 @@ func TestNewInternalConfig(t *testing.T) { t.Error(c.metadata) } } + +func TestConfigurableMaxCustomEvents(t *testing.T) { + expected := 1000 + cfg := config{Config: defaultConfig()} + cfg.CustomInsightsEvents.MaxSamplesStored = expected + result := cfg.maxCustomEvents() + if result != expected { + t.Errorf("Unexpected max number of custom events, expected %d but got %d", expected, result) + } +}