4 * This file is part of the Monolog package.
6 * (c) Jordi Boggiano <j.boggiano@seld.be>
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
12 namespace Monolog\Handler;
14 use Monolog\Formatter\ElasticaFormatter;
15 use Monolog\Formatter\NormalizerFormatter;
20 use Elastica\Response;
22 class ElasticSearchHandlerTest extends TestCase
30 * @var array Default handler options
32 protected $options = array(
33 'index' => 'my_index',
37 public function setUp()
39 // Elastica lib required
40 if (!class_exists("Elastica\Client")) {
41 $this->markTestSkipped("ruflin/elastica not installed");
44 // base mock Elastica Client object
45 $this->client = $this->getMockBuilder('Elastica\Client')
46 ->setMethods(array('addDocuments'))
47 ->disableOriginalConstructor()
52 * @covers Monolog\Handler\ElasticSearchHandler::write
53 * @covers Monolog\Handler\ElasticSearchHandler::handleBatch
54 * @covers Monolog\Handler\ElasticSearchHandler::bulkSend
55 * @covers Monolog\Handler\ElasticSearchHandler::getDefaultFormatter
57 public function testHandle()
61 'level' => Logger::ERROR,
62 'level_name' => 'ERROR',
64 'context' => array('foo' => 7, 'bar', 'class' => new \stdClass),
65 'datetime' => new \DateTime("@0"),
70 // format expected result
71 $formatter = new ElasticaFormatter($this->options['index'], $this->options['type']);
72 $expected = array($formatter->format($msg));
74 // setup ES client mock
75 $this->client->expects($this->any())
76 ->method('addDocuments')
80 $handler = new ElasticSearchHandler($this->client, $this->options);
81 $handler->handle($msg);
82 $handler->handleBatch(array($msg));
86 * @covers Monolog\Handler\ElasticSearchHandler::setFormatter
88 public function testSetFormatter()
90 $handler = new ElasticSearchHandler($this->client);
91 $formatter = new ElasticaFormatter('index_new', 'type_new');
92 $handler->setFormatter($formatter);
93 $this->assertInstanceOf('Monolog\Formatter\ElasticaFormatter', $handler->getFormatter());
94 $this->assertEquals('index_new', $handler->getFormatter()->getIndex());
95 $this->assertEquals('type_new', $handler->getFormatter()->getType());
99 * @covers Monolog\Handler\ElasticSearchHandler::setFormatter
100 * @expectedException InvalidArgumentException
101 * @expectedExceptionMessage ElasticSearchHandler is only compatible with ElasticaFormatter
103 public function testSetFormatterInvalid()
105 $handler = new ElasticSearchHandler($this->client);
106 $formatter = new NormalizerFormatter();
107 $handler->setFormatter($formatter);
111 * @covers Monolog\Handler\ElasticSearchHandler::__construct
112 * @covers Monolog\Handler\ElasticSearchHandler::getOptions
114 public function testOptions()
117 'index' => $this->options['index'],
118 'type' => $this->options['type'],
119 'ignore_error' => false,
121 $handler = new ElasticSearchHandler($this->client, $this->options);
122 $this->assertEquals($expected, $handler->getOptions());
126 * @covers Monolog\Handler\ElasticSearchHandler::bulkSend
127 * @dataProvider providerTestConnectionErrors
129 public function testConnectionErrors($ignore, $expectedError)
131 $clientOpts = array('host' => '127.0.0.1', 'port' => 1);
132 $client = new Client($clientOpts);
133 $handlerOpts = array('ignore_error' => $ignore);
134 $handler = new ElasticSearchHandler($client, $handlerOpts);
136 if ($expectedError) {
137 $this->setExpectedException($expectedError[0], $expectedError[1]);
138 $handler->handle($this->getRecord());
140 $this->assertFalse($handler->handle($this->getRecord()));
147 public function providerTestConnectionErrors()
150 array(false, array('RuntimeException', 'Error sending messages to Elasticsearch')),
156 * Integration test using localhost Elastic Search server
158 * @covers Monolog\Handler\ElasticSearchHandler::__construct
159 * @covers Monolog\Handler\ElasticSearchHandler::handleBatch
160 * @covers Monolog\Handler\ElasticSearchHandler::bulkSend
161 * @covers Monolog\Handler\ElasticSearchHandler::getDefaultFormatter
163 public function testHandleIntegration()
166 'level' => Logger::ERROR,
167 'level_name' => 'ERROR',
169 'context' => array('foo' => 7, 'bar', 'class' => new \stdClass),
170 'datetime' => new \DateTime("@0"),
176 $expected['datetime'] = $msg['datetime']->format(\DateTime::ISO8601);
177 $expected['context'] = array(
178 'class' => '[object] (stdClass: {})',
183 $client = new Client();
184 $handler = new ElasticSearchHandler($client, $this->options);
186 $handler->handleBatch(array($msg));
187 } catch (\RuntimeException $e) {
188 $this->markTestSkipped("Cannot connect to Elastic Search server on localhost");
191 // check document id from ES server response
192 $documentId = $this->getCreatedDocId($client->getLastResponse());
193 $this->assertNotEmpty($documentId, 'No elastic document id received');
195 // retrieve document source from ES and validate
196 $document = $this->getDocSourceFromElastic(
198 $this->options['index'],
199 $this->options['type'],
202 $this->assertEquals($expected, $document);
204 // remove test index from ES
205 $client->request("/{$this->options['index']}", Request::DELETE);
209 * Return last created document id from ES response
210 * @param Response $response Elastica Response object
211 * @return string|null
213 protected function getCreatedDocId(Response $response)
215 $data = $response->getData();
216 if (!empty($data['items'][0]['create']['_id'])) {
217 return $data['items'][0]['create']['_id'];
222 * Retrieve document by id from Elasticsearch
223 * @param Client $client Elastica client
224 * @param string $index
225 * @param string $type
226 * @param string $documentId
229 protected function getDocSourceFromElastic(Client $client, $index, $type, $documentId)
231 $resp = $client->request("/{$index}/{$type}/{$documentId}", Request::GET);
232 $data = $resp->getData();
233 if (!empty($data['_source'])) {
234 return $data['_source'];