Hi,
is there a way to retrieve the final url that is generated and used to query ES?
I think this can be very useful for unit testing and debugging.
Thanks
Sorta. The debug and trace logs will provide that information, but it may not be the easiest to work with in unit testing environments. For example, I'm using it in this test to determine if HTTP Basic Auth headers were being properly sent (since the client doesn't expose the raw headers being sent over the wire):
That test is using a virtual filesystem to collect the logs, but now that I'm thinking about it, a Monolog handler that emits to stdout or similar may be a better option. Will have to think about that...
Another possibility is adding a lastRequestInfo() method, which returns headers/URI/etc about the last request.
Thanks for the quick reply.
I think both the monolog solution AND the lastRequestInfo() could both be helpful in certain situations.
However the lastRequestInfo() was specifically what i was thinking about, and would really be great i think.
So I'm on the road at the moment, but I'll investigate the options once I get home, and chat with the other client devs to see if there is a way we can standardize it across the clients. Will keep you posted.
Hi, do you already have some news on this?
Maybe there's a possibility to do some mocking using the fact the client is based on Guzzle?
Mocking would be possible, with caveats. There is no way to inject a different Guzzle right now, so you would have to mock out the entire Connection class and inject that instead.
Something like:
public class MockConnection implements Elasticsearch\Connections\ConnectionInterface
{
public function __construct($hostDetails, $connectionParams, LoggerInterface $log, LoggerInterface $trace){}
public function getTransportSchema(){}
public function isAlive(){}
public function markAlive(){}
public function markDead(){}
public function getLastRequestInfo(){}
public function performRequest($method, $uri, $params = null, $body = null){}
}
$params['connectionClass'] = '\MyProject\MockConnection';
$client = new Elasticsearch\Client($params);
The caveat is that each Connection class does a certain amount of processing internal to the class (e.g. pre-pending the connection schema, adding URI parameters, setting curl options, etc). So mocking out a connection class is a good way to unit-test the data that your app is providing to the library...but not a great way to integration test the whole system.
Instead of implementing a complete mock connection, you could extend one of the existing connection classes and just call parent:: on every method, which would be act like a hazy middle-ground between unit and integration testing :)
I went ahead and implemented the "getLastRequest" functionality, since it has several useful side effects (exposing transport, etc).
The data is buried pretty deep inside the library (all the way down at the connection level), so it requires a fairly long/obnoxious API to surface the data.
But for stuff like debugging/unit testing, I think that is ok. This won't be used often in "normal" code.
$client = new Elasticsearch\Client();
$client->index(['index' => 'test', 'type' => 'test', 'id' => 1, 'body' => ['field' => 'value']]);
$last = $client->transport->getLastConnection()->getLastRequestInfo();
print_r($last);
(
[request] => Array
(
[uri] => http://localhost:9200/test/test/1?
[body] => {"field":"value"}
[options] => Array
(
)
[method] => PUT
)
[response] => Array
(
[body] => {"_index":"test","_type":"test","_id":"1","_version":1,"created":true}
[status] => 201
)
)
Wow, super cool, works like a charm!
And indeed the long/obnoxious API is indeed not a problem.
Thanks a lot!
fuck
We are currently using cviebrock/laravel-elasticsearch. Because it presents a facade to the Elasticsearch client, it wasn't immediately obvious how @polyfractal's example should be translated to work within that environment. This thread shows up high in Google, so I'd like to share our solution:
// Get to `transport` through the facade's `connection` static method
$last = Elasticsearch::connection('default')->transport->lastConnection->getLastRequestInfo();
// Just the body (JSON string)
$body = $last['request']['body'];
// If you are inside a controller, this is prettier than dd()
return response( $body )->header('Content-Type', 'application/json');
Equivalent one-liner for debugging:
return response( Elasticsearch::connection('default')->transport->lastConnection->getLastRequestInfo()['request']['body'] )->header('Content-Type', 'application/json');
Hopefully this'll save some folks the dd() calls to figure it out.
Most helpful comment
Mocking would be possible, with caveats. There is no way to inject a different
Guzzleright now, so you would have to mock out the entire Connection class and inject that instead.Something like:
The caveat is that each Connection class does a certain amount of processing internal to the class (e.g. pre-pending the connection schema, adding URI parameters, setting curl options, etc). So mocking out a connection class is a good way to unit-test the data that your app is providing to the library...but not a great way to integration test the whole system.
Instead of implementing a complete mock connection, you could extend one of the existing connection classes and just call
parent::on every method, which would be act like a hazy middle-ground between unit and integration testing :)I went ahead and implemented the "getLastRequest" functionality, since it has several useful side effects (exposing transport, etc).
The data is buried pretty deep inside the library (all the way down at the connection level), so it requires a fairly long/obnoxious API to surface the data.
But for stuff like debugging/unit testing, I think that is ok. This won't be used often in "normal" code.