SolrLogger::setOptions()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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