From 8feeb49bfa90e274d8d834174f905ffe2ae876b6 Mon Sep 17 00:00:00 2001 From: VihasMakwana <121151420+VihasMakwana@users.noreply.github.com> Date: Mon, 2 Mar 2026 19:34:07 +0530 Subject: [PATCH 01/10] add state storage extension --- internal/edot/otelcol/components.go | 2 + .../otel/extension/elasticstorage/config.go | 37 ++++ .../extension/elasticstorage/extension.go | 50 +++++ .../otel/extension/elasticstorage/factory.go | 21 ++ .../generated_component_test.go | 68 ++++++ .../elasticstorage/generated_package_test.go | 12 ++ .../internal/metadata/generated_status.go | 16 ++ .../extension/elasticstorage/metadata.yaml | 9 + .../otel/extension/elasticstorage/store.go | 199 ++++++++++++++++++ internal/pkg/otel/translate/otelconfig.go | 6 + 10 files changed, 420 insertions(+) create mode 100644 internal/pkg/otel/extension/elasticstorage/config.go create mode 100644 internal/pkg/otel/extension/elasticstorage/extension.go create mode 100644 internal/pkg/otel/extension/elasticstorage/factory.go create mode 100644 internal/pkg/otel/extension/elasticstorage/generated_component_test.go create mode 100644 internal/pkg/otel/extension/elasticstorage/generated_package_test.go create mode 100644 internal/pkg/otel/extension/elasticstorage/internal/metadata/generated_status.go create mode 100644 internal/pkg/otel/extension/elasticstorage/metadata.yaml create mode 100644 internal/pkg/otel/extension/elasticstorage/store.go diff --git a/internal/edot/otelcol/components.go b/internal/edot/otelcol/components.go index faf6124c5d0..ba339c3e046 100644 --- a/internal/edot/otelcol/components.go +++ b/internal/edot/otelcol/components.go @@ -94,6 +94,7 @@ import ( "go.opentelemetry.io/collector/extension/memorylimiterextension" // for putting backpressure when approach a memory limit elasticdiagnostics "github.com/elastic/elastic-agent/internal/pkg/otel/extension/elasticdiagnostics" + elasticstorage "github.com/elastic/elastic-agent/internal/pkg/otel/extension/elasticstorage" "github.com/elastic/opentelemetry-collector-components/extension/apikeyauthextension" "github.com/elastic/opentelemetry-collector-components/extension/apmconfigextension" @@ -238,6 +239,7 @@ func components(extensionFactories ...extension.Factory) func() (otelcol.Factori headersetterextension.NewFactory(), beatsauthextension.NewFactory(), elasticdiagnostics.NewFactory(), + elasticstorage.NewFactory(), awslogsencodingextension.NewFactory(), opampextension.NewFactory(), } diff --git a/internal/pkg/otel/extension/elasticstorage/config.go b/internal/pkg/otel/extension/elasticstorage/config.go new file mode 100644 index 00000000000..d5371aaae0b --- /dev/null +++ b/internal/pkg/otel/extension/elasticstorage/config.go @@ -0,0 +1,37 @@ +// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +// or more contributor license agreements. Licensed under the Elastic License 2.0; +// you may not use this file except in compliance with the Elastic License 2.0. + +package elasticstorage + +import ( + "go.opentelemetry.io/collector/component" +) + +type Config struct { + // Hosts []string `mapstructure:"hosts"` + // Protocol string `mapstructure:"protocol"` + // Path string `mapstructure:"path"` + // Params map[string]string `mapstructure:"parameters"` + // Headers map[string]string `mapstructure:"headers"` + + // Kerberos *kerberos.Config `mapstructure:"kerberos"` + + // Username string `mapstructure:"username"` + // Password string `mapstructure:"password"` + // APIKey string `mapstructure:"api_key"` + + // CompressionLevel int `mapstructure:"compression_level"` + // EscapeHTML bool `mapstructure:"escape_html"` + + // Transport httpcommon.HTTPTransportSettings `mapstructure:",squash"` + ElasticsearchConfig map[string]interface{} `mapstructure:",remain"` +} + +func createDefaultConfig() component.Config { + return &Config{} +} + +func (c *Config) Validate() error { + return nil +} diff --git a/internal/pkg/otel/extension/elasticstorage/extension.go b/internal/pkg/otel/extension/elasticstorage/extension.go new file mode 100644 index 00000000000..83e3a56f579 --- /dev/null +++ b/internal/pkg/otel/extension/elasticstorage/extension.go @@ -0,0 +1,50 @@ +package elasticstorage + +import ( + "context" + + "github.com/elastic/beats/v7/libbeat/esleg/eslegclient" + "github.com/elastic/beats/v7/libbeat/statestore/backend" + cfg "github.com/elastic/elastic-agent-libs/config" + "github.com/elastic/elastic-agent-libs/logp" + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/extension" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" +) + +var _ extension.Extension = (*elasticStorage)(nil) +var _ backend.Registry = (*elasticStorage)(nil) + +type elasticStorage struct { + cfg *Config + logger *zap.Logger + client *eslegclient.Connection +} + +func (e *elasticStorage) Start(ctx context.Context, host component.Host) error { + c, err := cfg.NewConfigFrom(e.cfg.ElasticsearchConfig) + if err != nil { + return err + } + client, err := eslegclient.NewConnectedClient(ctx, c, "Filebeat", logp.NewLogger("", zap.WrapCore(func(zapcore.Core) zapcore.Core { + return e.logger.Core() + }))) + if err != nil { + return err + } + e.client = client + return nil +} + +func (e *elasticStorage) Shutdown(ctx context.Context) error { + return e.client.Close() +} + +func (e *elasticStorage) Access(name string) (backend.Store, error) { + return openStore(e.client, name) +} + +func (e *elasticStorage) Close() error { + return e.client.Close() +} diff --git a/internal/pkg/otel/extension/elasticstorage/factory.go b/internal/pkg/otel/extension/elasticstorage/factory.go new file mode 100644 index 00000000000..4651dcb91d4 --- /dev/null +++ b/internal/pkg/otel/extension/elasticstorage/factory.go @@ -0,0 +1,21 @@ +// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +// or more contributor license agreements. Licensed under the Elastic License 2.0; +// you may not use this file except in compliance with the Elastic License 2.0. + +package elasticstorage + +import ( + "context" + + "github.com/elastic/elastic-agent/internal/pkg/otel/extension/elasticstorage/internal/metadata" + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/extension" +) + +func NewFactory() extension.Factory { + return extension.NewFactory(metadata.Type, createDefaultConfig, newExtension, component.StabilityLevelDevelopment) +} + +func newExtension(ctx context.Context, set extension.Settings, cfg component.Config) (extension.Extension, error) { + return &elasticStorage{cfg: cfg.(*Config), logger: set.Logger.Named("elasticstorage")}, nil +} diff --git a/internal/pkg/otel/extension/elasticstorage/generated_component_test.go b/internal/pkg/otel/extension/elasticstorage/generated_component_test.go new file mode 100644 index 00000000000..1eced305c0e --- /dev/null +++ b/internal/pkg/otel/extension/elasticstorage/generated_component_test.go @@ -0,0 +1,68 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package elasticstorage + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/component/componenttest" + "go.opentelemetry.io/collector/confmap/confmaptest" + "go.opentelemetry.io/collector/extension/extensiontest" +) + +var typ = component.MustNewType("elastic_storage") + +func TestComponentFactoryType(t *testing.T) { + require.Equal(t, typ, NewFactory().Type()) +} + +func TestComponentConfigStruct(t *testing.T) { + require.NoError(t, componenttest.CheckConfigStruct(NewFactory().CreateDefaultConfig())) +} + +func TestComponentLifecycle(t *testing.T) { + factory := NewFactory() + + cm, err := confmaptest.LoadConf("metadata.yaml") + require.NoError(t, err) + cfg := factory.CreateDefaultConfig() + sub, err := cm.Sub("tests::config") + require.NoError(t, err) + require.NoError(t, sub.Unmarshal(&cfg)) + t.Run("shutdown", func(t *testing.T) { + e, err := factory.Create(context.Background(), extensiontest.NewNopSettings(typ), cfg) + require.NoError(t, err) + err = e.Shutdown(context.Background()) + require.NoError(t, err) + }) + t.Run("lifecycle", func(t *testing.T) { + firstExt, err := factory.Create(context.Background(), extensiontest.NewNopSettings(typ), cfg) + require.NoError(t, err) + require.NoError(t, firstExt.Start(context.Background(), newMdatagenNopHost())) + require.NoError(t, firstExt.Shutdown(context.Background())) + + secondExt, err := factory.Create(context.Background(), extensiontest.NewNopSettings(typ), cfg) + require.NoError(t, err) + require.NoError(t, secondExt.Start(context.Background(), newMdatagenNopHost())) + require.NoError(t, secondExt.Shutdown(context.Background())) + }) +} + +var _ component.Host = (*mdatagenNopHost)(nil) + +type mdatagenNopHost struct{} + +func newMdatagenNopHost() component.Host { + return &mdatagenNopHost{} +} + +func (mnh *mdatagenNopHost) GetExtensions() map[component.ID]component.Component { + return nil +} + +func (mnh *mdatagenNopHost) GetFactory(_ component.Kind, _ component.Type) component.Factory { + return nil +} diff --git a/internal/pkg/otel/extension/elasticstorage/generated_package_test.go b/internal/pkg/otel/extension/elasticstorage/generated_package_test.go new file mode 100644 index 00000000000..7afd311633d --- /dev/null +++ b/internal/pkg/otel/extension/elasticstorage/generated_package_test.go @@ -0,0 +1,12 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package elasticstorage + +import ( + "go.uber.org/goleak" + "testing" +) + +func TestMain(m *testing.M) { + goleak.VerifyTestMain(m) +} diff --git a/internal/pkg/otel/extension/elasticstorage/internal/metadata/generated_status.go b/internal/pkg/otel/extension/elasticstorage/internal/metadata/generated_status.go new file mode 100644 index 00000000000..14b559768ac --- /dev/null +++ b/internal/pkg/otel/extension/elasticstorage/internal/metadata/generated_status.go @@ -0,0 +1,16 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package metadata + +import ( + "go.opentelemetry.io/collector/component" +) + +var ( + Type = component.MustNewType("elastic_storage") + ScopeName = "github.com/elastic/elastic-agent/internal/pkg/otel/extension/elasticstorage" +) + +const ( + ExtensionStability = component.StabilityLevelDevelopment +) diff --git a/internal/pkg/otel/extension/elasticstorage/metadata.yaml b/internal/pkg/otel/extension/elasticstorage/metadata.yaml new file mode 100644 index 00000000000..c7de9e5e312 --- /dev/null +++ b/internal/pkg/otel/extension/elasticstorage/metadata.yaml @@ -0,0 +1,9 @@ +type: elastic_storage +github_project: elastic/elastic-agent + +status: + class: extension + stability: + development: [extension] + codeowners: + active: [VihasMakwana] diff --git a/internal/pkg/otel/extension/elasticstorage/store.go b/internal/pkg/otel/extension/elasticstorage/store.go new file mode 100644 index 00000000000..9e69ff82158 --- /dev/null +++ b/internal/pkg/otel/extension/elasticstorage/store.go @@ -0,0 +1,199 @@ +package elasticstorage + +import ( + "encoding/json" + "errors" + "fmt" + "net/http" + "net/url" + "sync" + "time" + + "github.com/elastic/beats/v7/libbeat/esleg/eslegclient" + "github.com/elastic/beats/v7/libbeat/statestore/backend" + "github.com/elastic/elastic-agent-libs/transform/typeconv" +) + +type store struct { + client *eslegclient.Connection + index string + mx sync.Mutex +} + +type queryResult struct { + Found bool `json:"found"` + Source struct { + Value json.RawMessage `json:"v"` + } `json:"_source"` +} + +type doc struct { + Value any `struct:"v"` + UpdatedAt any `struct:"updated_at"` +} + +var ErrKeyUnknown = errors.New("key unknown") + +const docType = "_doc" + +var _ backend.Store = (*store)(nil) + +func openStore(client *eslegclient.Connection, name string) (*store, error) { + return &store{ + client: client, + index: renderIndexName(name), + }, nil +} + +func (s *store) Close() error { + return nil +} + +func (s *store) Has(key string) (bool, error) { + s.mx.Lock() + defer s.mx.Unlock() + + var v interface{} + err := s.get(key, v) + if err != nil { + if errors.Is(err, ErrKeyUnknown) { + return false, nil + } + return false, err + } + return true, nil +} + +func (s *store) Get(key string, to interface{}) error { + s.mx.Lock() + defer s.mx.Unlock() + + return s.get(key, to) +} + +func (s *store) get(key string, to interface{}) error { + status, data, err := s.client.Request("GET", fmt.Sprintf("/%s/%s/%s", s.index, docType, url.QueryEscape(key)), "", nil, nil) + + if err != nil { + if status == http.StatusNotFound { + return ErrKeyUnknown + } + return err + } + + var qr queryResult + err = json.Unmarshal(data, &qr) + if err != nil { + return err + } + + err = json.Unmarshal(qr.Source.Value, to) + if err != nil { + return err + } + return nil +} + +func (s *store) Set(key string, value interface{}) error { + s.mx.Lock() + defer s.mx.Unlock() + + doc := renderRequest(value) + _, _, err := s.client.Request("PUT", fmt.Sprintf("/%s/%s/%s", s.index, docType, url.QueryEscape(key)), "", nil, doc) + if err != nil { + return err + } + return nil +} + +func (s *store) Remove(key string) error { + s.mx.Lock() + defer s.mx.Unlock() + + _, _, err := s.client.Delete(s.index, docType, url.QueryEscape(key), nil) + if err != nil { + return err + } + return nil +} + +type entry struct { + value interface{} +} + +func (e entry) Decode(to interface{}) error { + return typeconv.Convert(to, e.value) +} + +type searchResult struct { + ID string `json:"_id"` + Source struct { + Value json.RawMessage `json:"v"` + } `json:"_source"` +} + +func (s *store) Each(fn func(string, backend.ValueDecoder) (bool, error)) error { + s.mx.Lock() + defer s.mx.Unlock() + + status, result, err := s.client.SearchURIWithBody(s.index, "", nil, map[string]any{ + "query": map[string]any{ + "match_all": map[string]any{}, + }, + "size": 1000, // TODO: we might have to do scroll if there are more than 1000 keys + }) + + if err != nil && status != http.StatusNotFound { + return err + } + + if result == nil || len(result.Hits.Hits) == 0 { + return nil + } + + for _, hit := range result.Hits.Hits { + var sres searchResult + err = json.Unmarshal(hit, &sres) + if err != nil { + return err + } + + var e entry + err = json.Unmarshal(sres.Source.Value, &e.value) + if err != nil { + return err + } + + key, err := url.QueryUnescape(sres.ID) + if err != nil { + return err + } + + cont, err := fn(key, e) + if !cont || err != nil { + return err + } + } + + return nil +} + +func (s *store) SetID(id string) { + s.mx.Lock() + defer s.mx.Unlock() + + if id == "" { + return + } + s.index = renderIndexName(id) +} +func renderIndexName(name string) string { + return "agentless-state-" + name +} + +func renderRequest(val interface{}) doc { + return doc{ + Value: val, + UpdatedAt: time.Now().UTC().Format("2006-01-02T15:04:05.000Z"), + } +} diff --git a/internal/pkg/otel/translate/otelconfig.go b/internal/pkg/otel/translate/otelconfig.go index 7c2ad035a35..f2ee1c9dbe8 100644 --- a/internal/pkg/otel/translate/otelconfig.go +++ b/internal/pkg/otel/translate/otelconfig.go @@ -43,6 +43,7 @@ const ( outputOtelOverrideFieldName = "otel" outputOtelOverrideExporterFieldName = "exporter" outputOtelOverrideExtensionsFieldName = "extensions" + elasticsearchStateStoreExtensionName = "elastic_storage" ) // BeatMonitoringConfigGetter is a function that returns the monitoring configuration for a beat receiver. @@ -347,6 +348,7 @@ func getReceiversConfigForComponent( receiverConfig[beatName] = map[string]any{ "inputs": inputs, } + receiverConfig["storage"] = "elastic_storage" case "metricbeat": receiverConfig[beatName] = map[string]any{ "modules": inputs, @@ -525,6 +527,10 @@ func unitToExporterConfig(unit component.Unit, outputName string, exporterType o "authenticator": extensionID.String(), } + // Add elasticsearch state store extension for agentless mode + // We paste the config as is, without any translation. + // The state store extension will pick up relevant settings from it and ignore the rest. + extensionCfg[elasticsearchStateStoreExtensionName] = unitConfigMap } return exporterConfig, queueSettings, extensionCfg, nil From 719ec22718d8eb8fb8aaca29ccc2c8d05b0e4a43 Mon Sep 17 00:00:00 2001 From: VihasMakwana <121151420+VihasMakwana@users.noreply.github.com> Date: Mon, 2 Mar 2026 19:36:18 +0530 Subject: [PATCH 02/10] config --- .../pkg/otel/extension/elasticstorage/config.go | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/internal/pkg/otel/extension/elasticstorage/config.go b/internal/pkg/otel/extension/elasticstorage/config.go index d5371aaae0b..07a33963a7f 100644 --- a/internal/pkg/otel/extension/elasticstorage/config.go +++ b/internal/pkg/otel/extension/elasticstorage/config.go @@ -9,22 +9,6 @@ import ( ) type Config struct { - // Hosts []string `mapstructure:"hosts"` - // Protocol string `mapstructure:"protocol"` - // Path string `mapstructure:"path"` - // Params map[string]string `mapstructure:"parameters"` - // Headers map[string]string `mapstructure:"headers"` - - // Kerberos *kerberos.Config `mapstructure:"kerberos"` - - // Username string `mapstructure:"username"` - // Password string `mapstructure:"password"` - // APIKey string `mapstructure:"api_key"` - - // CompressionLevel int `mapstructure:"compression_level"` - // EscapeHTML bool `mapstructure:"escape_html"` - - // Transport httpcommon.HTTPTransportSettings `mapstructure:",squash"` ElasticsearchConfig map[string]interface{} `mapstructure:",remain"` } From a0d5521a81ce29d18192afafe21ef3566d598d67 Mon Sep 17 00:00:00 2001 From: VihasMakwana <121151420+VihasMakwana@users.noreply.github.com> Date: Wed, 4 Mar 2026 15:52:15 +0530 Subject: [PATCH 03/10] delete extension from elastic-agent --- internal/edot/otelcol/components.go | 2 +- .../otel/extension/elasticstorage/config.go | 21 -- .../extension/elasticstorage/extension.go | 50 ----- .../otel/extension/elasticstorage/factory.go | 21 -- .../generated_component_test.go | 68 ------ .../elasticstorage/generated_package_test.go | 12 -- .../internal/metadata/generated_status.go | 16 -- .../extension/elasticstorage/metadata.yaml | 9 - .../otel/extension/elasticstorage/store.go | 199 ------------------ 9 files changed, 1 insertion(+), 397 deletions(-) delete mode 100644 internal/pkg/otel/extension/elasticstorage/config.go delete mode 100644 internal/pkg/otel/extension/elasticstorage/extension.go delete mode 100644 internal/pkg/otel/extension/elasticstorage/factory.go delete mode 100644 internal/pkg/otel/extension/elasticstorage/generated_component_test.go delete mode 100644 internal/pkg/otel/extension/elasticstorage/generated_package_test.go delete mode 100644 internal/pkg/otel/extension/elasticstorage/internal/metadata/generated_status.go delete mode 100644 internal/pkg/otel/extension/elasticstorage/metadata.yaml delete mode 100644 internal/pkg/otel/extension/elasticstorage/store.go diff --git a/internal/edot/otelcol/components.go b/internal/edot/otelcol/components.go index ba339c3e046..0e42f679742 100644 --- a/internal/edot/otelcol/components.go +++ b/internal/edot/otelcol/components.go @@ -93,8 +93,8 @@ import ( filestorage "github.com/open-telemetry/opentelemetry-collector-contrib/extension/storage/filestorage" "go.opentelemetry.io/collector/extension/memorylimiterextension" // for putting backpressure when approach a memory limit + elasticstorage "github.com/elastic/beats/v7/x-pack/otel/extension/elasticstorage" elasticdiagnostics "github.com/elastic/elastic-agent/internal/pkg/otel/extension/elasticdiagnostics" - elasticstorage "github.com/elastic/elastic-agent/internal/pkg/otel/extension/elasticstorage" "github.com/elastic/opentelemetry-collector-components/extension/apikeyauthextension" "github.com/elastic/opentelemetry-collector-components/extension/apmconfigextension" diff --git a/internal/pkg/otel/extension/elasticstorage/config.go b/internal/pkg/otel/extension/elasticstorage/config.go deleted file mode 100644 index 07a33963a7f..00000000000 --- a/internal/pkg/otel/extension/elasticstorage/config.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one -// or more contributor license agreements. Licensed under the Elastic License 2.0; -// you may not use this file except in compliance with the Elastic License 2.0. - -package elasticstorage - -import ( - "go.opentelemetry.io/collector/component" -) - -type Config struct { - ElasticsearchConfig map[string]interface{} `mapstructure:",remain"` -} - -func createDefaultConfig() component.Config { - return &Config{} -} - -func (c *Config) Validate() error { - return nil -} diff --git a/internal/pkg/otel/extension/elasticstorage/extension.go b/internal/pkg/otel/extension/elasticstorage/extension.go deleted file mode 100644 index 83e3a56f579..00000000000 --- a/internal/pkg/otel/extension/elasticstorage/extension.go +++ /dev/null @@ -1,50 +0,0 @@ -package elasticstorage - -import ( - "context" - - "github.com/elastic/beats/v7/libbeat/esleg/eslegclient" - "github.com/elastic/beats/v7/libbeat/statestore/backend" - cfg "github.com/elastic/elastic-agent-libs/config" - "github.com/elastic/elastic-agent-libs/logp" - "go.opentelemetry.io/collector/component" - "go.opentelemetry.io/collector/extension" - "go.uber.org/zap" - "go.uber.org/zap/zapcore" -) - -var _ extension.Extension = (*elasticStorage)(nil) -var _ backend.Registry = (*elasticStorage)(nil) - -type elasticStorage struct { - cfg *Config - logger *zap.Logger - client *eslegclient.Connection -} - -func (e *elasticStorage) Start(ctx context.Context, host component.Host) error { - c, err := cfg.NewConfigFrom(e.cfg.ElasticsearchConfig) - if err != nil { - return err - } - client, err := eslegclient.NewConnectedClient(ctx, c, "Filebeat", logp.NewLogger("", zap.WrapCore(func(zapcore.Core) zapcore.Core { - return e.logger.Core() - }))) - if err != nil { - return err - } - e.client = client - return nil -} - -func (e *elasticStorage) Shutdown(ctx context.Context) error { - return e.client.Close() -} - -func (e *elasticStorage) Access(name string) (backend.Store, error) { - return openStore(e.client, name) -} - -func (e *elasticStorage) Close() error { - return e.client.Close() -} diff --git a/internal/pkg/otel/extension/elasticstorage/factory.go b/internal/pkg/otel/extension/elasticstorage/factory.go deleted file mode 100644 index 4651dcb91d4..00000000000 --- a/internal/pkg/otel/extension/elasticstorage/factory.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one -// or more contributor license agreements. Licensed under the Elastic License 2.0; -// you may not use this file except in compliance with the Elastic License 2.0. - -package elasticstorage - -import ( - "context" - - "github.com/elastic/elastic-agent/internal/pkg/otel/extension/elasticstorage/internal/metadata" - "go.opentelemetry.io/collector/component" - "go.opentelemetry.io/collector/extension" -) - -func NewFactory() extension.Factory { - return extension.NewFactory(metadata.Type, createDefaultConfig, newExtension, component.StabilityLevelDevelopment) -} - -func newExtension(ctx context.Context, set extension.Settings, cfg component.Config) (extension.Extension, error) { - return &elasticStorage{cfg: cfg.(*Config), logger: set.Logger.Named("elasticstorage")}, nil -} diff --git a/internal/pkg/otel/extension/elasticstorage/generated_component_test.go b/internal/pkg/otel/extension/elasticstorage/generated_component_test.go deleted file mode 100644 index 1eced305c0e..00000000000 --- a/internal/pkg/otel/extension/elasticstorage/generated_component_test.go +++ /dev/null @@ -1,68 +0,0 @@ -// Code generated by mdatagen. DO NOT EDIT. - -package elasticstorage - -import ( - "context" - "testing" - - "github.com/stretchr/testify/require" - "go.opentelemetry.io/collector/component" - "go.opentelemetry.io/collector/component/componenttest" - "go.opentelemetry.io/collector/confmap/confmaptest" - "go.opentelemetry.io/collector/extension/extensiontest" -) - -var typ = component.MustNewType("elastic_storage") - -func TestComponentFactoryType(t *testing.T) { - require.Equal(t, typ, NewFactory().Type()) -} - -func TestComponentConfigStruct(t *testing.T) { - require.NoError(t, componenttest.CheckConfigStruct(NewFactory().CreateDefaultConfig())) -} - -func TestComponentLifecycle(t *testing.T) { - factory := NewFactory() - - cm, err := confmaptest.LoadConf("metadata.yaml") - require.NoError(t, err) - cfg := factory.CreateDefaultConfig() - sub, err := cm.Sub("tests::config") - require.NoError(t, err) - require.NoError(t, sub.Unmarshal(&cfg)) - t.Run("shutdown", func(t *testing.T) { - e, err := factory.Create(context.Background(), extensiontest.NewNopSettings(typ), cfg) - require.NoError(t, err) - err = e.Shutdown(context.Background()) - require.NoError(t, err) - }) - t.Run("lifecycle", func(t *testing.T) { - firstExt, err := factory.Create(context.Background(), extensiontest.NewNopSettings(typ), cfg) - require.NoError(t, err) - require.NoError(t, firstExt.Start(context.Background(), newMdatagenNopHost())) - require.NoError(t, firstExt.Shutdown(context.Background())) - - secondExt, err := factory.Create(context.Background(), extensiontest.NewNopSettings(typ), cfg) - require.NoError(t, err) - require.NoError(t, secondExt.Start(context.Background(), newMdatagenNopHost())) - require.NoError(t, secondExt.Shutdown(context.Background())) - }) -} - -var _ component.Host = (*mdatagenNopHost)(nil) - -type mdatagenNopHost struct{} - -func newMdatagenNopHost() component.Host { - return &mdatagenNopHost{} -} - -func (mnh *mdatagenNopHost) GetExtensions() map[component.ID]component.Component { - return nil -} - -func (mnh *mdatagenNopHost) GetFactory(_ component.Kind, _ component.Type) component.Factory { - return nil -} diff --git a/internal/pkg/otel/extension/elasticstorage/generated_package_test.go b/internal/pkg/otel/extension/elasticstorage/generated_package_test.go deleted file mode 100644 index 7afd311633d..00000000000 --- a/internal/pkg/otel/extension/elasticstorage/generated_package_test.go +++ /dev/null @@ -1,12 +0,0 @@ -// Code generated by mdatagen. DO NOT EDIT. - -package elasticstorage - -import ( - "go.uber.org/goleak" - "testing" -) - -func TestMain(m *testing.M) { - goleak.VerifyTestMain(m) -} diff --git a/internal/pkg/otel/extension/elasticstorage/internal/metadata/generated_status.go b/internal/pkg/otel/extension/elasticstorage/internal/metadata/generated_status.go deleted file mode 100644 index 14b559768ac..00000000000 --- a/internal/pkg/otel/extension/elasticstorage/internal/metadata/generated_status.go +++ /dev/null @@ -1,16 +0,0 @@ -// Code generated by mdatagen. DO NOT EDIT. - -package metadata - -import ( - "go.opentelemetry.io/collector/component" -) - -var ( - Type = component.MustNewType("elastic_storage") - ScopeName = "github.com/elastic/elastic-agent/internal/pkg/otel/extension/elasticstorage" -) - -const ( - ExtensionStability = component.StabilityLevelDevelopment -) diff --git a/internal/pkg/otel/extension/elasticstorage/metadata.yaml b/internal/pkg/otel/extension/elasticstorage/metadata.yaml deleted file mode 100644 index c7de9e5e312..00000000000 --- a/internal/pkg/otel/extension/elasticstorage/metadata.yaml +++ /dev/null @@ -1,9 +0,0 @@ -type: elastic_storage -github_project: elastic/elastic-agent - -status: - class: extension - stability: - development: [extension] - codeowners: - active: [VihasMakwana] diff --git a/internal/pkg/otel/extension/elasticstorage/store.go b/internal/pkg/otel/extension/elasticstorage/store.go deleted file mode 100644 index 9e69ff82158..00000000000 --- a/internal/pkg/otel/extension/elasticstorage/store.go +++ /dev/null @@ -1,199 +0,0 @@ -package elasticstorage - -import ( - "encoding/json" - "errors" - "fmt" - "net/http" - "net/url" - "sync" - "time" - - "github.com/elastic/beats/v7/libbeat/esleg/eslegclient" - "github.com/elastic/beats/v7/libbeat/statestore/backend" - "github.com/elastic/elastic-agent-libs/transform/typeconv" -) - -type store struct { - client *eslegclient.Connection - index string - mx sync.Mutex -} - -type queryResult struct { - Found bool `json:"found"` - Source struct { - Value json.RawMessage `json:"v"` - } `json:"_source"` -} - -type doc struct { - Value any `struct:"v"` - UpdatedAt any `struct:"updated_at"` -} - -var ErrKeyUnknown = errors.New("key unknown") - -const docType = "_doc" - -var _ backend.Store = (*store)(nil) - -func openStore(client *eslegclient.Connection, name string) (*store, error) { - return &store{ - client: client, - index: renderIndexName(name), - }, nil -} - -func (s *store) Close() error { - return nil -} - -func (s *store) Has(key string) (bool, error) { - s.mx.Lock() - defer s.mx.Unlock() - - var v interface{} - err := s.get(key, v) - if err != nil { - if errors.Is(err, ErrKeyUnknown) { - return false, nil - } - return false, err - } - return true, nil -} - -func (s *store) Get(key string, to interface{}) error { - s.mx.Lock() - defer s.mx.Unlock() - - return s.get(key, to) -} - -func (s *store) get(key string, to interface{}) error { - status, data, err := s.client.Request("GET", fmt.Sprintf("/%s/%s/%s", s.index, docType, url.QueryEscape(key)), "", nil, nil) - - if err != nil { - if status == http.StatusNotFound { - return ErrKeyUnknown - } - return err - } - - var qr queryResult - err = json.Unmarshal(data, &qr) - if err != nil { - return err - } - - err = json.Unmarshal(qr.Source.Value, to) - if err != nil { - return err - } - return nil -} - -func (s *store) Set(key string, value interface{}) error { - s.mx.Lock() - defer s.mx.Unlock() - - doc := renderRequest(value) - _, _, err := s.client.Request("PUT", fmt.Sprintf("/%s/%s/%s", s.index, docType, url.QueryEscape(key)), "", nil, doc) - if err != nil { - return err - } - return nil -} - -func (s *store) Remove(key string) error { - s.mx.Lock() - defer s.mx.Unlock() - - _, _, err := s.client.Delete(s.index, docType, url.QueryEscape(key), nil) - if err != nil { - return err - } - return nil -} - -type entry struct { - value interface{} -} - -func (e entry) Decode(to interface{}) error { - return typeconv.Convert(to, e.value) -} - -type searchResult struct { - ID string `json:"_id"` - Source struct { - Value json.RawMessage `json:"v"` - } `json:"_source"` -} - -func (s *store) Each(fn func(string, backend.ValueDecoder) (bool, error)) error { - s.mx.Lock() - defer s.mx.Unlock() - - status, result, err := s.client.SearchURIWithBody(s.index, "", nil, map[string]any{ - "query": map[string]any{ - "match_all": map[string]any{}, - }, - "size": 1000, // TODO: we might have to do scroll if there are more than 1000 keys - }) - - if err != nil && status != http.StatusNotFound { - return err - } - - if result == nil || len(result.Hits.Hits) == 0 { - return nil - } - - for _, hit := range result.Hits.Hits { - var sres searchResult - err = json.Unmarshal(hit, &sres) - if err != nil { - return err - } - - var e entry - err = json.Unmarshal(sres.Source.Value, &e.value) - if err != nil { - return err - } - - key, err := url.QueryUnescape(sres.ID) - if err != nil { - return err - } - - cont, err := fn(key, e) - if !cont || err != nil { - return err - } - } - - return nil -} - -func (s *store) SetID(id string) { - s.mx.Lock() - defer s.mx.Unlock() - - if id == "" { - return - } - s.index = renderIndexName(id) -} -func renderIndexName(name string) string { - return "agentless-state-" + name -} - -func renderRequest(val interface{}) doc { - return doc{ - Value: val, - UpdatedAt: time.Now().UTC().Format("2006-01-02T15:04:05.000Z"), - } -} From 458e2d49b51129bcbdb1b03aad1d882621938019 Mon Sep 17 00:00:00 2001 From: VihasMakwana <121151420+VihasMakwana@users.noreply.github.com> Date: Wed, 4 Mar 2026 16:01:12 +0530 Subject: [PATCH 04/10] use env variable --- internal/pkg/otel/translate/otelconfig.go | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/internal/pkg/otel/translate/otelconfig.go b/internal/pkg/otel/translate/otelconfig.go index f2ee1c9dbe8..d8c858d3db4 100644 --- a/internal/pkg/otel/translate/otelconfig.go +++ b/internal/pkg/otel/translate/otelconfig.go @@ -24,6 +24,7 @@ import ( "go.opentelemetry.io/collector/pipeline" "golang.org/x/exp/maps" + fbfeatures "github.com/elastic/beats/v7/filebeat/features" "github.com/elastic/beats/v7/libbeat/outputs/elasticsearch" "github.com/elastic/beats/v7/x-pack/libbeat/management" "github.com/elastic/beats/v7/x-pack/otel/extension/beatsauthextension" @@ -348,7 +349,9 @@ func getReceiversConfigForComponent( receiverConfig[beatName] = map[string]any{ "inputs": inputs, } - receiverConfig["storage"] = "elastic_storage" + if fbfeatures.IsElasticsearchStateStoreEnabled() { + receiverConfig["storage"] = "elastic_storage" + } case "metricbeat": receiverConfig[beatName] = map[string]any{ "modules": inputs, @@ -526,11 +529,12 @@ func unitToExporterConfig(unit component.Unit, outputName string, exporterType o exporterConfig["auth"] = map[string]any{ "authenticator": extensionID.String(), } - - // Add elasticsearch state store extension for agentless mode - // We paste the config as is, without any translation. - // The state store extension will pick up relevant settings from it and ignore the rest. - extensionCfg[elasticsearchStateStoreExtensionName] = unitConfigMap + if fbfeatures.IsElasticsearchStateStoreEnabled() { + // Add elasticsearch state store extension for agentless mode + // We paste the config as is, without any translation. + // The state store extension will pick up relevant settings from it and ignore the rest. + extensionCfg[elasticsearchStateStoreExtensionName] = unitConfigMap + } } return exporterConfig, queueSettings, extensionCfg, nil From 2b94429652d5b2d253a468d8b33eee753446dddb Mon Sep 17 00:00:00 2001 From: VihasMakwana <121151420+VihasMakwana@users.noreply.github.com> Date: Fri, 6 Mar 2026 16:28:40 +0530 Subject: [PATCH 05/10] point to personal fork --- go.mod | 14 +++++++------- go.sum | 29 ++++++++++++++++------------- internal/edot/go.mod | 20 ++++++++++---------- internal/edot/go.sum | 38 ++++++++++++++++++++------------------ 4 files changed, 53 insertions(+), 48 deletions(-) diff --git a/go.mod b/go.mod index fbcceadec99..34fb835a43a 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,7 @@ module github.com/elastic/elastic-agent go 1.24.13 -replace github.com/elastic/beats/v7 => ./beats +replace github.com/elastic/beats/v7 => github.com/VihasMakwana/beats/v7 v7.0.0-20260306060228-d1a0f47dcbbc require ( github.com/Jeffail/gabs/v2 v2.6.0 @@ -20,7 +20,7 @@ require ( github.com/elastic/cloud-on-k8s/v2 v2.0.0-20250327073047-b624240832ae github.com/elastic/elastic-agent-autodiscover v0.10.2 github.com/elastic/elastic-agent-client/v7 v7.18.0 - github.com/elastic/elastic-agent-libs v0.32.2 + github.com/elastic/elastic-agent-libs v0.33.3 github.com/elastic/elastic-agent-system-metrics v0.14.1 github.com/elastic/elastic-transport-go/v8 v8.9.0 github.com/elastic/go-elasticsearch/v8 v8.19.3 @@ -71,10 +71,10 @@ require ( go.opentelemetry.io/collector/pipeline v1.51.0 go.opentelemetry.io/collector/service v0.145.0 go.opentelemetry.io/contrib/otelconf v0.18.0 - go.opentelemetry.io/otel v1.39.0 - go.opentelemetry.io/otel/metric v1.39.0 - go.opentelemetry.io/otel/sdk v1.39.0 - go.opentelemetry.io/otel/sdk/metric v1.39.0 + go.opentelemetry.io/otel v1.40.0 + go.opentelemetry.io/otel/metric v1.40.0 + go.opentelemetry.io/otel/sdk v1.40.0 + go.opentelemetry.io/otel/sdk/metric v1.40.0 go.uber.org/zap v1.27.1 go.yaml.in/yaml/v3 v3.0.4 golang.org/x/crypto v0.47.0 @@ -337,7 +337,7 @@ require ( go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 // indirect go.opentelemetry.io/otel/log v0.15.0 // indirect go.opentelemetry.io/otel/sdk/log v0.14.0 // indirect - go.opentelemetry.io/otel/trace v1.39.0 // indirect + go.opentelemetry.io/otel/trace v1.40.0 // indirect go.opentelemetry.io/proto/otlp v1.9.0 // indirect go.uber.org/goleak v1.3.0 // indirect go.uber.org/multierr v1.11.0 // indirect diff --git a/go.sum b/go.sum index 577ddd37fff..442cb48b1df 100644 --- a/go.sum +++ b/go.sum @@ -6,8 +6,9 @@ cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdB cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10= dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= -filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +filippo.io/edwards25519 v1.1.1 h1:YpjwWWlNmGIDyXOn8zLzqiD+9TyIlPhGFG96P39uBpw= +filippo.io/edwards25519 v1.1.1/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk= github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU= @@ -43,6 +44,8 @@ github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERo github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA= github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= +github.com/VihasMakwana/beats/v7 v7.0.0-20260306060228-d1a0f47dcbbc h1:EAusMNRqnzo9Bts7CCZHni0vECjKgQjoGu6n5FWkU7U= +github.com/VihasMakwana/beats/v7 v7.0.0-20260306060228-d1a0f47dcbbc/go.mod h1:PGY8/w5QSponBhQ5MEZCRRlpTKH5ARSNpGVyfkVXfhs= github.com/akavel/rsrc v0.10.2 h1:Zxm8V5eI1hW4gGaYsJQUhxpjkENuG91ki8B4zCrvEsw= github.com/akavel/rsrc v0.10.2/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ= @@ -171,8 +174,8 @@ github.com/elastic/elastic-agent-autodiscover v0.10.2 h1:fzi+CIcK7FKUQlQHfKP+3Ix github.com/elastic/elastic-agent-autodiscover v0.10.2/go.mod h1:qBoYxp3lX3qFRYjEgsOaROC+xL4ItG63GSvOg1SjjsQ= github.com/elastic/elastic-agent-client/v7 v7.18.0 h1:zXdoErqECfvRjj1c+1Ko4VGuUnFtJfTiC9JJz4aQCHc= github.com/elastic/elastic-agent-client/v7 v7.18.0/go.mod h1:ChFjpIfSsQOnhWT3se5Euw/o8P4Vf77FxeObE/vUfSc= -github.com/elastic/elastic-agent-libs v0.32.2 h1:2CaO4TAMcZDy0qNxh48Ui1oMc+xExKL+JkpcyOxF7XA= -github.com/elastic/elastic-agent-libs v0.32.2/go.mod h1:0xUg7alsNE/WhY9DZRIdTYW75nqSHC1octIAg//j/PQ= +github.com/elastic/elastic-agent-libs v0.33.3 h1:Gsq5FA29sUbbZVJbeLCKPyRkAxCrOhv3VtXvuG9Uu6k= +github.com/elastic/elastic-agent-libs v0.33.3/go.mod h1:0xUg7alsNE/WhY9DZRIdTYW75nqSHC1octIAg//j/PQ= github.com/elastic/elastic-agent-system-metrics v0.14.1 h1:XdV3KWbug/M1dkn8h9Yth9pfdyeFR2Z1iqaypX+ohBg= github.com/elastic/elastic-agent-system-metrics v0.14.1/go.mod h1:JNfnZrC0viAjlJRUzQKKuMpDlXgjXBn4WdWEXQF7jcA= github.com/elastic/elastic-transport-go/v8 v8.9.0 h1:KeT/2P54F0xS0S8Y3Pf+tFDg4HmBgReQMB+BMz8dDAs= @@ -786,8 +789,8 @@ go.opentelemetry.io/contrib/zpages v0.63.0 h1:TppOKuZGbqXMgsfjqq3i09N5Vbo1JLtLIm go.opentelemetry.io/contrib/zpages v0.63.0/go.mod h1:5F8uugz75ay/MMhRRhxAXY33FuaI8dl7jTxefrIy5qk= go.opentelemetry.io/ebpf-profiler v0.0.202601 h1:6GxLX+2LD2GhrbbiKjR55JSqr+3Z7thmFUi68TtnwAg= go.opentelemetry.io/ebpf-profiler v0.0.202601/go.mod h1:83Zc+bFPt47coVV9v2zyZoiCvk0ZoHkbN5H/cAbtCN8= -go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= -go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= +go.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms= +go.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 h1:OMqPldHt79PqWKOMYIAQs3CxAi7RLgPxwfFSwr4ZxtM= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0/go.mod h1:1biG4qiqTxKiUCtoWDPpL3fB3KxVwCiGw81j3nKMuHE= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 h1:QQqYw3lkrzwVsoEX0w//EhH/TCnpRdEenKBOOEIMjWc= @@ -814,18 +817,18 @@ go.opentelemetry.io/otel/log v0.15.0 h1:0VqVnc3MgyYd7QqNVIldC3dsLFKgazR6P3P3+ypk go.opentelemetry.io/otel/log v0.15.0/go.mod h1:9c/G1zbyZfgu1HmQD7Qj84QMmwTp2QCQsZH1aeoWDE4= go.opentelemetry.io/otel/log/logtest v0.14.0 h1:BGTqNeluJDK2uIHAY8lRqxjVAYfqgcaTbVk1n3MWe5A= go.opentelemetry.io/otel/log/logtest v0.14.0/go.mod h1:IuguGt8XVP4XA4d2oEEDMVDBBCesMg8/tSGWDjuKfoA= -go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= -go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= -go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= -go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= +go.opentelemetry.io/otel/metric v1.40.0 h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g= +go.opentelemetry.io/otel/metric v1.40.0/go.mod h1:ib/crwQH7N3r5kfiBZQbwrTge743UDc7DTFVZrrXnqc= +go.opentelemetry.io/otel/sdk v1.40.0 h1:KHW/jUzgo6wsPh9At46+h4upjtccTmuZCFAc9OJ71f8= +go.opentelemetry.io/otel/sdk v1.40.0/go.mod h1:Ph7EFdYvxq72Y8Li9q8KebuYUr2KoeyHx0DRMKrYBUE= go.opentelemetry.io/otel/sdk/log v0.14.0 h1:JU/U3O7N6fsAXj0+CXz21Czg532dW2V4gG1HE/e8Zrg= go.opentelemetry.io/otel/sdk/log v0.14.0/go.mod h1:imQvII+0ZylXfKU7/wtOND8Hn4OpT3YUoIgqJVksUkM= go.opentelemetry.io/otel/sdk/log/logtest v0.14.0 h1:Ijbtz+JKXl8T2MngiwqBlPaHqc4YCaP/i13Qrow6gAM= go.opentelemetry.io/otel/sdk/log/logtest v0.14.0/go.mod h1:dCU8aEL6q+L9cYTqcVOk8rM9Tp8WdnHOPLiBgp0SGOA= -go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= -go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= -go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= -go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= +go.opentelemetry.io/otel/sdk/metric v1.40.0 h1:mtmdVqgQkeRxHgRv4qhyJduP3fYJRMX4AtAlbuWdCYw= +go.opentelemetry.io/otel/sdk/metric v1.40.0/go.mod h1:4Z2bGMf0KSK3uRjlczMOeMhKU2rhUqdWNoKcYrtcBPg= +go.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw= +go.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA= go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= go.opentelemetry.io/proto/slim/otlp v1.9.0 h1:fPVMv8tP3TrsqlkH1HWYUpbCY9cAIemx184VGkS6vlE= diff --git a/internal/edot/go.mod b/internal/edot/go.mod index bb6f10e1d43..f9b31bc995a 100644 --- a/internal/edot/go.mod +++ b/internal/edot/go.mod @@ -5,12 +5,12 @@ go 1.24.13 // use in-repo directory replace github.com/elastic/elastic-agent => ../../ -replace github.com/elastic/beats/v7 => ../../beats +replace github.com/elastic/beats/v7 => github.com/VihasMakwana/beats/v7 v7.0.0-20260306060228-d1a0f47dcbbc require ( github.com/elastic/beats/v7 v7.0.0-alpha2.0.20260226174817-c6f22b080eb8 github.com/elastic/elastic-agent v0.0.0-00010101000000-000000000000 - github.com/elastic/elastic-agent-libs v0.32.2 + github.com/elastic/elastic-agent-libs v0.33.3 github.com/elastic/mock-es v0.0.0-20250530054253-8c3b6053f9b6 github.com/elastic/opentelemetry-collector-components/connector/elasticapmconnector v0.29.0 github.com/elastic/opentelemetry-collector-components/connector/profilingmetricsconnector v0.29.0 @@ -116,7 +116,7 @@ require ( github.com/open-telemetry/opentelemetry-collector-contrib/pkg/sampling v0.145.0 // indirect github.com/oschwald/geoip2-golang/v2 v2.1.0 // indirect github.com/oschwald/maxminddb-golang/v2 v2.1.1 // indirect - github.com/osquery/osquery-go v0.0.0-20231108163517-e3cde127e724 // indirect + github.com/osquery/osquery-go v0.0.0-20260226222546-0cc22f415e57 // indirect github.com/otiai10/copy v1.14.0 // indirect github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect github.com/pkg/xattr v0.4.9 // indirect @@ -205,7 +205,7 @@ require ( code.cloudfoundry.org/go-loggregator v7.4.0+incompatible // indirect code.cloudfoundry.org/gofileutils v0.0.0-20170111115228-4d0c80011a0f // indirect code.cloudfoundry.org/rfc5424 v0.0.0-20180905210152-236a6d29298a // indirect - filippo.io/edwards25519 v1.1.0 // indirect + filippo.io/edwards25519 v1.1.1 // indirect github.com/Azure/azure-amqp-common-go/v4 v4.2.0 // indirect github.com/Azure/azure-event-hubs-go/v3 v3.6.1 // indirect github.com/Azure/azure-pipeline-go v0.2.3 // indirect @@ -413,7 +413,7 @@ require ( github.com/goccy/go-json v0.10.5 // indirect github.com/goccy/go-yaml v1.19.2 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect - github.com/godror/godror v0.49.3 // indirect + github.com/godror/godror v0.49.4 // indirect github.com/godror/knownpb v0.3.0 // indirect github.com/gofrs/flock v0.13.0 // indirect github.com/gogo/googleapis v1.4.1 // indirect @@ -694,7 +694,7 @@ require ( go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0 // indirect go.opentelemetry.io/contrib/otelconf v0.18.0 // indirect go.opentelemetry.io/contrib/propagators/b3 v1.39.0 // indirect - go.opentelemetry.io/otel v1.39.1-0.20260115134311-f809f7d71e2d // indirect + go.opentelemetry.io/otel v1.40.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.39.0 // indirect @@ -707,11 +707,11 @@ require ( go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.39.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.39.0 // indirect go.opentelemetry.io/otel/log v0.15.0 // indirect - go.opentelemetry.io/otel/metric v1.39.1-0.20260115134311-f809f7d71e2d // indirect - go.opentelemetry.io/otel/sdk v1.39.0 // indirect + go.opentelemetry.io/otel/metric v1.40.0 // indirect + go.opentelemetry.io/otel/sdk v1.40.0 // indirect go.opentelemetry.io/otel/sdk/log v0.14.0 // indirect - go.opentelemetry.io/otel/sdk/metric v1.39.1-0.20260115134311-f809f7d71e2d // indirect - go.opentelemetry.io/otel/trace v1.39.1-0.20260115134311-f809f7d71e2d // indirect + go.opentelemetry.io/otel/sdk/metric v1.40.0 // indirect + go.opentelemetry.io/otel/trace v1.40.0 // indirect go.opentelemetry.io/proto/otlp v1.9.0 // indirect go.uber.org/atomic v1.11.0 // indirect go.uber.org/goleak v1.3.0 // indirect diff --git a/internal/edot/go.sum b/internal/edot/go.sum index d0272faa9b4..a08f435be91 100644 --- a/internal/edot/go.sum +++ b/internal/edot/go.sum @@ -46,8 +46,8 @@ code.cloudfoundry.org/rfc5424 v0.0.0-20180905210152-236a6d29298a h1:8rqv2w8xEceN code.cloudfoundry.org/rfc5424 v0.0.0-20180905210152-236a6d29298a/go.mod h1:tkZo8GtzBjySJ7USvxm4E36lNQw1D3xM6oKHGqdaAJ4= dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= -filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= -filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +filippo.io/edwards25519 v1.1.1 h1:YpjwWWlNmGIDyXOn8zLzqiD+9TyIlPhGFG96P39uBpw= +filippo.io/edwards25519 v1.1.1/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/Azure/azure-amqp-common-go/v4 v4.2.0 h1:q/jLx1KJ8xeI8XGfkOWMN9XrXzAfVTkyvCxPvHCjd2I= github.com/Azure/azure-amqp-common-go/v4 v4.2.0/go.mod h1:GD3m/WPPma+621UaU6KNjKEo5Hl09z86viKwQjTpV0Q= github.com/Azure/azure-event-hubs-go/v3 v3.6.1 h1:vSiMmn3tOwgiLyfnmhT5K6Of/3QWRLaaNZPI0hFvZyU= @@ -184,6 +184,8 @@ github.com/UNO-SOFT/zlog v0.8.1 h1:TEFkGJHtUfTRgMkLZiAjLSHALjwSBdw6/zByMC5GJt4= github.com/UNO-SOFT/zlog v0.8.1/go.mod h1:yqFOjn3OhvJ4j7ArJqQNA+9V+u6t9zSAyIZdWdMweWc= github.com/VictoriaMetrics/easyproto v0.1.4 h1:r8cNvo8o6sR4QShBXQd1bKw/VVLSQma/V2KhTBPf+Sc= github.com/VictoriaMetrics/easyproto v0.1.4/go.mod h1:QlGlzaJnDfFd8Lk6Ci/fuLxfTo3/GThPs2KH23mv710= +github.com/VihasMakwana/beats/v7 v7.0.0-20260306060228-d1a0f47dcbbc h1:EAusMNRqnzo9Bts7CCZHni0vECjKgQjoGu6n5FWkU7U= +github.com/VihasMakwana/beats/v7 v7.0.0-20260306060228-d1a0f47dcbbc/go.mod h1:PGY8/w5QSponBhQ5MEZCRRlpTKH5ARSNpGVyfkVXfhs= github.com/aerospike/aerospike-client-go/v7 v7.7.1 h1:lcskBtPZYe6ESObhIEQEp4XO1axYZpaFD3ie4iwr6tg= github.com/aerospike/aerospike-client-go/v7 v7.7.1/go.mod h1:STlBtOkKT8nmp7iD+sEkr/JGEOu+4e2jGlNN0Jiu2a4= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= @@ -452,8 +454,8 @@ github.com/elastic/elastic-agent-autodiscover v0.10.2 h1:fzi+CIcK7FKUQlQHfKP+3Ix github.com/elastic/elastic-agent-autodiscover v0.10.2/go.mod h1:qBoYxp3lX3qFRYjEgsOaROC+xL4ItG63GSvOg1SjjsQ= github.com/elastic/elastic-agent-client/v7 v7.18.0 h1:zXdoErqECfvRjj1c+1Ko4VGuUnFtJfTiC9JJz4aQCHc= github.com/elastic/elastic-agent-client/v7 v7.18.0/go.mod h1:ChFjpIfSsQOnhWT3se5Euw/o8P4Vf77FxeObE/vUfSc= -github.com/elastic/elastic-agent-libs v0.32.2 h1:2CaO4TAMcZDy0qNxh48Ui1oMc+xExKL+JkpcyOxF7XA= -github.com/elastic/elastic-agent-libs v0.32.2/go.mod h1:0xUg7alsNE/WhY9DZRIdTYW75nqSHC1octIAg//j/PQ= +github.com/elastic/elastic-agent-libs v0.33.3 h1:Gsq5FA29sUbbZVJbeLCKPyRkAxCrOhv3VtXvuG9Uu6k= +github.com/elastic/elastic-agent-libs v0.33.3/go.mod h1:0xUg7alsNE/WhY9DZRIdTYW75nqSHC1octIAg//j/PQ= github.com/elastic/elastic-agent-system-metrics v0.14.1 h1:XdV3KWbug/M1dkn8h9Yth9pfdyeFR2Z1iqaypX+ohBg= github.com/elastic/elastic-agent-system-metrics v0.14.1/go.mod h1:JNfnZrC0viAjlJRUzQKKuMpDlXgjXBn4WdWEXQF7jcA= github.com/elastic/elastic-transport-go/v8 v8.9.0 h1:KeT/2P54F0xS0S8Y3Pf+tFDg4HmBgReQMB+BMz8dDAs= @@ -695,8 +697,8 @@ github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM= github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/godror/godror v0.49.3 h1:84CPEu1p3qPvpN7PTHv8NDept+t+d+AoO/7WjYVsFNc= -github.com/godror/godror v0.49.3/go.mod h1:kTMcxZzRw73RT5kn9v3JkBK4kHI6dqowHotqV72ebU8= +github.com/godror/godror v0.49.4 h1:8kKWKoR17nPX7u10hr4GwD4u10hzTZED9ihdkuzRrKI= +github.com/godror/godror v0.49.4/go.mod h1:kTMcxZzRw73RT5kn9v3JkBK4kHI6dqowHotqV72ebU8= github.com/godror/knownpb v0.3.0 h1:+caUdy8hTtl7X05aPl3tdL540TvCcaQA6woZQroLZMw= github.com/godror/knownpb v0.3.0/go.mod h1:PpTyfJwiOEAzQl7NtVCM8kdPCnp3uhxsZYIzZ5PV4zU= github.com/gofrs/flock v0.13.0 h1:95JolYOvGMqeH31+FC7D2+uULf6mG61mEZ/A8dRYMzw= @@ -1342,8 +1344,8 @@ github.com/oschwald/maxminddb-golang v1.13.0 h1:R8xBorY71s84yO06NgTmQvqvTvlS/bnY github.com/oschwald/maxminddb-golang v1.13.0/go.mod h1:BU0z8BfFVhi1LQaonTwwGQlsHUEu9pWNdMfmq4ztm0o= github.com/oschwald/maxminddb-golang/v2 v2.1.1 h1:lA8FH0oOrM4u7mLvowq8IT6a3Q/qEnqRzLQn9eH5ojc= github.com/oschwald/maxminddb-golang/v2 v2.1.1/go.mod h1:PLdx6PR+siSIoXqqy7C7r3SB3KZnhxWr1Dp6g0Hacl8= -github.com/osquery/osquery-go v0.0.0-20231108163517-e3cde127e724 h1:z8XmnNQeCDZB3BwVoRxcqwo7MlDdsB6AJxqTap72S7w= -github.com/osquery/osquery-go v0.0.0-20231108163517-e3cde127e724/go.mod h1:mLJRc1Go8uP32LRALGvWj2lVJ+hDYyIfxDzVa+C5Yo8= +github.com/osquery/osquery-go v0.0.0-20260226222546-0cc22f415e57 h1:t6YJWPvNurotG1WBdjycKpVFdHsvL7QqWslqfimhBWA= +github.com/osquery/osquery-go v0.0.0-20260226222546-0cc22f415e57/go.mod h1:4cBOmXSmmDULG4bTOq0EFvIy5NUMNJMKbLDBMg6lhJE= github.com/otiai10/copy v1.14.0 h1:dCI/t1iTdYGtkvCuBG2BgR6KZa83PTclw4U5n2wAllU= github.com/otiai10/copy v1.14.0/go.mod h1:ECfuL02W+/FkTWZWgQqXPWZgW9oeKCSQ5qVfSc4qc4w= github.com/otiai10/mint v1.5.1 h1:XaPLeE+9vGbuyEHem1JNk3bYc7KKqyI/na0/mLd/Kks= @@ -1824,8 +1826,8 @@ go.opentelemetry.io/contrib/zpages v0.63.0 h1:TppOKuZGbqXMgsfjqq3i09N5Vbo1JLtLIm go.opentelemetry.io/contrib/zpages v0.63.0/go.mod h1:5F8uugz75ay/MMhRRhxAXY33FuaI8dl7jTxefrIy5qk= go.opentelemetry.io/ebpf-profiler v0.0.202601 h1:6GxLX+2LD2GhrbbiKjR55JSqr+3Z7thmFUi68TtnwAg= go.opentelemetry.io/ebpf-profiler v0.0.202601/go.mod h1:83Zc+bFPt47coVV9v2zyZoiCvk0ZoHkbN5H/cAbtCN8= -go.opentelemetry.io/otel v1.39.1-0.20260115134311-f809f7d71e2d h1:d8jN5C+mHlN5HebF5NXapM8PW5Tq8LoBMUO/d7aqm4Y= -go.opentelemetry.io/otel v1.39.1-0.20260115134311-f809f7d71e2d/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= +go.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms= +go.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 h1:OMqPldHt79PqWKOMYIAQs3CxAi7RLgPxwfFSwr4ZxtM= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0/go.mod h1:1biG4qiqTxKiUCtoWDPpL3fB3KxVwCiGw81j3nKMuHE= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 h1:QQqYw3lkrzwVsoEX0w//EhH/TCnpRdEenKBOOEIMjWc= @@ -1852,18 +1854,18 @@ go.opentelemetry.io/otel/log v0.15.0 h1:0VqVnc3MgyYd7QqNVIldC3dsLFKgazR6P3P3+ypk go.opentelemetry.io/otel/log v0.15.0/go.mod h1:9c/G1zbyZfgu1HmQD7Qj84QMmwTp2QCQsZH1aeoWDE4= go.opentelemetry.io/otel/log/logtest v0.14.0 h1:BGTqNeluJDK2uIHAY8lRqxjVAYfqgcaTbVk1n3MWe5A= go.opentelemetry.io/otel/log/logtest v0.14.0/go.mod h1:IuguGt8XVP4XA4d2oEEDMVDBBCesMg8/tSGWDjuKfoA= -go.opentelemetry.io/otel/metric v1.39.1-0.20260115134311-f809f7d71e2d h1:Mv7jOS/papmlU4jeUx/ScvxT+UghI4YxgRG2ODBxqBA= -go.opentelemetry.io/otel/metric v1.39.1-0.20260115134311-f809f7d71e2d/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= -go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= -go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= +go.opentelemetry.io/otel/metric v1.40.0 h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g= +go.opentelemetry.io/otel/metric v1.40.0/go.mod h1:ib/crwQH7N3r5kfiBZQbwrTge743UDc7DTFVZrrXnqc= +go.opentelemetry.io/otel/sdk v1.40.0 h1:KHW/jUzgo6wsPh9At46+h4upjtccTmuZCFAc9OJ71f8= +go.opentelemetry.io/otel/sdk v1.40.0/go.mod h1:Ph7EFdYvxq72Y8Li9q8KebuYUr2KoeyHx0DRMKrYBUE= go.opentelemetry.io/otel/sdk/log v0.14.0 h1:JU/U3O7N6fsAXj0+CXz21Czg532dW2V4gG1HE/e8Zrg= go.opentelemetry.io/otel/sdk/log v0.14.0/go.mod h1:imQvII+0ZylXfKU7/wtOND8Hn4OpT3YUoIgqJVksUkM= go.opentelemetry.io/otel/sdk/log/logtest v0.14.0 h1:Ijbtz+JKXl8T2MngiwqBlPaHqc4YCaP/i13Qrow6gAM= go.opentelemetry.io/otel/sdk/log/logtest v0.14.0/go.mod h1:dCU8aEL6q+L9cYTqcVOk8rM9Tp8WdnHOPLiBgp0SGOA= -go.opentelemetry.io/otel/sdk/metric v1.39.1-0.20260115134311-f809f7d71e2d h1:Xc+v+yOWogGc1bTp6ISSnWEgHjaerCiU1VWBZQ40ewo= -go.opentelemetry.io/otel/sdk/metric v1.39.1-0.20260115134311-f809f7d71e2d/go.mod h1:UVPnzxO3YDVhII6+YVBzgScV6MYwDUlW2G9lVMvFS7c= -go.opentelemetry.io/otel/trace v1.39.1-0.20260115134311-f809f7d71e2d h1:BbdGrkH9cVsrnmD3egDymUWUjG5tGK6oaobhpHmDrK8= -go.opentelemetry.io/otel/trace v1.39.1-0.20260115134311-f809f7d71e2d/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= +go.opentelemetry.io/otel/sdk/metric v1.40.0 h1:mtmdVqgQkeRxHgRv4qhyJduP3fYJRMX4AtAlbuWdCYw= +go.opentelemetry.io/otel/sdk/metric v1.40.0/go.mod h1:4Z2bGMf0KSK3uRjlczMOeMhKU2rhUqdWNoKcYrtcBPg= +go.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw= +go.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA= go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= go.opentelemetry.io/proto/slim/otlp v1.9.0 h1:fPVMv8tP3TrsqlkH1HWYUpbCY9cAIemx184VGkS6vlE= From 018e5397e3c4997ecba5e6c90bd3b14addc62602 Mon Sep 17 00:00:00 2001 From: VihasMakwana <121151420+VihasMakwana@users.noreply.github.com> Date: Wed, 11 Mar 2026 19:35:06 +0530 Subject: [PATCH 06/10] update git submodule --- beats | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/beats b/beats index 8ed67e48c41..d634b972a87 160000 --- a/beats +++ b/beats @@ -1 +1 @@ -Subproject commit 8ed67e48c418cfa2704e6c071091db7ae39eceff +Subproject commit d634b972a87241bf37b956d774490a3a118cc0e6 From e42362bf8859353e353dc3b4daf9ae42b2a0485f Mon Sep 17 00:00:00 2001 From: VihasMakwana <121151420+VihasMakwana@users.noreply.github.com> Date: Wed, 11 Mar 2026 19:39:31 +0530 Subject: [PATCH 07/10] go.mod --- NOTICE-fips.txt | 4 ++-- NOTICE.txt | 4 ++-- go.mod | 4 ++-- go.sum | 2 -- internal/edot/go.mod | 6 +++--- internal/edot/go.sum | 6 ++---- internal/edot/otelcol/components.go | 4 ++-- wrapper/windows/archive-proxy/go.mod | 2 +- 8 files changed, 14 insertions(+), 18 deletions(-) diff --git a/NOTICE-fips.txt b/NOTICE-fips.txt index 6e5b2dbf0f4..00201f20e40 100644 --- a/NOTICE-fips.txt +++ b/NOTICE-fips.txt @@ -78245,11 +78245,11 @@ Contents of probable licence file $GOMODCACHE/github.com/gomodule/redigo@v1.9.3/ -------------------------------------------------------------------------------- Dependency : github.com/google/cel-go -Version: v0.26.0 +Version: v0.26.1 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/google/cel-go@v0.26.0/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/google/cel-go@v0.26.1/LICENSE: Apache License diff --git a/NOTICE.txt b/NOTICE.txt index fc5dad95354..2928ca9d121 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -81776,11 +81776,11 @@ Contents of probable licence file $GOMODCACHE/github.com/gomodule/redigo@v1.9.3/ -------------------------------------------------------------------------------- Dependency : github.com/google/cel-go -Version: v0.26.0 +Version: v0.26.1 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/google/cel-go@v0.26.0/LICENSE: +Contents of probable licence file $GOMODCACHE/github.com/google/cel-go@v0.26.1/LICENSE: Apache License diff --git a/go.mod b/go.mod index 0c36897f4a5..19fdf16f123 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,8 @@ module github.com/elastic/elastic-agent -go 1.24.13 +go 1.25.8 -replace github.com/elastic/beats/v7 => github.com/VihasMakwana/beats/v7 v7.0.0-20260306060228-d1a0f47dcbbc +replace github.com/elastic/beats/v7 => ./beats require ( github.com/Jeffail/gabs/v2 v2.6.0 diff --git a/go.sum b/go.sum index 0c1f3f64b29..833f4e51553 100644 --- a/go.sum +++ b/go.sum @@ -44,8 +44,6 @@ github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERo github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA= github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= -github.com/VihasMakwana/beats/v7 v7.0.0-20260306060228-d1a0f47dcbbc h1:EAusMNRqnzo9Bts7CCZHni0vECjKgQjoGu6n5FWkU7U= -github.com/VihasMakwana/beats/v7 v7.0.0-20260306060228-d1a0f47dcbbc/go.mod h1:PGY8/w5QSponBhQ5MEZCRRlpTKH5ARSNpGVyfkVXfhs= github.com/akavel/rsrc v0.10.2 h1:Zxm8V5eI1hW4gGaYsJQUhxpjkENuG91ki8B4zCrvEsw= github.com/akavel/rsrc v0.10.2/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ= diff --git a/internal/edot/go.mod b/internal/edot/go.mod index 3dca9e35a0c..48e57c1d7ac 100644 --- a/internal/edot/go.mod +++ b/internal/edot/go.mod @@ -1,11 +1,11 @@ module github.com/elastic/elastic-agent/internal/edot -go 1.24.13 +go 1.25.8 // use in-repo directory replace github.com/elastic/elastic-agent => ../../ -replace github.com/elastic/beats/v7 => github.com/VihasMakwana/beats/v7 v7.0.0-20260306060228-d1a0f47dcbbc +replace github.com/elastic/beats/v7 => ../../beats require ( github.com/elastic/beats/v7 v7.0.0-alpha2.0.20260305175215-8ed67e48c418 @@ -427,7 +427,7 @@ require ( github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v1.0.0 // indirect github.com/gomodule/redigo v1.9.3 // indirect - github.com/google/cel-go v0.26.0 // indirect + github.com/google/cel-go v0.26.1 // indirect github.com/google/flatbuffers v25.2.10+incompatible // indirect github.com/google/gnostic-models v0.7.0 // indirect github.com/google/go-cmp v0.7.0 diff --git a/internal/edot/go.sum b/internal/edot/go.sum index e13cdec0330..9107c72c2fe 100644 --- a/internal/edot/go.sum +++ b/internal/edot/go.sum @@ -184,8 +184,6 @@ github.com/UNO-SOFT/zlog v0.8.1 h1:TEFkGJHtUfTRgMkLZiAjLSHALjwSBdw6/zByMC5GJt4= github.com/UNO-SOFT/zlog v0.8.1/go.mod h1:yqFOjn3OhvJ4j7ArJqQNA+9V+u6t9zSAyIZdWdMweWc= github.com/VictoriaMetrics/easyproto v0.1.4 h1:r8cNvo8o6sR4QShBXQd1bKw/VVLSQma/V2KhTBPf+Sc= github.com/VictoriaMetrics/easyproto v0.1.4/go.mod h1:QlGlzaJnDfFd8Lk6Ci/fuLxfTo3/GThPs2KH23mv710= -github.com/VihasMakwana/beats/v7 v7.0.0-20260306060228-d1a0f47dcbbc h1:EAusMNRqnzo9Bts7CCZHni0vECjKgQjoGu6n5FWkU7U= -github.com/VihasMakwana/beats/v7 v7.0.0-20260306060228-d1a0f47dcbbc/go.mod h1:PGY8/w5QSponBhQ5MEZCRRlpTKH5ARSNpGVyfkVXfhs= github.com/aerospike/aerospike-client-go/v7 v7.7.1 h1:lcskBtPZYe6ESObhIEQEp4XO1axYZpaFD3ie4iwr6tg= github.com/aerospike/aerospike-client-go/v7 v7.7.1/go.mod h1:STlBtOkKT8nmp7iD+sEkr/JGEOu+4e2jGlNN0Jiu2a4= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= @@ -750,8 +748,8 @@ github.com/gomodule/redigo v1.9.3/go.mod h1:KsU3hiK/Ay8U42qpaJk+kuNa3C+spxapWpM+ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= -github.com/google/cel-go v0.26.0 h1:DPGjXackMpJWH680oGY4lZhYjIameYmR+/6RBdDGmaI= -github.com/google/cel-go v0.26.0/go.mod h1:A9O8OU9rdvrK5MQyrqfIxo1a0u4g3sF8KB6PUIaryMM= +github.com/google/cel-go v0.26.1 h1:iPbVVEdkhTX++hpe3lzSk7D3G3QSYqLGoHOcEio+UXQ= +github.com/google/cel-go v0.26.1/go.mod h1:A9O8OU9rdvrK5MQyrqfIxo1a0u4g3sF8KB6PUIaryMM= github.com/google/flatbuffers v25.2.10+incompatible h1:F3vclr7C3HpB1k9mxCGRMXq6FdUalZ6H/pNX4FP1v0Q= github.com/google/flatbuffers v25.2.10+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo= diff --git a/internal/edot/otelcol/components.go b/internal/edot/otelcol/components.go index 0e42f679742..fdfd401cf70 100644 --- a/internal/edot/otelcol/components.go +++ b/internal/edot/otelcol/components.go @@ -93,7 +93,7 @@ import ( filestorage "github.com/open-telemetry/opentelemetry-collector-contrib/extension/storage/filestorage" "go.opentelemetry.io/collector/extension/memorylimiterextension" // for putting backpressure when approach a memory limit - elasticstorage "github.com/elastic/beats/v7/x-pack/otel/extension/elasticstorage" + elasticsearchstorage "github.com/elastic/beats/v7/x-pack/otel/extension/elasticsearchstorage" elasticdiagnostics "github.com/elastic/elastic-agent/internal/pkg/otel/extension/elasticdiagnostics" "github.com/elastic/opentelemetry-collector-components/extension/apikeyauthextension" @@ -239,7 +239,7 @@ func components(extensionFactories ...extension.Factory) func() (otelcol.Factori headersetterextension.NewFactory(), beatsauthextension.NewFactory(), elasticdiagnostics.NewFactory(), - elasticstorage.NewFactory(), + elasticsearchstorage.NewFactory(), awslogsencodingextension.NewFactory(), opampextension.NewFactory(), } diff --git a/wrapper/windows/archive-proxy/go.mod b/wrapper/windows/archive-proxy/go.mod index 937077e2cc9..7425f7c6522 100644 --- a/wrapper/windows/archive-proxy/go.mod +++ b/wrapper/windows/archive-proxy/go.mod @@ -1,6 +1,6 @@ module github.com/elastic/elastic-agent/wrapper/windows/archive-proxy -go 1.24.13 +go 1.25.8 require github.com/elastic/elastic-agent v0.0.0 From eee43cab47bce043a6019f919c6a771f73c093a3 Mon Sep 17 00:00:00 2001 From: VihasMakwana <121151420+VihasMakwana@users.noreply.github.com> Date: Thu, 12 Mar 2026 01:14:14 +0530 Subject: [PATCH 08/10] submodule update after bug fix --- beats | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/beats b/beats index d634b972a87..987765e10c4 160000 --- a/beats +++ b/beats @@ -1 +1 @@ -Subproject commit d634b972a87241bf37b956d774490a3a118cc0e6 +Subproject commit 987765e10c47145762c8d2311c4653ef58f6ba75 From b9cfb33a89d347e25dbea55932788b3f47e0ddcc Mon Sep 17 00:00:00 2001 From: VihasMakwana <121151420+VihasMakwana@users.noreply.github.com> Date: Thu, 12 Mar 2026 01:15:34 +0530 Subject: [PATCH 09/10] update test case --- internal/pkg/otel/translate/otelconfig.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/pkg/otel/translate/otelconfig.go b/internal/pkg/otel/translate/otelconfig.go index 8bdacf47899..8e2ec3e8c3d 100644 --- a/internal/pkg/otel/translate/otelconfig.go +++ b/internal/pkg/otel/translate/otelconfig.go @@ -43,7 +43,7 @@ const ( outputOtelOverrideFieldName = "otel" outputOtelOverrideExporterFieldName = "exporter" outputOtelOverrideExtensionsFieldName = "extensions" - elasticsearchStateStoreExtensionName = "elastic_storage" + elasticsearchStateStoreExtensionName = "elasticsearch_storage" ) // BeatMonitoringConfigGetter is a function that returns the monitoring configuration for a beat receiver. @@ -393,7 +393,7 @@ func getReceiversConfigForComponent( "inputs": inputs, } if fbfeatures.IsElasticsearchStateStoreEnabled() { - receiverConfig["storage"] = "elastic_storage" + receiverConfig["storage"] = elasticsearchStateStoreExtensionName } case "metricbeat": receiverConfig[beatName] = map[string]any{ From ac1f1b242ef93d50d32958319bfe9ce4bb3a164a Mon Sep 17 00:00:00 2001 From: VihasMakwana <121151420+VihasMakwana@users.noreply.github.com> Date: Fri, 13 Mar 2026 19:34:40 +0530 Subject: [PATCH 10/10] changelog and integration test --- .../1773394006-state-store-extension.yaml | 45 +++ testing/integration/ess/otel_test.go | 271 ++++++++++++++++++ 2 files changed, 316 insertions(+) create mode 100644 changelog/fragments/1773394006-state-store-extension.yaml diff --git a/changelog/fragments/1773394006-state-store-extension.yaml b/changelog/fragments/1773394006-state-store-extension.yaml new file mode 100644 index 00000000000..687e784a898 --- /dev/null +++ b/changelog/fragments/1773394006-state-store-extension.yaml @@ -0,0 +1,45 @@ +# REQUIRED +# Kind can be one of: +# - breaking-change: a change to previously-documented behavior +# - deprecation: functionality that is being removed in a later release +# - bug-fix: fixes a problem in a previous version +# - enhancement: extends functionality but does not break or fix existing behavior +# - feature: new functionality +# - known-issue: problems that we are aware of in a given version +# - security: impacts on the security of a product or a user’s deployment. +# - upgrade: important information for someone upgrading from a prior version +# - other: does not fit into any of the other categories +kind: bug-fix + +# REQUIRED for all kinds +# Change summary; a 80ish characters long description of the change. +summary: Fix event ingestion for agentless in otel mode. + +# REQUIRED for breaking-change, deprecation, known-issue +# Long description; in case the summary is not enough to describe the change +# this field accommodate a description without length limits. +# description: + +# REQUIRED for breaking-change, deprecation, known-issue +# impact: + +# REQUIRED for breaking-change, deprecation, known-issue +# action: + +# REQUIRED for all kinds +# Affected component; usually one of "elastic-agent", "fleet-server", "filebeat", "metricbeat", "auditbeat", "all", etc. +component: elastic-agent + +# AUTOMATED +# OPTIONAL to manually add other PR URLs +# PR URL: A link the PR that added the changeset. +# If not present is automatically filled by the tooling finding the PR where this changelog fragment has been added. +# NOTE: the tooling supports backports, so it's able to fill the original PR number instead of the backport PR number. +# Please provide it if you are adding a fragment for a different PR. +# pr: https://github.com/owner/repo/1234 + +# AUTOMATED +# OPTIONAL to manually add other issue URLs +# Issue URL; optional; the GitHub issue related to this changeset (either closes or is part of). +# If not present is automatically filled by the tooling with the issue linked to the PR number. +# issue: https://github.com/owner/repo/1234 diff --git a/testing/integration/ess/otel_test.go b/testing/integration/ess/otel_test.go index fd7c81185a2..ff6b360667b 100644 --- a/testing/integration/ess/otel_test.go +++ b/testing/integration/ess/otel_test.go @@ -13,6 +13,8 @@ import ( "encoding/pem" "errors" "fmt" + "net" + "net/http" "os" "path/filepath" "strings" @@ -2537,6 +2539,275 @@ service: cancel() } +func TestOtelElasticsearchStateStore_Agentless(t *testing.T) { + info := define.Require(t, define.Requirements{ + Group: integration.Default, + Local: true, + OS: []define.OS{ + {Type: define.Linux}, + {Type: define.Darwin}, + }, + Stack: &define.Stack{}, + }) + + esEndpoint, err := integration.GetESHost() + require.NoError(t, err, "error getting elasticsearch endpoint") + esApiKey := createESApiKey(t, info.ESClient) + decodedApiKey, err := getDecodedApiKey(esApiKey) + require.NoError(t, err) + + mock := newHTTPJSONCursorMockServer(t) + defer mock.Close() + + type configOptions struct { + ESEndpoint string + ESApiKey string + InputURL string + } + + configTemplate := ` +agent.internal.runtime.filebeat.httpjson: otel +agent.monitoring.enabled: false +inputs: + - type: httpjson + id: httpjson-es-state-store + use_output: default + streams: + - id: httpjson-cursor-stream + data_stream: + dataset: httpjson_statestore + request.url: {{.InputURL}} + request.method: GET + request.transforms: + - set: + target: url.params.since + value: '[[.cursor.published]]' + default: '[[formatDate (now (parseDuration "-24h")) "RFC3339"]]' + cursor: + published: + value: '[[.last_event.published]]' + interval: 5s +outputs: + default: + type: elasticsearch + hosts: [{{.ESEndpoint}}] + api_key: "{{.ESApiKey}}" + preset: balanced +agent.grpc: + # listen address for the GRPC server that spawned processes connect back to. + address: localhost +# # port for the GRPC server that spawned processes connect back to. + port: 6794 + +` + var configBuffer bytes.Buffer + require.NoError(t, + template.Must(template.New("config").Parse(configTemplate)).Execute(&configBuffer, + configOptions{ + ESEndpoint: esEndpoint, + ESApiKey: decodedApiKey, + InputURL: mock.URL, + })) + + fixture, err := define.NewFixtureFromLocalBuild(t, define.Version()) + require.NoError(t, err) + + ctx, cancel := testcontext.WithDeadline(t, t.Context(), time.Now().Add(5*time.Minute)) + err = fixture.Prepare(ctx) + require.NoError(t, err) + + err = fixture.Configure(ctx, configBuffer.Bytes()) + require.NoError(t, err) + + dataIndex := ".ds-logs-httpjson_statestore-*" + + cmd, err := fixture.PrepareAgentCommand(ctx, nil) + require.NoError(t, err) + + cmd.Env = append(os.Environ(), "AGENTLESS_ELASTICSEARCH_STATE_STORE_INPUT_TYPES=httpjson") + + output := &strings.Builder{} + cmd.Stderr = output + cmd.Stdout = output + + err = cmd.Start() + require.NoError(t, err) + + t.Cleanup(func() { + _ = cmd.Wait() + if t.Failed() { + t.Log("Elastic-Agent output (1st run):") + t.Log(output.String()) + } + }) + + // Wait for data to arrive in the data index + require.EventuallyWithT(t, + func(ct *assert.CollectT) { + findCtx, findCancel := context.WithTimeout(ctx, 10*time.Second) + defer findCancel() + + docs, err := estools.GetAllLogsForIndexWithContext(findCtx, info.ESClient, dataIndex) + assert.NoError(ct, err) + assert.GreaterOrEqual(ct, docs.Hits.Total.Value, 1, "expected at least 1 event") + }, + 2*time.Minute, 1*time.Second, "expected data in the data index") + + // Wait for at least 2 polling cycles so the cursor is persisted to ES + require.Eventually(t, func() bool { + return mock.RequestCount() >= 2 + }, 60*time.Second, 1*time.Second, "expected at least 2 httpjson poll cycles") + + // Verify state exists in the agentless-state-* index + require.EventuallyWithT(t, + func(ct *assert.CollectT) { + findCtx, findCancel := context.WithTimeout(ctx, 10*time.Second) + defer findCancel() + + docs, err := estools.GetAllLogsForIndexWithContext(findCtx, info.ESClient, "agentless-state-*") + assert.NoError(ct, err) + assert.GreaterOrEqual(ct, docs.Hits.Total.Value, 1, "expected state document in agentless-state-* index") + }, + 30*time.Second, 1*time.Second, "expected cursor state in agentless-state-* index") + + // Record the cursor timestamp just before stopping + lastCursorBeforeStop := mock.LastSinceParam() + require.False(t, lastCursorBeforeStop.IsZero(), "expected at least one 'since' parameter before stopping") + t.Logf("cursor before stop: %s (request count: %d)", lastCursorBeforeStop.Format(time.RFC3339), mock.RequestCount()) + + // Stop the first agent + requestCountBeforeRestart := mock.RequestCount() + cancel() + cmd.Wait() + + mock.MarkRestart() + + ctx, cancel = testcontext.WithDeadline(t, t.Context(), time.Now().Add(5*time.Minute)) + cmd2, err := fixture.PrepareAgentCommand(ctx, nil) + require.NoError(t, err) + + cmd2.Env = append(os.Environ(), "AGENTLESS_ELASTICSEARCH_STATE_STORE_INPUT_TYPES=httpjson") + + output2 := &strings.Builder{} + cmd2.Stderr = output2 + cmd2.Stdout = output2 + + err = cmd2.Start() + require.NoError(t, err) + t.Cleanup(func() { + if cmd2.Process != nil { + _ = cmd2.Process.Kill() + } + _ = cmd2.Wait() + if t.Failed() { + t.Log("Elastic-Agent output (2nd run):") + t.Log(output2.String()) + } + }) + + // Wait for the httpjson input to resume polling after restart + require.Eventually(t, func() bool { + return mock.RequestCount() > requestCountBeforeRestart + }, 60*time.Second, 1*time.Second, "expected httpjson to resume polling after restart") + + // Verify the restored cursor: the first "since" parameter after restart + // should be recent (within 5 minutes), NOT the default 24h-ago value. + // If the cursor was not restored from ES, the httpjson input would fall + // back to its default: formatDate (now (parseDuration "-24h")). + firstSinceAfterRestart := mock.FirstSinceAfterRestart() + require.False(t, firstSinceAfterRestart.IsZero(), "expected a 'since' parameter after restart") + + timeSinceCursor := time.Since(firstSinceAfterRestart) + t.Logf("first 'since' after restart: %s (age: %s)", firstSinceAfterRestart.Format(time.RFC3339), timeSinceCursor) + + assert.Less(t, timeSinceCursor, 5*time.Minute, + "restored cursor should be recent (within 5 minutes), not the default 24h ago; "+ + "got since=%s which is %s old", firstSinceAfterRestart.Format(time.RFC3339), timeSinceCursor) + + cancel() +} + +// httpJSONCursorMockServer is a test HTTP server for the httpjson input that +// tracks the "since" cursor parameter across requests and restarts. +type httpJSONCursorMockServer struct { + URL string + server *http.Server + + mu sync.Mutex + requestCount int64 + lastSince time.Time + restartMarked bool + firstSinceAfterRestart time.Time +} + +func newHTTPJSONCursorMockServer(t *testing.T) *httpJSONCursorMockServer { + t.Helper() + mock := &httpJSONCursorMockServer{} + + mux := http.NewServeMux() + mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + mock.mu.Lock() + mock.requestCount++ + + // Parse the "since" query parameter sent by the httpjson cursor + sinceParam := r.URL.Query().Get("since") + if sinceParam != "" { + if parsed, err := time.Parse(time.RFC3339, sinceParam); err == nil { + mock.lastSince = parsed + if mock.restartMarked && mock.firstSinceAfterRestart.IsZero() { + mock.firstSinceAfterRestart = parsed + } + } + } + mock.mu.Unlock() + + // Respond with a JSON body containing "published" — the httpjson + // cursor will store this and send it back as "since" next time. + published := time.Now().UTC() + w.Header().Set("Content-Type", "application/json") + fmt.Fprintf(w, `{"message":"hello","published":"%s"}`, published.Format(time.RFC3339)) + }) + + mock.server = &http.Server{Handler: mux} + listener, err := net.Listen("tcp", "127.0.0.1:0") + require.NoError(t, err) + + go func() { _ = mock.server.Serve(listener) }() + mock.URL = fmt.Sprintf("http://%s", listener.Addr().String()) + + return mock +} + +func (m *httpJSONCursorMockServer) RequestCount() int64 { + m.mu.Lock() + defer m.mu.Unlock() + return m.requestCount +} + +func (m *httpJSONCursorMockServer) LastSinceParam() time.Time { + m.mu.Lock() + defer m.mu.Unlock() + return m.lastSince +} + +func (m *httpJSONCursorMockServer) MarkRestart() { + m.mu.Lock() + defer m.mu.Unlock() + m.restartMarked = true +} + +func (m *httpJSONCursorMockServer) FirstSinceAfterRestart() time.Time { + m.mu.Lock() + defer m.mu.Unlock() + return m.firstSinceAfterRestart +} + +func (m *httpJSONCursorMockServer) Close() { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + _ = m.server.Shutdown(ctx) +} + type ZapWriter struct { logger *zap.Logger level zapcore.Level