Skip to content

Validate the action before sending the bulk request to ES. #1080

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

mashhurs
Copy link
Contributor

@mashhurs mashhurs commented Aug 8, 2022

What this PR does?

Plugin receives 400 Validation Failed: 1: no requests added exception when requesting unsupported bulk action.
This PR introduces a validation check on action before sending bulk request to ES.

Closes #1079

Test

Manual testing

  • Used configuration to read from JSON file and send to ES. File contains an action field which is not in [index, create, update, delete]
   input {
      file {
          path => "/path/to/files/*.json"
          start_position => "beginning"
          codec => "json"
      }
   }
   output {
     elasticsearch {
       ....
       action => "%{[@metadata][action]}"
     }
   }
  • Result
[2022-09-09T11:59:44,810][WARN ][logstash.outputs.elasticsearch][main][ca10f590b6ab3366bc38f754293adbd2499c9d97aedd7933d11542cd26cd056d] Could not index event to Elasticsearch because its action is not supported. Action: ["partialupdate", {:_id=>"5412e1fe-7822-4440-86b6-5b508ab99229", :_index=>"logstash-test-output", :routing=>nil}, {"eventData"=>....}]

Unit testing

  • Run the unit test
    rspec spec/unit/outputs/elasticsearch_spec.rb

Logs

[2022-09-21T09:55:33,170][WARN ][logstash.outputs.elasticsearch][main][02e543d9daaf1e2af9190a6aef2cb91aa012fabaf7756093f487d85b2b9224de] Badly formatted index, after interpolation still contains placeholder: [%{[index_name]}], {"action"=>"index", "host"=>{"name"=>"dhcp-128-189-70-158"}, "name"=>"TEST", "source"=>"template", "@timestamp"=>2022-09-21T16:55:33.045630Z, "type"=>"TEST", "version"=>1, "@version"=>"1", "log"=>{"file"=>{"path"=>"/Users/mashhur/Dev/elastic/SDH/test2.json"}}, "event"=>{"original"=>"{\"name\":\"TEST\",\"type\":\"TEST\",\"action\":\"index\",\"source\":\"template\",\"version\":1}"}}

[2022-09-21T09:55:33,171][WARN ][logstash.outputs.elasticsearch][main][02e543d9daaf1e2af9190a6aef2cb91aa012fabaf7756093f487d85b2b9224de] Elasticsearch doesn't support [partialupdate] action, {"action"=>"partialupdate", "host"=>{"name"=>"dhcp-128-189-70-158"}, "source"=>"template", "type"=>"TEST", "index_name"=>"logstash-output", "@version"=>"1", "log"=>{"file"=>{"path"=>"/Users/mashhur/Dev/elastic/SDH/test2.json"}}, "event"=>{"original"=>"{\"name\":\"TEST\",\"type\":\"TEST\",\"action\":\"partialupdate\",\"source\":\"template\",\"version\":1,\"index_name\":\"logstash-output\"}"}, "name"=>"TEST", "@timestamp"=>2022-09-21T16:55:33.052311Z, "version"=>1}


[2022-09-21T09:55:33,171][WARN ][logstash.outputs.elasticsearch][main][02e543d9daaf1e2af9190a6aef2cb91aa012fabaf7756093f487d85b2b9224de] Can't map the event, needs to configure the pipeline settings according to the input. The event sent to DLQ: Badly formatted index, after interpolation still contains placeholder: [%{[index_name]}], {"action"=>"index", "host"=>{"name"=>"dhcp-128-189-70-158."}, "name"=>"TEST", "source"=>"template", "@timestamp"=>2022-09-21T16:55:33.045630Z, "type"=>"TEST", "version"=>1, "@version"=>"1", "log"=>{"file"=>{"path"=>"/Users/mashhur/Dev/elastic/SDH/test2.json"}}, "event"=>{"original"=>"{\"name\":\"TEST\",\"type\":\"TEST\",\"action\":\"index\",\"source\":\"template\",\"version\":1}"}}


[2022-09-21T09:55:33,171][WARN ][logstash.outputs.elasticsearch][main][02e543d9daaf1e2af9190a6aef2cb91aa012fabaf7756093f487d85b2b9224de] Can't map the event, needs to configure the pipeline settings according to the input. The event sent to DLQ: Elasticsearch doesn't support [partialupdate] action, {"action"=>"partialupdate", "host"=>{"name"=>"dhcp-128-189-70-158"}, "source"=>"template", "type"=>"TEST", "index_name"=>"logstash-output", "@version"=>"1", "log"=>{"file"=>{"path"=>"/Users/mashhur/Dev/elastic/SDH/test2.json"}}, "event"=>{"original"=>"{\"name\":\"TEST\",\"type\":\"TEST\",\"action\":\"partialupdate\",\"source\":\"template\",\"version\":1,\"index_name\":\"logstash-output\"}"}, "name"=>"TEST", "@timestamp"=>2022-09-21T16:55:33.052311Z, "version"=>1}

@mashhurs mashhurs added the bug label Aug 8, 2022
@mashhurs mashhurs requested a review from yaauie August 8, 2022 21:53
@mashhurs mashhurs self-assigned this Aug 8, 2022
@mashhurs mashhurs marked this pull request as ready for review August 8, 2022 21:56
@mashhurs mashhurs linked an issue Aug 8, 2022 that may be closed by this pull request
Copy link
Contributor

@yaauie yaauie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have an ordering problem, since the per-event responses must be emitted in the same order as the actions we received.

@mashhurs mashhurs requested a review from yaauie August 13, 2022 13:23
@mashhurs mashhurs requested a review from yaauie September 6, 2022 22:14
Copy link
Contributor

@andsel andsel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry to chime in, I saw this while working on #1084, and had similar problem in pre-validate a condition (in my case the sprintf of the index is fully resolved) and in case send to DLQ.

@mashhurs mashhurs requested a review from andsel September 9, 2022 23:29
@mashhurs mashhurs force-pushed the validate-action-when-sending-bulk-request-to-es branch from 5c57e56 to ad889cd Compare September 21, 2022 06:07
@mashhurs mashhurs requested a review from andsel September 21, 2022 06:19
@mashhurs mashhurs marked this pull request as ready for review September 21, 2022 06:19
Copy link
Contributor

@andsel andsel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes you proposed seems good to me.
Left a couple of notes on test's expectations, if should be re-enabled plus a concern about the eventuality to log something in case a mapping error happens.

it "rejects unsupported actions" do
event_result = subject.send(:safe_interpolation_map_events, events)
expect(event_result.successful_events.size).to be == 2
# expect(logger_stub).to have_received(:warn).with(a_string_including "Could not index event to Elasticsearch because its action is not supported.")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be re-enabled to check also the failed ones?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, added in new commits.

@logger.error("Can't map some events, needs to be handled by DLQ #{events_mapped.failed_events}")
send_failed_resolutions_to_dlq(events_mapped.failed_events)
unless events_mapped.event_mapping_errors.empty?
handle_event_mapping_errors(events_mapped.event_mapping_errors)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If dlq is enabled then no log lines are logged. I think that any mapping error, that route events to DLQ, should be clearly highlighted into the logs, so a warn log line should be present to eventually understand what's happening.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To avoid flooding I would like to log a single INFO for the batch if the DLQ is enabled (including the quantity of events from the batch), or to defer to the per-event WARN if there is no DLQ and we need to drop the event. Users who have the DLQ enabled should already be in a position to monitor its growth.

@logger.error("Can't map some events, needs to be handled by DLQ #{events_mapped.failed_events}")
send_failed_resolutions_to_dlq(events_mapped.failed_events)
unless events_mapped.event_mapping_errors.empty?
handle_event_mapping_errors(events_mapped.event_mapping_errors)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To avoid flooding I would like to log a single INFO for the batch if the DLQ is enabled (including the quantity of events from the batch), or to defer to the per-event WARN if there is no DLQ and we need to drop the event. Users who have the DLQ enabled should already be in a position to monitor its growth.

Comment on lines 379 to 380
detail_message = message + ", " + action.to_s
handle_dlq_status(action.event, :warn, detail_message)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer a rephrase of this, so that event_mapping_errors was either an array of event/message tuples or an array of objects that have event/message properties, since action in this code is somewhat ambiguous and can mean either a String action or an action-tuple as prepared for a bulk request.

When we are building this array, we already have access to the event and an object that has the message (the exception), and when we are raising the exception we have access to the event. We could either create a specialized struct, or can embed the event into the exception that we are already handling.

Additionally, we have everything we need to produce our detail_message when populating the array (or even when throwing the relevant exception that leads to an entry in the array), so I would rather pull that up.

mashhurs and others added 2 commits September 21, 2022 13:55
Set to bugfix version, accept detailed overview about the change.

Co-authored-by: Ry Biesemeyer <yaauie@users.noreply.github.com>
… Event is considered. Giving a noti to users when DQL enabled and failed events sent to it.
@mashhurs mashhurs requested review from yaauie and andsel September 21, 2022 21:37
]}
it "rejects unsupported actions" do
event_result = subject.send(:safe_interpolation_map_events, events)
expect(event_result.successful_events.size).to be == 3
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@yaauie , I really liked the idea of having rspec-collection_matchers when unit tests check agains collections sizes. I understood more about use cases after taking a look at this thread.
However, in order to use collection_matchers, we need to onboard it with LS-core (add gem "rspec-collection_matchers", :group => :development in Gemfile.template file).

Let me know your thoughts if I can add it to plugin level dependency.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could go either way -- the failure scenario reads "clear enough" for these specs.

The normal way of adding the dependency would be to declare a development dependency in this project's gemspec, not in Logstash core.

Copy link
Contributor

@yaauie yaauie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left one follow-up on the collections expectations. Feel free to either chase it down or merge as-is.

Copy link
Contributor

@yaauie yaauie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Bulk request without checking supported action causing ES 400.
4 participants