From dcc8e066ea2f7b55b033269744b39876c5261364 Mon Sep 17 00:00:00 2001 From: William Easton Date: Wed, 4 Sep 2024 12:52:44 -0500 Subject: [PATCH 1/4] Add option to prevent new session creation --- .../processors/script/javascript/config.go | 22 ++++++++++--------- .../processors/script/javascript/session.go | 15 ++++++++++--- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/libbeat/processors/script/javascript/config.go b/libbeat/processors/script/javascript/config.go index 03415a96d1b..4074ab3f974 100644 --- a/libbeat/processors/script/javascript/config.go +++ b/libbeat/processors/script/javascript/config.go @@ -24,14 +24,15 @@ import ( // Config defines the Javascript source files to use for the processor. type Config struct { - Tag string `config:"tag"` // Processor ID for debug and metrics. - Source string `config:"source"` // Inline script to execute. - File string `config:"file"` // Source file. - Files []string `config:"files"` // Multiple source files. - Params map[string]interface{} `config:"params"` // Parameters to pass to script. - Timeout time.Duration `config:"timeout" validate:"min=0"` // Execution timeout. - TagOnException string `config:"tag_on_exception"` // Tag to add to events when an exception happens. - MaxCachedSessions int `config:"max_cached_sessions" validate:"min=0"` // Max. number of cached VM sessions. + Tag string `config:"tag"` // Processor ID for debug and metrics. + Source string `config:"source"` // Inline script to execute. + File string `config:"file"` // Source file. + Files []string `config:"files"` // Multiple source files. + Params map[string]interface{} `config:"params"` // Parameters to pass to script. + Timeout time.Duration `config:"timeout" validate:"min=0"` // Execution timeout. + TagOnException string `config:"tag_on_exception"` // Tag to add to events when an exception happens. + MaxCachedSessions int `config:"max_cached_sessions" validate:"min=0"` // Max. number of cached VM sessions. + OnlyCachedSessions bool `config:"only_cached_sessions"` // Only use cached VM sessions. } // Validate returns an error if one (and only one) option is not set. @@ -57,7 +58,8 @@ func (c Config) Validate() error { func defaultConfig() Config { return Config{ - TagOnException: "_js_exception", - MaxCachedSessions: 4, + TagOnException: "_js_exception", + MaxCachedSessions: 4, + OnlyCachedSessions: false, } } diff --git a/libbeat/processors/script/javascript/session.go b/libbeat/processors/script/javascript/session.go index 5b08e7d6052..a85d432a8b1 100644 --- a/libbeat/processors/script/javascript/session.go +++ b/libbeat/processors/script/javascript/session.go @@ -273,8 +273,9 @@ func init() { } type sessionPool struct { - New func() *session - C chan *session + New func() *session + C chan *session + NewAllowed bool } func newSessionPool(p *goja.Program, c Config) (*sessionPool, error) { @@ -288,7 +289,8 @@ func newSessionPool(p *goja.Program, c Config) (*sessionPool, error) { s, _ := newSession(p, c, false) return s }, - C: make(chan *session, c.MaxCachedSessions), + C: make(chan *session, c.MaxCachedSessions), + NewAllowed: !c.OnlyCachedSessions, } pool.Put(s) @@ -296,6 +298,13 @@ func newSessionPool(p *goja.Program, c Config) (*sessionPool, error) { } func (p *sessionPool) Get() *session { + + // Only create a new session if it is allowed. + if !p.NewAllowed { + // wait for a session to be available + return <-p.C + } + select { case s := <-p.C: return s From 7bfdba024c7c6997415b14dda9b0d660674347fa Mon Sep 17 00:00:00 2001 From: William Easton Date: Wed, 4 Sep 2024 12:56:19 -0500 Subject: [PATCH 2/4] add changelog --- CHANGELOG.next.asciidoc | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.next.asciidoc b/CHANGELOG.next.asciidoc index 0ece7c88964..e6e21b2c7eb 100644 --- a/CHANGELOG.next.asciidoc +++ b/CHANGELOG.next.asciidoc @@ -221,6 +221,7 @@ https://github.com/elastic/beats/compare/v8.8.1\...main[Check the HEAD diff] - Enable early event encoding in the Elasticsearch output, improving cpu and memory use {pull}38572[38572] - The environment variable `BEATS_ADD_CLOUD_METADATA_PROVIDERS` overrides configured/default `add_cloud_metadata` providers {pull}38669[38669] - When running under Elastic-Agent Kafka output allows dynamic topic in `topic` field {pull}40415[40415] +- The script processor has a new configuration option that only uses the cached javascript sessions and prevents the creation of new javascript sessions. *Auditbeat* From ef8e6dfaf7980586d041a7c8f548b2e92361bb72 Mon Sep 17 00:00:00 2001 From: William Easton Date: Wed, 4 Sep 2024 13:18:26 -0500 Subject: [PATCH 3/4] Pre-create requested cached sessions --- .../processors/script/javascript/session.go | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/libbeat/processors/script/javascript/session.go b/libbeat/processors/script/javascript/session.go index a85d432a8b1..5a9609f94b1 100644 --- a/libbeat/processors/script/javascript/session.go +++ b/libbeat/processors/script/javascript/session.go @@ -273,9 +273,9 @@ func init() { } type sessionPool struct { - New func() *session - C chan *session - NewAllowed bool + New func() *session + C chan *session + NewSessionsAllowed bool } func newSessionPool(p *goja.Program, c Config) (*sessionPool, error) { @@ -289,22 +289,28 @@ func newSessionPool(p *goja.Program, c Config) (*sessionPool, error) { s, _ := newSession(p, c, false) return s }, - C: make(chan *session, c.MaxCachedSessions), - NewAllowed: !c.OnlyCachedSessions, + C: make(chan *session, c.MaxCachedSessions), + NewSessionsAllowed: !c.OnlyCachedSessions, } pool.Put(s) + // If we are not allowed to create new sessions, pre-cache requested sessions + if !pool.NewSessionsAllowed { + for i := 0; i < c.MaxCachedSessions-1; i++ { + pool.Put(pool.New()) + } + } + return &pool, nil } func (p *sessionPool) Get() *session { - // Only create a new session if it is allowed. - if !p.NewAllowed { - // wait for a session to be available + if !p.NewSessionsAllowed { return <-p.C } + // Try to get a session from the pool, if none is available, create a new one select { case s := <-p.C: return s From 4d0d8e683fede6584f216462e2015d62abfc43fd Mon Sep 17 00:00:00 2001 From: William Easton Date: Wed, 4 Sep 2024 15:17:26 -0500 Subject: [PATCH 4/4] Make the linter happy --- libbeat/processors/script/javascript/session.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libbeat/processors/script/javascript/session.go b/libbeat/processors/script/javascript/session.go index 5a9609f94b1..94e344d4e22 100644 --- a/libbeat/processors/script/javascript/session.go +++ b/libbeat/processors/script/javascript/session.go @@ -91,7 +91,7 @@ func newSession(p *goja.Program, conf Config, test bool) (*session, error) { // Measure load times start := time.Now() defer func() { - took := time.Now().Sub(start) + took := time.Since(start) logger.Debugf("Load of javascript pipeline took %v", took) }() // Setup JS runtime. @@ -217,9 +217,9 @@ func (s *session) runProcessFunc(b *beat.Event) (out *beat.Event, err error) { } err = fmt.Errorf("unexpected panic in javascript processor: %v", r) if s.tagOnException != "" { - mapstr.AddTags(b.Fields, []string{s.tagOnException}) + _ = mapstr.AddTags(b.Fields, []string{s.tagOnException}) } - appendString(b.Fields, "error.message", err.Error(), false) + _ = appendString(b.Fields, "error.message", err.Error(), false) } }() @@ -238,9 +238,9 @@ func (s *session) runProcessFunc(b *beat.Event) (out *beat.Event, err error) { if _, err = s.processFunc(goja.Undefined(), s.evt.JSObject()); err != nil { if s.tagOnException != "" { - mapstr.AddTags(b.Fields, []string{s.tagOnException}) + _ = mapstr.AddTags(b.Fields, []string{s.tagOnException}) } - appendString(b.Fields, "error.message", err.Error(), false) + _ = appendString(b.Fields, "error.message", err.Error(), false) return b, fmt.Errorf("failed in process function: %w", err) }