|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
namespace Atrapalo\Monolog\Handler; |
|
4
|
|
|
|
|
5
|
|
|
use Atrapalo\Monolog\Formatter\ElasticsearchFormatter; |
|
6
|
|
|
use Monolog\Handler\AbstractProcessingHandler; |
|
7
|
|
|
use Monolog\Formatter\FormatterInterface; |
|
8
|
|
|
use InvalidArgumentException; |
|
9
|
|
|
use Elasticsearch\Client; |
|
10
|
|
|
use Monolog\Logger; |
|
11
|
|
|
|
|
12
|
|
|
/** |
|
13
|
|
|
* Elasticsearch handler |
|
14
|
|
|
* |
|
15
|
|
|
* Usage example: |
|
16
|
|
|
* |
|
17
|
|
|
* $client = ClientBuilder::create()->build(); |
|
18
|
|
|
* $options = [ |
|
19
|
|
|
* 'index' => 'elastic_index_name', |
|
20
|
|
|
* 'type' => 'elastic_doc_type', |
|
21
|
|
|
* ]; |
|
22
|
|
|
* $handler = new ElasticsearchHandler($client, $options); |
|
23
|
|
|
* $log = new Logger('application'); |
|
24
|
|
|
* $log->pushHandler($handler); |
|
25
|
|
|
* |
|
26
|
|
|
* @author Christian Soronellas <[email protected]> |
|
27
|
|
|
*/ |
|
28
|
|
|
class ElasticsearchHandler extends AbstractProcessingHandler |
|
29
|
|
|
{ |
|
30
|
|
|
const DEFAULT_INDEX_NAME = 'monolog'; |
|
31
|
|
|
const DEFAULT_TYPE_NAME = 'record'; |
|
32
|
|
|
|
|
33
|
|
|
/** |
|
34
|
|
|
* @var Client |
|
35
|
|
|
*/ |
|
36
|
|
|
protected $client; |
|
37
|
|
|
|
|
38
|
|
|
/** |
|
39
|
|
|
* @var array Handler config options |
|
40
|
|
|
*/ |
|
41
|
|
|
protected $options = []; |
|
42
|
|
|
|
|
43
|
|
|
/** |
|
44
|
|
|
* @param Client $client Elastica Client object |
|
45
|
|
|
* @param array $options Handler configuration |
|
46
|
|
|
* @param integer $level The minimum logging level at which this handler will be triggered |
|
47
|
|
|
* @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not |
|
48
|
|
|
*/ |
|
49
|
|
|
public function __construct(Client $client, array $options = [], $level = Logger::DEBUG, $bubble = true) |
|
50
|
|
|
{ |
|
51
|
|
|
$this->client = $client; |
|
52
|
|
|
$this->options = array_merge(['index' => static::DEFAULT_INDEX_NAME, 'type' => static::DEFAULT_TYPE_NAME], $options); |
|
53
|
|
|
|
|
54
|
|
|
parent::__construct($level, $bubble); |
|
55
|
|
|
} |
|
56
|
|
|
|
|
57
|
|
|
/** |
|
58
|
|
|
* {@inheritDoc} |
|
59
|
|
|
*/ |
|
60
|
|
|
protected function write(array $record) |
|
61
|
|
|
{ |
|
62
|
|
|
$this->client->index($record['formatted']); |
|
63
|
|
|
} |
|
64
|
|
|
|
|
65
|
|
|
/** |
|
66
|
|
|
* {@inheritdoc} |
|
67
|
|
|
*/ |
|
68
|
|
|
public function setFormatter(FormatterInterface $formatter) |
|
69
|
|
|
{ |
|
70
|
|
|
if ($formatter instanceof ElasticsearchFormatter) { |
|
71
|
|
|
return parent::setFormatter($formatter); |
|
72
|
|
|
} |
|
73
|
|
|
|
|
74
|
|
|
throw new InvalidArgumentException('ElasticsearchHandler is only compatible with ElasticsearchFormatter'); |
|
75
|
|
|
} |
|
76
|
|
|
|
|
77
|
|
|
/** |
|
78
|
|
|
* Getter options |
|
79
|
|
|
* @return array |
|
80
|
|
|
*/ |
|
81
|
|
|
public function getOptions() |
|
82
|
|
|
{ |
|
83
|
|
|
return $this->options; |
|
84
|
|
|
} |
|
85
|
|
|
|
|
86
|
|
|
/** |
|
87
|
|
|
* {@inheritDoc} |
|
88
|
|
|
*/ |
|
89
|
|
|
protected function getDefaultFormatter() |
|
90
|
|
|
{ |
|
91
|
|
|
return new ElasticsearchFormatter($this->options['index'], $this->options['type']); |
|
|
|
|
|
|
92
|
|
|
} |
|
93
|
|
|
|
|
94
|
|
|
/** |
|
95
|
|
|
* {@inheritdoc} |
|
96
|
|
|
*/ |
|
97
|
|
|
public function handleBatch(array $records) |
|
98
|
|
|
{ |
|
99
|
|
|
$this->client->bulk( |
|
100
|
|
|
$this->getFormatter()->formatBatch($records) |
|
101
|
|
|
); |
|
102
|
|
|
} |
|
103
|
|
|
} |
|
104
|
|
|
|
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.
Let’s take a look at an example:
Our function
my_functionexpects aPostobject, and outputs the author of the post. The base classPostreturns a simple string and outputting a simple string will work just fine. However, the child classBlogPostwhich is a sub-type ofPostinstead decided to return anobject, and is therefore violating the SOLID principles. If aBlogPostwere passed tomy_function, PHP would not complain, but ultimately fail when executing thestrtouppercall in its body.