Java API: Add mechanism for configuring an input/processor/output with a confg map #8240
Java API: Add mechanism for configuring an input/processor/output with a confg map #8240jordansissel wants to merge 17 commits intomainfrom
Conversation
|
In implementing the other types (boolean, float, etc), I had forgotten that primitives are keywords in Java, so youc an't have a method called 'float'. So I will move everything to be |
08ec826 to
8ef455f
Compare
|
I spiked out an implementation of the The Ruby API |
0c04c0b to
e2be201
Compare
|
@jordansissel and I spoke on this subject on Slack, and came to some conclusions around the requirements:
|
|
I think this is ready for review. It may be best to pair up on this one in order to navigate the functionality. I have written a "sample filter" which demonstrates the use of the ObjectFactory and in a way that I think we will use when writing Logstash plugins (See TranslateFilterPlugin.java). The Translate filter is a bit of a complex plugin because it has model operations (depends on whether 'dictionary' or 'dictionary_path' are set).
Still todo is documentation on how to use it, but I will write that in a future PR with the Plugin API PR. |
e927542 to
4a95760
Compare
…ion map.
The idea behind ConstructingObjectParser was largely lifted from Elasticsearch's class by the same name. The reasons I liked this approach was that it provided a type-safe way to define how user input (a Map, in Logstash's case) is parsed to create an object like an input plugin.
The ConstructingObjectParser roughly implements in Java what `config/mixin.rb` provides for Ruby plugins.
This class allows us to take a Map that comes from the config parser and
build a pipeline plugin (input, filter, output).
Differences from the ruby api:
* Custom object validation is possible. Example, `http_poller` has a map of `urls` which are `name => { configuration }`, and we can achieve type-safe validation of this `urls` thing which benefits us as plugin authors and benefits users through better error reporting.
* Explicit `default` value is not required because Java class fields already allow you to set default values :)
Some rationale on IllegalArgumentException:
* Object construction will throw IllegalArgumentException upon validation failure. This was chosen because IllegalArgumentException is an unchecked exception we can throw while still satisfying the constraints of the java.util.function interfaces (BiFunction, etc)
Also renamed noun-verb things (stringTransform) to verb-noun (transformString)
* note IllegalArgumentException throws * method order slightly rearranged. * javadocs
…ete. This mirrors the current `:deprecated => "details"` and `:obsolete => "details"` in the Ruby side of Logstash. * When a field is obsolete, using it will raise an exception. * When a field is deprecated, using it will log a warning. In tests, I used a trick I learned from Go to make compile-time assertions about return types. This is the reason for `Field x` in various places used in assignment but otherwise not used.
Previously this was in org.logstash.plugin, and it felt not the right package. Big code reorg also: * refactored all the shorthand helpers like declareInteger into default methods of a new ObjectParser interface. * moved object transforms like transformInteger to a new ObjectTransforms class
This exists primarily to practice and demonstrate the capabilities of ConstructingObjectParser
This exists primarily to practice and demonstrate the capabilities of ConstructingObjectParser
…(String) arg[0]` for constructors.
…(String) arg[0]` for constructors.
Renamed ConstructingObjectParser -> ObjectFactory (shorter name, felt more appropriate)
Fields (setters, etc) are now declared using a fluent interface on ObjectFactory and don't need to be done in a `static { ... }` block anymore
Also added back deprecated and obsolete fields.
4a95760 to
a67644f
Compare
…ring, would feel in the new API.
|
Very rough sketch to see how another complicated filter (mutate) would exist in this new world --- Major concept here is that |
|
@jakelandis and I spend lots of time talking about this project. We compare annotations-vs-factories pretty frequently. Annotations some really nice readability properties that factories simply don't have. I'm leaning Jake's suggestion of declaring settings and capabilities with annotations. In fact, the last sketch we drew on this topic looks identical to how Graylog's plugins are configured -- these use a mix of https://github.com/joschi/JadConfig and Java EE Inject. I'll have a go sketching a few more plugins using annotations to see how it feels. |
|
This pull request does not have a backport label. Could you fix it @jordansissel? 🙏
|
|
|
|
This pull request is now in conflicts. Could you fix it @jordansissel? 🙏 |
The idea behind ConstructingObjectParser was largely lifted from
Elasticsearch's class by the same name. The reasons I liked this approach was that it provided a type-safe way to define how user input (a Map, in Logstash's case) is parsed to create an object like an input plugin.
The ConstructingObjectParser roughly implements in Java what
config/mixin.rbprovides for Ruby plugins.This class allows us to take a Map that comes from the config parser and
build a pipeline plugin (input, filter, output).
Differences from the ruby api:
http_pollerhas a map ofurlswhich arename => { configuration }, and we can achieve type-safe validation of thisurlsthing which benefits us as plugin authors and benefits users through better error reporting.defaultvalue is not required because Java class fields already allow you to set default values :)Request for comments:
Note: Exposing the builders to Logstash will require #8227 to be completed and is outside the scope of this PR.
Example invocation:
:required => truein Ruby plugins). If you do not provide all builder args, a NullPointerException is thrown (because the missing values are null?)EnclosedandParameterizedtest runners). Do you like either of these?[1] I chose IllegalArgumentException because it is an unchecked exception we can throw while still satisfying the constraints of the java.util.function interfaces (BiFunction, etc)
Todo:
declareList("hosts", Elasticsearch::setHosts, transformString)obsoleteanddeprecated