Passed
Pull Request — master (#225)
by Simon
16:05 queued 06:01
created

SolrLogger::getOptions()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 3
ccs 0
cts 0
cp 0
crap 2
rs 10
1
<?php
2
/**
3
 * class SolrLogger|Firesphere\SolrSearch\Helpers\SolrLogger Log errors to the Database
4
 *
5
 * @package Firesphere\SolrSearch\Helpers
6
 * @author Simon `Firesphere` Erkelens; Marco `Sheepy` Hermo
7
 * @copyright Copyright (c) 2018 - now() Firesphere & Sheepy
8
 */
9
10
namespace Firesphere\SolrSearch\Helpers;
11
12
use Countable;
13
use Firesphere\SolrSearch\Models\SolrLog;
14
use Firesphere\SolrSearch\Services\SolrCoreService;
15
use GuzzleHttp\Client;
16
use GuzzleHttp\Exception\GuzzleException;
17
use Psr\Log\LoggerInterface;
18
use SilverStripe\Control\Controller;
19
use SilverStripe\Control\Director;
20
use SilverStripe\Core\Injector\Injector;
21
use SilverStripe\Dev\Debug;
22
use SilverStripe\ORM\DB;
23
use SilverStripe\ORM\ValidationException;
24
25
/**
26
 * Class SolrLogger
27
 *
28
 * Log information from Solr to the CMS for reference
29
 *
30
 * @package Firesphere\SolrSearch\Helpers
31
 */
32
class SolrLogger
33
{
34
    /**
35
     * @var Client Guzzle base client to communicate with Solr
36
     */
37
    protected $client;
38
39
    /**
40
     * @var array
41
     */
42
    protected $options = [];
43
44 41
    /**
45
     * SolrLogger constructor.
46 41
     *
47 41
     * @param null|Countable $handler
48
     */
49 41
    public function __construct($handler = null)
50
    {
51 41
        $config = SolrCoreService::config()->get('config');
52 1
        $hostConfig = array_shift($config['endpoint']);
53
        $guzzleConfig = [
54
            'base_uri' => $hostConfig['host'] . ':' . $hostConfig['port'],
55 41
        ];
56 41
        if ($handler) {
57
            $guzzleConfig['handler'] = $handler;
58
        }
59
60
        if (isset($hostConfig['username']) && isset($hostConfig['password'])) {
61
            $this->options = [
62
                'auth' => [
63
                    $hostConfig['username'],
64
                    $hostConfig['password']
65
                ]
66
            ];
67
        }
68 1
69
70 1
        $this->client = new Client($guzzleConfig);
71 1
    }
72
73 1
    /**
74 1
     * Log the given message and dump it out.
75 1
     * Also boot the Log to get the latest errors from Solr
76 1
     *
77
     * @param string $type
78 1
     * @param string $message
79 1
     * @throws GuzzleException
80
     * @throws ValidationException
81 1
     */
82 1
    public static function logMessage($type, $message): void
83
    {
84 1
        $solrLogger = new self();
85 1
        $solrLogger->saveSolrLog($type);
86 1
        /** @var SolrLog $lastError */
87 1
        $lastError = SolrLog::get()->last();
88
89 1
        $err = ($lastError === null) ? 'Unknown' : $lastError->getLastErrorLine();
90
        $message .= 'Last known error:' . PHP_EOL . $err;
91
        /** @var LoggerInterface $logger */
92
        $logger = Injector::inst()->get(LoggerInterface::class);
93
        $logger->alert($message);
94
        if (Director::is_cli() || Controller::curr()->getRequest()->getVar('unittest')) {
95
            Debug::dump($message);
96
        }
97
    }
98 39
99
    /**
100 39
     * Save the latest Solr errors to the log
101 39
     *
102
     * @param string $type
103
     * @throws GuzzleException
104
     * @throws ValidationException
105
     */
106
    public function saveSolrLog($type = 'Query'): void
107 39
    {
108
        $options = array_merge($this->options, [
109 39
            'query' => [
110
                'since' => 0,
111 35
                'wt'    => 'json',
112 35
            ],
113 35
        ]);
114
        $response = $this->client->get('solr/admin/info/logging', $options);
115 35
116
        $arrayResponse = json_decode($response->getBody(), true);
117 39
118
        foreach ($arrayResponse['history']['docs'] as $error) {
119
            $filter = [
120
                'Timestamp' => $error['time'],
121
                'Index'     => $error['core'] ?? 'x:Unknown',
122
                'Level'     => $error['level'],
123
            ];
124
            $this->findOrCreateLog($type, $filter, $error);
125
        }
126
    }
127 35
128
    /**
129
     * Attempt to find, otherwise create, a log object
130 35
     *
131
     * @param $type
132
     * @param array $filter
133
     * @param $error
134
     * @throws ValidationException
135
     */
136
    private function findOrCreateLog($type, array $filter, $error): void
137 35
    {
138
        // Not covered in tests. It's only here to make sure the connection isn't closed by a child process
139 35
        $conn = DB::is_active();
140 35
        // @codeCoverageIgnoreStart
141
        if (!$conn) {
142 35
            $config = DB::getConfig();
143 35
            DB::connect($config);
144 35
        }
145
        // @codeCoverageIgnoreEnd
146 35
        if (!SolrLog::get()->filter($filter)->exists()) {
147 35
            $logData = [
148
                'Message' => $error['message'],
149
                'Type'    => $type,
150 35
            ];
151
            $log = array_merge($filter, $logData);
152
            SolrLog::create($log)->write();
153
            if (Director::is_cli() || Controller::curr()->getRequest()->getVar('unittest')) {
154
                /** @var LoggerInterface $logger */
155
                $logger = Injector::inst()->get(LoggerInterface::class);
156
                $logger->error($error['message']);
157 2
            }
158
        }
159 2
    }
160
161
    /**
162
     * Return the Guzzle Client
163
     *
164
     * @return Client
165
     */
166
    public function getClient(): Client
167
    {
168 1
        return $this->client;
169
    }
170 1
171
    /**
172 1
     * Set the Guzzle client
173
     *
174
     * @param Client $client
175
     * @return SolrLogger
176
     */
177
    public function setClient(Client $client): self
178
    {
179
        $this->client = $client;
180
181
        return $this;
182
    }
183
184
    /**
185
     * Get the options for Guzzle
186
     *
187
     * @return array
188
     */
189
    public function getOptions(): array
190
    {
191
        return $this->options;
192
    }
193
194
    /**
195
     * Set custom options for Guzzle
196
     *
197
     * @param array $options
198
     */
199
    public function setOptions(array $options): void
200
    {
201
        $this->options = $options;
202
    }
203
}
204