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_function
expects aPost
object, and outputs the author of the post. The base classPost
returns a simple string and outputting a simple string will work just fine. However, the child classBlogPost
which is a sub-type ofPost
instead decided to return anobject
, and is therefore violating the SOLID principles. If aBlogPost
were passed tomy_function
, PHP would not complain, but ultimately fail when executing thestrtoupper
call in its body.