From 01559fb2bb81d64edda2d99f6d946d61d9421625 Mon Sep 17 00:00:00 2001 From: Faith Chikwekwe Date: Thu, 16 Nov 2023 10:53:18 -0500 Subject: [PATCH] feat: add ability to filter and export markers (#27862) **Description:** This add logic to filter logs based on log conditions and sent desired logs as event markers to the honeycomb marker api. **Link to tracking Issue:** https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/27666 **Testing:** Unit testing for log exporter and config. Added component testing to `otelcontribcol`. **Documentation:** README describing component usage Screenshot of exported markers showing up in Honeycomb Screenshot 2023-11-14 at 1 27 49 PM --------- Co-authored-by: Tyler Helmuth <12352919+TylerHelmuth@users.noreply.github.com> --- cmd/otelcontribcol/builder-config.yaml | 2 + cmd/otelcontribcol/components.go | 2 + cmd/otelcontribcol/exporters_test.go | 13 + cmd/otelcontribcol/go.mod | 3 + exporter/honeycombmarkerexporter/README.md | 43 ++- exporter/honeycombmarkerexporter/config.go | 50 ++-- .../honeycombmarkerexporter/config_test.go | 44 +-- exporter/honeycombmarkerexporter/factory.go | 11 +- exporter/honeycombmarkerexporter/go.mod | 14 + exporter/honeycombmarkerexporter/go.sum | 27 ++ .../honeycombmarkerexporter/logs_exporter.go | 121 +++++++- .../logs_exporter_test.go | 272 ++++++++++++++++++ .../testdata/config.yaml | 78 +++-- 13 files changed, 551 insertions(+), 129 deletions(-) create mode 100644 exporter/honeycombmarkerexporter/logs_exporter_test.go diff --git a/cmd/otelcontribcol/builder-config.yaml b/cmd/otelcontribcol/builder-config.yaml index 7d6f19ad8c01..9349963ff931 100644 --- a/cmd/otelcontribcol/builder-config.yaml +++ b/cmd/otelcontribcol/builder-config.yaml @@ -56,6 +56,7 @@ exporters: - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/exporter/googlecloudexporter v0.89.0 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/exporter/googlecloudpubsubexporter v0.89.0 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/exporter/googlemanagedprometheusexporter v0.89.0 + - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/exporter/honeycombmarkerexporter v0.89.0 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/exporter/influxdbexporter v0.89.0 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/exporter/instanaexporter v0.89.0 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/exporter/kafkaexporter v0.89.0 @@ -389,6 +390,7 @@ replaces: - github.com/open-telemetry/opentelemetry-collector-contrib/receiver/googlecloudpubsubreceiver => ../../receiver/googlecloudpubsubreceiver - github.com/open-telemetry/opentelemetry-collector-contrib/exporter/sumologicexporter => ../../exporter/sumologicexporter - github.com/open-telemetry/opentelemetry-collector-contrib/exporter/instanaexporter => ../../exporter/instanaexporter + - github.com/open-telemetry/opentelemetry-collector-contrib/exporter/honeycombmarkerexporter => ../../exporter/honeycombmarkerexporter - github.com/open-telemetry/opentelemetry-collector-contrib/receiver/otlpjsonfilereceiver => ../../receiver/otlpjsonfilereceiver - github.com/open-telemetry/opentelemetry-collector-contrib/processor/redactionprocessor => ../../processor/redactionprocessor - github.com/open-telemetry/opentelemetry-collector-contrib/extension/jaegerremotesampling => ../../extension/jaegerremotesampling diff --git a/cmd/otelcontribcol/components.go b/cmd/otelcontribcol/components.go index 449cd50ad7e3..619077fc7b12 100644 --- a/cmd/otelcontribcol/components.go +++ b/cmd/otelcontribcol/components.go @@ -47,6 +47,7 @@ import ( googlecloudexporter "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/googlecloudexporter" googlecloudpubsubexporter "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/googlecloudpubsubexporter" googlemanagedprometheusexporter "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/googlemanagedprometheusexporter" + honeycombmarkerexporter "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/honeycombmarkerexporter" influxdbexporter "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/influxdbexporter" instanaexporter "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/instanaexporter" kafkaexporter "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/kafkaexporter" @@ -348,6 +349,7 @@ func components() (otelcol.Factories, error) { googlecloudexporter.NewFactory(), googlecloudpubsubexporter.NewFactory(), googlemanagedprometheusexporter.NewFactory(), + honeycombmarkerexporter.NewFactory(), influxdbexporter.NewFactory(), instanaexporter.NewFactory(), kafkaexporter.NewFactory(), diff --git a/cmd/otelcontribcol/exporters_test.go b/cmd/otelcontribcol/exporters_test.go index ea2443a4456f..c1db9d66ee6c 100644 --- a/cmd/otelcontribcol/exporters_test.go +++ b/cmd/otelcontribcol/exporters_test.go @@ -40,6 +40,7 @@ import ( "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/elasticsearchexporter" "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/f5cloudexporter" "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/fileexporter" + "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/honeycombmarkerexporter" "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/influxdbexporter" "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/instanaexporter" "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/kafkaexporter" @@ -421,6 +422,18 @@ func TestDefaultExporters(t *testing.T) { exporter: "googlecloudpubsub", skipLifecycle: true, }, + { + exporter: "honeycombmarker", + getConfigFn: func() component.Config { + cfg := expFactories["honeycombmarker"].CreateDefaultConfig().(*honeycombmarkerexporter.Config) + cfg.Endpoint = "http://" + endpoint + // disable queue to validate passing the test data synchronously + cfg.QueueSettings.Enabled = false + cfg.RetrySettings.Enabled = false + return cfg + }, + expectConsumeErr: true, + }, { exporter: "influxdb", getConfigFn: func() component.Config { diff --git a/cmd/otelcontribcol/go.mod b/cmd/otelcontribcol/go.mod index 12a8f49aa01a..d50dd3469d5a 100644 --- a/cmd/otelcontribcol/go.mod +++ b/cmd/otelcontribcol/go.mod @@ -32,6 +32,7 @@ require ( github.com/open-telemetry/opentelemetry-collector-contrib/exporter/googlecloudexporter v0.89.0 github.com/open-telemetry/opentelemetry-collector-contrib/exporter/googlecloudpubsubexporter v0.89.0 github.com/open-telemetry/opentelemetry-collector-contrib/exporter/googlemanagedprometheusexporter v0.89.0 + github.com/open-telemetry/opentelemetry-collector-contrib/exporter/honeycombmarkerexporter v0.89.0 github.com/open-telemetry/opentelemetry-collector-contrib/exporter/influxdbexporter v0.89.0 github.com/open-telemetry/opentelemetry-collector-contrib/exporter/instanaexporter v0.89.0 github.com/open-telemetry/opentelemetry-collector-contrib/exporter/kafkaexporter v0.89.0 @@ -1082,6 +1083,8 @@ replace github.com/open-telemetry/opentelemetry-collector-contrib/exporter/sumol replace github.com/open-telemetry/opentelemetry-collector-contrib/exporter/instanaexporter => ../../exporter/instanaexporter +replace github.com/open-telemetry/opentelemetry-collector-contrib/exporter/honeycombmarkerexporter => ../../exporter/honeycombmarkerexporter + replace github.com/open-telemetry/opentelemetry-collector-contrib/receiver/otlpjsonfilereceiver => ../../receiver/otlpjsonfilereceiver replace github.com/open-telemetry/opentelemetry-collector-contrib/processor/redactionprocessor => ../../processor/redactionprocessor diff --git a/exporter/honeycombmarkerexporter/README.md b/exporter/honeycombmarkerexporter/README.md index c11819579877..e6a4cfb04c6a 100644 --- a/exporter/honeycombmarkerexporter/README.md +++ b/exporter/honeycombmarkerexporter/README.md @@ -5,38 +5,27 @@ This exporter allows creating markers, via the Honeycomb Markers API, based on t The following configuration options are supported: -* `api_key` (Required): This is the API key (also called Write Key) for your Honeycomb account. -* `api_url` (Required): You can set the hostname to send marker data to. -* `markers` (Required): This specifies the exact configuration to create an event marker. - * `type`: Specifies the marker type. Markers with the same type will appear in the same color in Honeycomb. MarkerType or MarkerColor should be set. - * `color`: Specifies the marker color. Will only be used if MarkerType is not set. - * `messagefield`: This is the attribute that will be used as the message. If necessary the value will be converted to a string. - * `urlfield`: This is the attribute that will be used as the url. If necessary the value will be converted to a string. - * `rules`: This is a list of OTTL rules that determine when to create an event marker. - * `resourceconditions`: A list of ottlresource conditions that determine a match - * `logconditions`: A list of ottllog conditions that determine a match +* `api_key` (Required): This is the API key for your Honeycomb account. +* `api_url` (Required): This sets the hostname to send marker data to. +* `markers` (Required): This is a list of configurations to create an event marker. + * `type` (Required): Specifies the marker type. + * `message_key`: This attribute will be used as the message. It describes the event marker. If necessary the value will be converted to a string. + * `url_key`: This attribute will be used as the url. It can be accessed through the event marker in Honeycomb. If necessary the value will be converted to a string. + * `rules` (Required): This is a list of OTTL rules that determine when to create an event marker. + * `log_conditions` (Required): A list of ottllog conditions that determine a match Example: ```yaml exporters: - honeycomb: - api_key: "my-api-key" - api_url: "https://api.testhost.io" + honeycombmarker: + api_key: "environment-api-key" + api_url: "https://api.honeycomb.io" markers: - - type: "fooType", - messagefield: "test message", - urlfield: "https://api.testhost.io", + - type: "marker-type" + message_key: "marker-message" + url_key: "marker-url" + dataset_slug: "__all__" rules: - - resourceconditions: - - IsMatch(attributes["test"], ".*") - - logconditions: - - body == "test" - - color: "green", - messagefield: "another test message", - urlfield: "https://api.testhost.io", - rules: - - resourceconditions: - - IsMatch(attributes["test"], ".*") - - logconditions: + - log_conditions: - body == "test" ``` \ No newline at end of file diff --git a/exporter/honeycombmarkerexporter/config.go b/exporter/honeycombmarkerexporter/config.go index bc9bf7d2987c..d94268f08f4b 100644 --- a/exporter/honeycombmarkerexporter/config.go +++ b/exporter/honeycombmarkerexporter/config.go @@ -7,11 +7,15 @@ import ( "fmt" "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/config/confighttp" "go.opentelemetry.io/collector/config/configopaque" + "go.opentelemetry.io/collector/exporter/exporterhelper" "go.uber.org/zap" + "github.com/open-telemetry/opentelemetry-collector-contrib/internal/filter/expr" "github.com/open-telemetry/opentelemetry-collector-contrib/internal/filter/filterottl" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl" + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/contexts/ottllog" ) // Config defines configuration for the Honeycomb Marker exporter. @@ -24,58 +28,60 @@ type Config struct { // Markers is the list of markers to create Markers []Marker `mapstructure:"markers"` + + confighttp.HTTPClientSettings `mapstructure:",squash"` + exporterhelper.QueueSettings `mapstructure:"sending_queue"` + exporterhelper.RetrySettings `mapstructure:"retry_on_failure"` } type Marker struct { - // Type defines the type of Marker. Markers with the same type appear in Honeycomb with the same color + // Type defines the type of Marker. Type string `mapstructure:"type"` - // Color is the color of the Marker. Will only be used if the Type does not already exist. - Color string `mapstructure:"color"` - - // MessageField is the attribute that will be used as the message. + // MessageKey is the attribute that will be used as the message. // If necessary the value will be converted to a string. - MessageField string `mapstructure:"message_field"` + MessageKey string `mapstructure:"message_key"` - // URLField is the attribute that will be used as the url. + // URLKey is the attribute that will be used as the url. // If necessary the value will be converted to a string. - URLField string `mapstructure:"url_field"` + URLKey string `mapstructure:"url_key"` // Rules are the OTTL rules that determine when a piece of telemetry should be turned into a Marker Rules Rules `mapstructure:"rules"` + + // DatasetSlug is the endpoint that specifies the Honeycomb environment + DatasetSlug string `mapstructure:"dataset_slug"` } type Rules struct { - // ResourceConditions is the list of ottlresource conditions that determine a match - ResourceConditions []string `mapstructure:"resource_conditions"` - // LogConditions is the list of ottllog conditions that determine a match LogConditions []string `mapstructure:"log_conditions"` + + logBoolExpr expr.BoolExpr[ottllog.TransformContext] } -var defaultCfg = createDefaultConfig().(*Config) +var _ component.Config = (*Config)(nil) func (cfg *Config) Validate() error { - if cfg == nil { - cfg = defaultCfg - } - if cfg.APIKey == "" { return fmt.Errorf("invalid API Key") } if len(cfg.Markers) != 0 { for _, m := range cfg.Markers { - if len(m.Rules.ResourceConditions) == 0 && len(m.Rules.LogConditions) == 0 { - return fmt.Errorf("no rules supplied for Marker %v", m) + if m.Type == "" { + return fmt.Errorf("marker must have a type %v", m) } - _, err := filterottl.NewBoolExprForResource(m.Rules.ResourceConditions, filterottl.StandardResourceFuncs(), ottl.PropagateError, component.TelemetrySettings{Logger: zap.NewNop()}) - if err != nil { - return err + if m.DatasetSlug == "" { + return fmt.Errorf("marker must have a dataset slug %v", m) + } + + if len(m.Rules.LogConditions) == 0 { + return fmt.Errorf("marker must have rules %v", m) } - _, err = filterottl.NewBoolExprForLog(m.Rules.LogConditions, filterottl.StandardLogFuncs(), ottl.PropagateError, component.TelemetrySettings{Logger: zap.NewNop()}) + _, err := filterottl.NewBoolExprForLog(m.Rules.LogConditions, filterottl.StandardLogFuncs(), ottl.PropagateError, component.TelemetrySettings{Logger: zap.NewNop()}) if err != nil { return err } diff --git a/exporter/honeycombmarkerexporter/config_test.go b/exporter/honeycombmarkerexporter/config_test.go index 9fbdc724db56..85a33fc701bb 100644 --- a/exporter/honeycombmarkerexporter/config_test.go +++ b/exporter/honeycombmarkerexporter/config_test.go @@ -11,6 +11,7 @@ import ( "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/confmap/confmaptest" + "go.opentelemetry.io/collector/exporter/exporterhelper" "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/honeycombmarkerexporter/internal/metadata" ) @@ -26,45 +27,23 @@ func TestLoadConfig(t *testing.T) { expected component.Config }{ { - id: component.NewIDWithName("honeycomb", ""), + id: component.NewIDWithName(metadata.Type, ""), expected: &Config{ - APIKey: "test-apikey", - APIURL: "https://api.testhost.io", + QueueSettings: exporterhelper.NewDefaultQueueSettings(), + RetrySettings: exporterhelper.NewDefaultRetrySettings(), + APIKey: "test-apikey", + APIURL: "https://api.testhost.io", Markers: []Marker{ { - Type: "fooType", - MessageField: "test message", - URLField: "https://api.testhost.io", + Type: "fooType", + MessageKey: "test message", + URLKey: "https://api.testhost.io", Rules: Rules{ - ResourceConditions: []string{ - `IsMatch(attributes["test"], ".*")`, - }, - LogConditions: []string{ - `body == "test"`, - }, - }, - }, - }, - }, - }, - { - id: component.NewIDWithName("honeycomb", "color_no_type"), - expected: &Config{ - APIKey: "test-apikey", - APIURL: "https://api.testhost.io", - Markers: []Marker{ - { - Color: "green", - MessageField: "test message", - URLField: "https://api.testhost.io", - Rules: Rules{ - ResourceConditions: []string{ - `IsMatch(attributes["test"], ".*")`, - }, LogConditions: []string{ `body == "test"`, }, }, + DatasetSlug: "__all__", }, }, }, @@ -81,6 +60,9 @@ func TestLoadConfig(t *testing.T) { { id: component.NewIDWithName(metadata.Type, "no_markers_supplied"), }, + { + id: component.NewIDWithName(metadata.Type, "no_dataset_slug"), + }, } for _, tt := range tests { diff --git a/exporter/honeycombmarkerexporter/factory.go b/exporter/honeycombmarkerexporter/factory.go index 36e26f4d7e7f..0d4adb2f947b 100644 --- a/exporter/honeycombmarkerexporter/factory.go +++ b/exporter/honeycombmarkerexporter/factory.go @@ -36,12 +36,19 @@ func createLogsExporter( ) (exporter.Logs, error) { cf := cfg.(*Config) - exporter := newLogsExporter(set.Logger, cf) + logsExp, err := newHoneycombLogsExporter(set.TelemetrySettings, cf) + if err != nil { + return nil, err + } return exporterhelper.NewLogsExporter( ctx, set, cfg, - exporter.exportLogs, + logsExp.exportMarkers, + exporterhelper.WithTimeout(exporterhelper.TimeoutSettings{Timeout: 0}), + exporterhelper.WithRetry(cf.RetrySettings), + exporterhelper.WithQueue(cf.QueueSettings), + exporterhelper.WithStart(logsExp.start), ) } diff --git a/exporter/honeycombmarkerexporter/go.mod b/exporter/honeycombmarkerexporter/go.mod index 71db80799c9d..983db14ff335 100644 --- a/exporter/honeycombmarkerexporter/go.mod +++ b/exporter/honeycombmarkerexporter/go.mod @@ -7,6 +7,7 @@ require ( github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl v0.89.0 github.com/stretchr/testify v1.8.4 go.opentelemetry.io/collector/component v0.89.0 + go.opentelemetry.io/collector/config/confighttp v0.89.0 go.opentelemetry.io/collector/config/configopaque v0.89.0 go.opentelemetry.io/collector/confmap v0.89.0 go.opentelemetry.io/collector/exporter v0.89.0 @@ -18,14 +19,20 @@ require ( github.com/alecthomas/participle/v2 v2.1.0 // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/felixge/httpsnoop v1.0.3 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/go-logr/logr v1.3.0 // indirect + github.com/go-logr/stdr v1.2.2 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/snappy v0.0.4 // indirect github.com/google/uuid v1.4.0 // indirect github.com/hashicorp/go-version v1.6.0 // indirect github.com/iancoleman/strcase v0.3.0 // indirect github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/compress v1.17.2 // indirect github.com/knadh/koanf/maps v0.1.1 // indirect github.com/knadh/koanf/providers/confmap v0.1.0 // indirect github.com/knadh/koanf/v2 v2.0.1 // indirect @@ -36,13 +43,20 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal v0.89.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/rs/cors v1.10.1 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/collector v0.89.0 // indirect + go.opentelemetry.io/collector/config/configauth v0.89.0 // indirect + go.opentelemetry.io/collector/config/configcompression v0.89.0 // indirect go.opentelemetry.io/collector/config/configtelemetry v0.89.0 // indirect + go.opentelemetry.io/collector/config/configtls v0.89.0 // indirect + go.opentelemetry.io/collector/config/internal v0.89.0 // indirect go.opentelemetry.io/collector/consumer v0.89.0 // indirect go.opentelemetry.io/collector/extension v0.89.0 // indirect + go.opentelemetry.io/collector/extension/auth v0.89.0 // indirect go.opentelemetry.io/collector/featuregate v1.0.0-rcv0018 // indirect go.opentelemetry.io/collector/receiver v0.89.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 // indirect go.opentelemetry.io/otel v1.20.0 // indirect go.opentelemetry.io/otel/metric v1.20.0 // indirect go.opentelemetry.io/otel/trace v1.20.0 // indirect diff --git a/exporter/honeycombmarkerexporter/go.sum b/exporter/honeycombmarkerexporter/go.sum index b95c66eb5230..6aa813c0b68a 100644 --- a/exporter/honeycombmarkerexporter/go.sum +++ b/exporter/honeycombmarkerexporter/go.sum @@ -19,10 +19,17 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= +github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= +github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -44,6 +51,8 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -65,6 +74,8 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4= +github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/knadh/koanf/maps v0.1.1 h1:G5TjmUh2D7G2YWf5SQQqSiHRJEjaicvU0KpypqB3NIs= github.com/knadh/koanf/maps v0.1.1/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI= github.com/knadh/koanf/providers/confmap v0.1.0 h1:gOkxhHkemwG4LezxxN8DMOFopOPghxRVp7JbIvdvqzU= @@ -94,6 +105,8 @@ github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lne github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI= github.com/prometheus/statsd_exporter v0.22.7 h1:7Pji/i2GuhK6Lu7DHrtTkFmNBCudCPT1pX2CziuyQR0= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rs/cors v1.10.1 h1:L0uuZVXIKlI1SShY2nhFfo44TYvDPQ1w4oFkUJNfhyo= +github.com/rs/cors v1.10.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -111,10 +124,20 @@ go.opentelemetry.io/collector v0.89.0 h1:lzpfD9NTHh+1M+qzcoYUH+i2rOgFSox3bGQFUI5 go.opentelemetry.io/collector v0.89.0/go.mod h1:UZUtmQ3kai0CLPWvPmHKpmwqqEoo50n1bwzYYhXX0eA= go.opentelemetry.io/collector/component v0.89.0 h1:PoQJX86BpaSZhzx0deQXHh3QMuW6XKVmolSdTKE506c= go.opentelemetry.io/collector/component v0.89.0/go.mod h1:ZZncnMVaNs++JIbAMiemUIWLZrZ3PMEzI3S3K8pnkws= +go.opentelemetry.io/collector/config/configauth v0.89.0 h1:F082cy1OwrjyucI0wgEO2lRPTWJlgJzM/I5d0BoVgp4= +go.opentelemetry.io/collector/config/configauth v0.89.0/go.mod h1:yRJj70B3MyfbyGuyKO1I+5LtGuvx/WLUh8kuQ/XX6RE= +go.opentelemetry.io/collector/config/configcompression v0.89.0 h1:Z4LG045HwoNqXaibVbAQkcAQGmvY4OHrY4eCppoAzoQ= +go.opentelemetry.io/collector/config/configcompression v0.89.0/go.mod h1:LaavoxZsro5lL7qh1g9DMifG0qixWPEecW18Qr8bpag= +go.opentelemetry.io/collector/config/confighttp v0.89.0 h1:RatLdeZkCu3uLtCjbS8g5Aec2JB3/CSpB6O7P081Bhg= +go.opentelemetry.io/collector/config/confighttp v0.89.0/go.mod h1:R5BIbvqlxSDQGpCRWd2HBZIWijfSIWRpLeSpZjkKkag= go.opentelemetry.io/collector/config/configopaque v0.89.0 h1:Ad6yGcGBHs+J9SNjkedY68JsLZ1vBn4kKzdqKuTCRsE= go.opentelemetry.io/collector/config/configopaque v0.89.0/go.mod h1:TPCHaU+QXiEV+JXbgyr6mSErTI9chwQyasDVMdJr3eY= go.opentelemetry.io/collector/config/configtelemetry v0.89.0 h1:NtRknYDfMgP1r8mnByo6qQQK8IBw/lF9Qke5f7VhGZ0= go.opentelemetry.io/collector/config/configtelemetry v0.89.0/go.mod h1:+LAXM5WFMW/UbTlAuSs6L/W72WC+q8TBJt/6z39FPOU= +go.opentelemetry.io/collector/config/configtls v0.89.0 h1:XDeUaTU7LYwnEXz/CSdjbCStJa7n0YR1q0QpK0Vtw9w= +go.opentelemetry.io/collector/config/configtls v0.89.0/go.mod h1:NlE4elqXoyFfzQvYfzgH6uOU1zNVa+5tt6EIq52TJ9Y= +go.opentelemetry.io/collector/config/internal v0.89.0 h1:fs7LJTJd1EF76pjK7ZZZMWNxze0+pDXq3mfRwhm0P0g= +go.opentelemetry.io/collector/config/internal v0.89.0/go.mod h1:42VsQ/1kP2qnvzjNi+dfNP+KyCFRADejyrJ8m2GVL3M= go.opentelemetry.io/collector/confmap v0.89.0 h1:N5Vg1+FXEFBHHlGIPg4OSlM9uTHjCI7RlWWrKjtOzWQ= go.opentelemetry.io/collector/confmap v0.89.0/go.mod h1:D8FMPvuihtVxwXaz/qp5q9X2lq9l97QyjfsdZD1spmc= go.opentelemetry.io/collector/consumer v0.89.0 h1:MteKhkudX2L1ylbtdpSazO8SwyHSxl6fUEElc0rRLDQ= @@ -123,12 +146,16 @@ go.opentelemetry.io/collector/exporter v0.89.0 h1:8sYpJdKDQ2RuYOPKDsMz/lMJqp4WEW go.opentelemetry.io/collector/exporter v0.89.0/go.mod h1:zR8PFXMHlG0qPIEdRPNaefxDNj4UVP47uJ4vbHs+YME= go.opentelemetry.io/collector/extension v0.89.0 h1:iiaWIPPFqP4T0FSgl6+D1xRUhVnhsk88uk2BxCFqt7E= go.opentelemetry.io/collector/extension v0.89.0/go.mod h1:tBh5wD4AZ3xFO6M1CjkEEx2urexTqcAcgi9cJSPME3E= +go.opentelemetry.io/collector/extension/auth v0.89.0 h1:eo9JoWklZdSManEPLm1LqlwEq5v/YIsOupjZHdRYm3I= +go.opentelemetry.io/collector/extension/auth v0.89.0/go.mod h1:TzC5WYGMgsZvkpYSU1Jlwxh46tSDmWRLFsc9awXaedk= go.opentelemetry.io/collector/featuregate v1.0.0-rcv0018 h1:iK4muX3KIMqKk0xwKcRzu4ravgCtUdzsvuxxdz6A27g= go.opentelemetry.io/collector/featuregate v1.0.0-rcv0018/go.mod h1:xGbRuw+GbutRtVVSEy3YR2yuOlEyiUMhN2M9DJljgqY= go.opentelemetry.io/collector/pdata v1.0.0-rcv0018 h1:a2IHOZKphRzPagcvOHQHHUE0DlITFSKlIBwaWhPZpl4= go.opentelemetry.io/collector/pdata v1.0.0-rcv0018/go.mod h1:oNIcTRyEJYIfMcRYyyh5lquDU0Vl+ktTL6ka+p+dYvg= go.opentelemetry.io/collector/receiver v0.89.0 h1:wC/FB8e2Ej06jjNW2OiuZoyiSyB8TQNIzYyPlh9oRqI= go.opentelemetry.io/collector/receiver v0.89.0/go.mod h1:Rk7Bkz45fVdrcJaVDsPTnHa97ZfSs1ULO76LXc4kLN0= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 h1:x8Z78aZx8cOF0+Kkazoc7lwUNMGy0LrzEMxTm4BbTxg= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0/go.mod h1:62CPTSry9QZtOaSsE3tOzhx6LzDhHnXJ6xHeMNNiM6Q= go.opentelemetry.io/otel v1.20.0 h1:vsb/ggIY+hUjD/zCAQHpzTmndPqv/ml2ArbsbfBYTAc= go.opentelemetry.io/otel v1.20.0/go.mod h1:oUIGj3D77RwJdM6PPZImDpSZGDvkD9fhesHny69JFrs= go.opentelemetry.io/otel/exporters/prometheus v0.43.0 h1:Skkl6akzvdWweXX6LLAY29tyFSO6hWZ26uDbVGTDXe8= diff --git a/exporter/honeycombmarkerexporter/logs_exporter.go b/exporter/honeycombmarkerexporter/logs_exporter.go index 3dfe36d5d9bc..608fe4ef0c9f 100644 --- a/exporter/honeycombmarkerexporter/logs_exporter.go +++ b/exporter/honeycombmarkerexporter/logs_exporter.go @@ -4,25 +4,134 @@ package honeycombmarkerexporter // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/honeycombmarkerexporter" import ( + "bytes" "context" + "encoding/json" + "fmt" + "io" + "net/http" + "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/pdata/plog" - "go.uber.org/zap" + + "github.com/open-telemetry/opentelemetry-collector-contrib/internal/filter/filterottl" + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl" + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/contexts/ottllog" ) type honeycombLogsExporter struct { - logger *zap.Logger + set component.TelemetrySettings markers []Marker + client *http.Client + config *Config } -func newLogsExporter(logger *zap.Logger, config *Config) *honeycombLogsExporter { +func newHoneycombLogsExporter(set component.TelemetrySettings, config *Config) (*honeycombLogsExporter, error) { + if config == nil { + return nil, fmt.Errorf("unable to create honeycombLogsExporter without config") + } + + for i, m := range config.Markers { + matchLogConditions, err := filterottl.NewBoolExprForLog(m.Rules.LogConditions, filterottl.StandardLogFuncs(), ottl.PropagateError, set) + if err != nil { + return nil, fmt.Errorf("failed to parse log conditions: %w", err) + } + + config.Markers[i].Rules.logBoolExpr = matchLogConditions + } logsExp := &honeycombLogsExporter{ - logger: logger, + set: set, markers: config.Markers, + config: config, } - return logsExp + return logsExp, nil } -func (e *honeycombLogsExporter) exportLogs(_ context.Context, _ plog.Logs) error { +func (e *honeycombLogsExporter) exportMarkers(ctx context.Context, ld plog.Logs) error { + for i := 0; i < ld.ResourceLogs().Len(); i++ { + rlogs := ld.ResourceLogs().At(i) + for j := 0; j < rlogs.ScopeLogs().Len(); j++ { + slogs := rlogs.ScopeLogs().At(j) + logs := slogs.LogRecords() + for k := 0; k < logs.Len(); k++ { + logRecord := logs.At(k) + tCtx := ottllog.NewTransformContext(logRecord, slogs.Scope(), rlogs.Resource()) + for _, m := range e.markers { + match, err := m.Rules.logBoolExpr.Eval(ctx, tCtx) + if err != nil { + return err + } + if match { + err := e.sendMarker(ctx, m, logRecord) + if err != nil { + return err + } + } + } + + } + } + } + return nil +} + +func (e *honeycombLogsExporter) sendMarker(ctx context.Context, marker Marker, logRecord plog.LogRecord) error { + requestMap := map[string]string{ + "type": marker.Type, + } + + messageValue, found := logRecord.Attributes().Get(marker.MessageKey) + if found { + requestMap["message"] = messageValue.AsString() + } + + URLValue, found := logRecord.Attributes().Get(marker.URLKey) + if found { + requestMap["url"] = URLValue.AsString() + } + + request, err := json.Marshal(requestMap) + if err != nil { + return err + } + + url := fmt.Sprintf("%s/1/markers/%s", e.config.APIURL, marker.DatasetSlug) + req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(request)) + if err != nil { + return err + } + + req.Header.Set("Content-Type", "application/json") + req.Header.Set("X-Honeycomb-Team", fmt.Sprint(e.config.APIKey)) + + resp, err := e.client.Do(req) + if err != nil { + return fmt.Errorf("failed to send a request: %w", err) + } + + defer func() { + _ = resp.Body.Close() + }() + + if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusBadRequest { + b, err := io.ReadAll(resp.Body) + if err != nil { + return fmt.Errorf("marker creation failed with %s and unable to read response body: %w", resp.Status, err) + } + return fmt.Errorf("marker creation failed with %s and message: %s", resp.Status, b) + } + + return nil +} + +func (e *honeycombLogsExporter) start(_ context.Context, host component.Host) (err error) { + client, err := e.config.HTTPClientSettings.ToClient(host, e.set) + + if err != nil { + return err + } + + e.client = client + return nil } diff --git a/exporter/honeycombmarkerexporter/logs_exporter_test.go b/exporter/honeycombmarkerexporter/logs_exporter_test.go new file mode 100644 index 000000000000..a7e3cd8aad0f --- /dev/null +++ b/exporter/honeycombmarkerexporter/logs_exporter_test.go @@ -0,0 +1,272 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package honeycombmarkerexporter + +import ( + "context" + "encoding/json" + "net/http" + "net/http/httptest" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.opentelemetry.io/collector/component/componenttest" + "go.opentelemetry.io/collector/exporter/exportertest" + "go.opentelemetry.io/collector/pdata/plog" +) + +func TestExportMarkers(t *testing.T) { + tests := []struct { + name string + config Config + attributeMap map[string]string + }{ + { + name: "all fields", + config: Config{ + APIKey: "test-apikey", + Markers: []Marker{ + { + Type: "test-type", + MessageKey: "message", + URLKey: "url", + DatasetSlug: "test-dataset", + Rules: Rules{ + LogConditions: []string{ + `body == "test"`, + }, + }, + }, + }, + }, + attributeMap: map[string]string{ + "message": "this is a test message", + "url": "https://api.testhost.io", + "type": "test-type", + }, + }, + { + name: "no message key", + config: Config{ + APIKey: "test-apikey", + Markers: []Marker{ + { + Type: "test-type", + URLKey: "url", + DatasetSlug: "test-dataset", + Rules: Rules{ + LogConditions: []string{ + `body == "test"`, + }, + }, + }, + }, + }, + attributeMap: map[string]string{ + "url": "https://api.testhost.io", + "type": "test-type", + }, + }, + { + name: "no url", + config: Config{ + APIKey: "test-apikey", + Markers: []Marker{ + { + Type: "test-type", + MessageKey: "message", + DatasetSlug: "test-dataset", + Rules: Rules{ + LogConditions: []string{ + `body == "test"`, + }, + }, + }, + }, + }, + attributeMap: map[string]string{ + "message": "this is a test message", + "type": "test-type", + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + markerServer := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { + decodedBody := map[string]any{} + err := json.NewDecoder(req.Body).Decode(&decodedBody) + + require.NoError(t, err) + + assert.Equal(t, len(decodedBody), len(tt.attributeMap)) + + for attr := range tt.attributeMap { + assert.Equal(t, decodedBody[attr], tt.attributeMap[attr]) + } + assert.Contains(t, req.URL.Path, tt.config.Markers[0].DatasetSlug) + + apiKey := req.Header.Get("X-Honeycomb-Team") + assert.Equal(t, apiKey, string(tt.config.APIKey)) + + rw.WriteHeader(http.StatusAccepted) + })) + defer markerServer.Close() + + config := tt.config + config.APIURL = markerServer.URL + + f := NewFactory() + exp, err := f.CreateLogsExporter(context.Background(), exportertest.NewNopCreateSettings(), &config) + require.NoError(t, err) + + err = exp.Start(context.Background(), componenttest.NewNopHost()) + assert.NoError(t, err) + + logs := constructLogs(tt.attributeMap) + err = exp.ConsumeLogs(context.Background(), logs) + assert.NoError(t, err) + }) + } +} + +func constructLogs(attributes map[string]string) plog.Logs { + logs := plog.NewLogs() + rl := logs.ResourceLogs().AppendEmpty() + sl := rl.ScopeLogs().AppendEmpty() + l := sl.LogRecords().AppendEmpty() + + l.Body().SetStr("test") + for attr, attrVal := range attributes { + l.Attributes().PutStr(attr, attrVal) + } + return logs +} + +func TestExportMarkers_Error(t *testing.T) { + tests := []struct { + name string + config Config + responseCode int + errorMessage string + }{ + { + name: "unauthorized greater than 400", + config: Config{ + APIKey: "test-apikey", + Markers: []Marker{ + { + Type: "test-type", + MessageKey: "message", + URLKey: "https://api.testhost.io", + DatasetSlug: "test-dataset", + Rules: Rules{ + LogConditions: []string{ + `body == "test"`, + }, + }, + }, + }, + }, + responseCode: http.StatusUnauthorized, + errorMessage: "marker creation failed with 401", + }, + { + name: "continue less than 200", + config: Config{ + APIKey: "test-apikey", + Markers: []Marker{ + { + Type: "test-type", + MessageKey: "message", + URLKey: "https://api.testhost.io", + DatasetSlug: "test-dataset", + Rules: Rules{ + LogConditions: []string{ + `body == "test"`, + }, + }, + }, + }, + }, + responseCode: http.StatusSwitchingProtocols, + errorMessage: "marker creation failed with 101", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + markerServer := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { + rw.WriteHeader(tt.responseCode) + })) + defer markerServer.Close() + + config := tt.config + config.APIURL = markerServer.URL + + f := NewFactory() + exp, err := f.CreateLogsExporter(context.Background(), exportertest.NewNopCreateSettings(), &config) + require.NoError(t, err) + + err = exp.Start(context.Background(), componenttest.NewNopHost()) + assert.NoError(t, err) + + logs := constructLogs(map[string]string{}) + err = exp.ConsumeLogs(context.Background(), logs) + assert.ErrorContains(t, err, tt.errorMessage) + }) + } +} + +func TestExportMarkers_NoAPICall(t *testing.T) { + tests := []struct { + name string + config Config + }{ + { + name: "all fields", + config: Config{ + APIKey: "test-apikey", + Markers: []Marker{ + { + Type: "test-type", + MessageKey: "message", + URLKey: "url", + DatasetSlug: "test-dataset", + Rules: Rules{ + LogConditions: []string{ + `body == "foo"`, + }, + }, + }, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + markerServer := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { + assert.Fail(t, "should not call the markers api") + rw.WriteHeader(http.StatusBadRequest) // 400 + })) + defer markerServer.Close() + + config := tt.config + config.APIURL = markerServer.URL + + f := NewFactory() + exp, err := f.CreateLogsExporter(context.Background(), exportertest.NewNopCreateSettings(), &config) + require.NoError(t, err) + + err = exp.Start(context.Background(), componenttest.NewNopHost()) + assert.NoError(t, err) + + logs := constructLogs(map[string]string{}) + err = exp.ConsumeLogs(context.Background(), logs) + assert.NoError(t, err) + }) + } +} diff --git a/exporter/honeycombmarkerexporter/testdata/config.yaml b/exporter/honeycombmarkerexporter/testdata/config.yaml index 3ca6508c9ffb..b3ec158d70b8 100644 --- a/exporter/honeycombmarkerexporter/testdata/config.yaml +++ b/exporter/honeycombmarkerexporter/testdata/config.yaml @@ -1,78 +1,74 @@ -honeycomb: +honeycombmarker: api_key: "test-apikey" api_url: "https://api.testhost.io" + sending_queue: + enabled: true + num_consumers: 10 + queue_size: 1000 + retry_on_failure: + enabled: true + initial_interval: 5000000000 + randomization_factor: 0.5 + multiplier: 1.5 + max_interval: 30000000000 + max_elapsed_time: 300000000000 markers: - type: "fooType" - message_field: "test message" - url_field: "https://api.testhost.io" + message_key: "test message" + url_key: "https://api.testhost.io" + dataset_slug: "__all__" rules: - resource_conditions: - - IsMatch(attributes["test"], ".*") log_conditions: - body == "test" -honeycomb/color_no_type: - api_key: "test-apikey" - api_url: "https://api.testhost.io" - markers: - - color: "green" - message_field: "test message" - url_field: "https://api.testhost.io" - rules: - resource_conditions: - - IsMatch(attributes["test"], ".*") - log_conditions: - - body == "test" - -honeycomb/bad_syntax_log: +honeycombmarker/bad_syntax_log: api_key: "test-apikey" api_url: "https://api.testhost.io" markers: - type: "fooType" - message_field: "test message" - url_field: "https://api.testhost.io" + message_key: "test message" + url_key: "https://api.testhost.io" + dataset_slug: "__all__" rules: log_conditions: - body == "test" - set(attributes["body"], body) -honeycomb/no_conditions: +honeycombmarker/no_conditions: api_key: "test-apikey" api_url: "https://api.testhost.io" markers: - - color: "green" - message_field: "test message" - url_field: "https://api.testhost.io" + - type: "test-apikey" + message_key: "test message" + url_key: "https://api.testhost.io" + dataset_slug: "__all__" rules: -honeycomb/no_api_key: +honeycombmarker/no_api_key: api_key: "" api_url: "https://api.testhost.io" markers: - type: "fooType" - message_field: "test message" - url_field: "https://api.testhost.io" + message_key: "test message" + url_key: "https://api.testhost.io" + dataset_slug: "__all__" rules: - resource_conditions: - - IsMatch(attributes["test"], ".*") log_conditions: - body == "test" -honeycomb/no_api_url: +honeycombmarker/no_markers_supplied: + api_key: "test-apikey" + api_url: "https://api.testhost.io" + markers: + +honeycombmarker/no_dataset_slug: api_key: "test-apikey" - api_url: "" + api_url: "https://api.testhost.io" markers: - type: "fooType" - message_field: "test message" - url_field: "https://api.testhost.io" + message_key: "test message" + url_key: "https://api.testhost.io" rules: - resource_conditions: - - IsMatch(attributes["test"], ".*") log_conditions: - body == "test" -honeycomb/no_markers_supplied: - api_key: "test-apikey" - api_url: "https://api.testhost.io" - markers: -