RestFilters for ES 5.x

Goal: log all REST requests made to ElasticSearch 5.6.4 cluster.

*Note: in ES 2.x, this can done via RestFilter and RestFilterChain but I am struggle to find the equivalent for ES 5.x .

Implementation 1:

  • I wrote a plugin (RestlogPlugin) which extends Plugin and implements ActionPlugin.
  • My plugin overrides getRestHandlerWrapper() and returns a RestHandler (RestLogHandler).
  • My rest handler overrides:
    protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client)

Question:

  • within the rest handler once I finish my custom bizlogic, how do I create RestChannelConsumer to continue processing the request through tis normal flow? Specifically, what is the 5.x equivalent of Es 2.x RestFilterChain.continueProcessing()?

Implementation 2:

  • I wrote a plugin (RestlogPlugin) which extends Plugin and implements ActionPlugin.
  • My plugin overrides:

getActionFilters() and returns an ActionFilter (RestLogActionFilter).

  • My action filter overrides:

public <Request extends ActionRequest, Response extends ActionResponse> void apply(Task task, String action, Request request, ActionListener listener, ActionFilterChain<Request, Response> chain

Question:

  • within applyTask(), Request is not a RestRequest so how do I get the information http headers of the REST request?

@s1monw . Hi Simon, apologies for pinging you directly. I am a developer here at Netflix and I have hit a blocker that I hope you can provide guidance. I found your handle base on a previous discussion of the same topic (Basic Authentication using RestFilter).

Regards

Hi,

No - I did not able to find a solution for Basic Autentication using RestFilter.

Thanks

-arif

I assume you use this method: https://github.com/elastic/elasticsearch/blob/5.6/core/src/main/java/org/elasticsearch/plugins/ActionPlugin.java#L93

so you have full control over all rest requests. There is no additional logic and I don't know what you mean by RestChannelConsumer to be honest. you just wrap the incoming RestHandler in your impl and execute you biz logic before delegating to the incoming RestHandler#handleRequest method (https://github.com/elastic/elasticsearch/blob/5.6/core/src/main/java/org/elasticsearch/rest/RestHandler.java#L36). The RestChannelConsumer class doesn't exist in 5.x?

@s1monw Hi Simon, thanks for responding. Ok, getting closer, I have the following:

public class RestlogPlugin extends Plugin implements ActionPlugin {

@Override
public UnaryOperator<RestHandler> getRestHandlerWrapper(ThreadContext threadContext) {

         /*
        Simon, I don't see how to get the "incoming RestHandler" that you mentioned?
         */
}

}

you have to return a factory like this:

UnaryOperator<RestHandler> getRestHandlerWrapper(ThreadContext threadContext) {
    return originalHanlder ->
        (RestHandler) (request, channel, client) -> {
            System.out.println("Log Something");
            originalHanlder.handleRequest(request, channel, client);
        };
}

Hi Simon,

It was not obvious to me from javadoc, discussions, or existing 5.x code samples that the original rest handler is provided to an implementation of ActionPlugin. Specifically, RestController.dispatchRequest(...) creates a RestHandler base on the request and gives it to the implementation of ActionPlugin.

Thanks for the help. I can create a PR to update the javadoc for getRestHandlerWrapper(..) if there is value.

Regards

Hi @Vinh_Nguyen - It will be of immense help if you can put together the basics of your implementation here in this forum/topic. For eg: I need to use ES6.x for a Custom Implemengtation in the next week.I guess, the help from @s1monw will also be captured and it need not be repeated across redundant topics.

Something like,
public class CustomRESTPlugin extends Plugin implements ActionPlugin {
@Override
UnaryOperator getRestHandlerWrapper(ThreadContext threadContext) {
return originalHanlder ->
(RestHandler) (request, channel, client) -> {
System.out.println("Log Something");
originalHanlder.handleRequest(request, channel, client);
};
}

//Any other methods/changes?
}

public class CustomRESTHandler extends BaseRestHandler {
//constructor - please add
@Override
public void handleRequest(RestRequest request, RestChannel channel, NodeClient client) throws
IOException {
System.out.println("CustomRESTHandler is running");
//custom code - we have the 'request'
}
//any other methods ?

}

@arimoham - Did you find any other implementation ?

please do and ping me on the issue/PR. my handle on github is the same as here

@smoitra A couple of things concerning your object diagram.

1.If your plugin contains logic to handle the request, you don't need the CustomRESTHandler class.
2.If you choose to use CustomRESTHandler:

  • When your plugin instantiates your custom handler, you need to pass it the original handler. Original handler should be use within handleRequest(...) to pass the request along its normal processing.

@Vinh_Nguyen - I need to have some logic on the header(custom security) of the request - hence wanted to have the CustomRESTHandler class.
Can you can please put down the structure/object diagram/psuedo code in that case?

Thanks!

@smoitra here it is:

public class YourPlugin extends Plugin implements ActionPlugin {
@Override
public UnaryOperator getRestHandlerWrapper(ThreadContext threadContext) {
UnaryOperator u = (originalRestHandler) -> {
final YourRestLogHandler yourResttLogHandler = new YourRestLogHandler(originalRestHandler);
return yourResttLogHandler;
}
}
}

public class YourRestLogHandler implements RestHandler {
public YourRestLogHandler(RestHandler originalRestHandler) {
this.originalRestHandler = originalRestHandler;
}

@Override
public void handleRequest(RestRequest request, RestChannel channel, NodeClient client) throws
Exception {
try {
//your customer bizlogic
} catch (Exception e) {
} finally {
this.originalRestHandler.handleRequest(request, channel, client);
}

}
}

Thanks @Vinh_Nguyen