Passed
Push — master ( 2ec749...6a9421 )
by Simon
06:29
created

SolrLogger::findOrCreateLog()   A

Complexity

Conditions 5
Paths 6

Size

Total Lines 19
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 5.0909

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 13
c 1
b 0
f 0
nc 6
nop 3
dl 0
loc 19
ccs 11
cts 13
cp 0.8462
crap 5.0909
rs 9.5222
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
 * @todo implement {@link LoggerInterface}
31
 * @package Firesphere\SolrSearch\Helpers
32
 */
33
class SolrLogger
34
{
35
    /**
36
     * Guzzle base client to communicate with Solr
37
     *
38
     * @var Client
39
     */
40
    protected $client;
41
42
    /**
43
     * SolrLogger constructor.
44
     *
45
     * @param null|Countable $handler
46
     */
47 41
    public function __construct($handler = null)
48
    {
49 41
        $config = SolrCoreService::config()->get('config');
50 41
        $hostConfig = array_shift($config['endpoint']);
51
        $guzzleConfig = [
52 41
            'base_uri' => $hostConfig['host'] . ':' . $hostConfig['port'],
53
        ];
54 41
        if ($handler) {
55 1
            $guzzleConfig['handler'] = $handler;
56
        }
57
58 41
        $this->client = new Client($guzzleConfig);
59 41
    }
60
61
    /**
62
     * Log the given message and dump it out.
63
     * Also boot the Log to get the latest errors from Solr
64
     *
65
     * @param string $type
66
     * @param string $message
67
     * @param string $index
68
     * @throws GuzzleException
69
     * @throws ValidationException
70
     */
71 1
    public static function logMessage($type, $message, $index): void
72
    {
73 1
        $solrLogger = new self();
74 1
        $solrLogger->saveSolrLog($type);
75
        /** @var SolrLog $lastError */
76 1
        $lastError = SolrLog::get()
77 1
            ->filter([
78 1
                'Index' => 'x:' . $index,
79 1
                'Level' => $type,
80
            ])
81 1
            ->sort('Timestamp DESC')
82 1
            ->first();
83
84 1
        $err = ($lastError === null) ? 'Unknown' : $lastError->getLastErrorLine();
85 1
        $message .= 'Last known error:' . PHP_EOL . $err;
86
        /** @var LoggerInterface $logger */
87 1
        $logger = Injector::inst()->get(LoggerInterface::class);
88 1
        $logger->alert($message);
89 1
        if (Director::is_cli() || Controller::curr()->getRequest()->getVar('unittest')) {
90 1
            Debug::dump($message);
91
        }
92 1
    }
93
94
    /**
95
     * Save the latest Solr errors to the log
96
     *
97
     * @param string $type
98
     * @throws GuzzleException
99
     * @throws ValidationException
100
     */
101 39
    public function saveSolrLog($type = 'Query'): void
102
    {
103 39
        $response = $this->client->request('GET', 'solr/admin/info/logging', [
104 39
            'query' => [
105
                'since' => 0,
106
                'wt'    => 'json',
107
            ],
108
        ]);
109
110 39
        $arrayResponse = json_decode($response->getBody(), true);
111
112 39
        foreach ($arrayResponse['history']['docs'] as $error) {
113
            $filter = [
114 39
                'Timestamp' => $error['time'],
115 39
                'Index'     => $error['core'] ?? 'x:Unknown',
116 39
                'Level'     => $error['level'],
117
            ];
118 39
            $this->findOrCreateLog($type, $filter, $error);
119
        }
120 39
    }
121
122
    /**
123
     * Attempt to find, otherwise create, a log object
124
     *
125
     * @param $type
126
     * @param array $filter
127
     * @param $error
128
     * @throws ValidationException
129
     */
130 39
    private function findOrCreateLog($type, array $filter, $error): void
131
    {
132
        // Not covered in tests. It's only here to make sure the connection isn't closed by a child process
133 39
        $conn = DB::is_active();
134 39
        if (!$conn) {
135
            $config = DB::getConfig();
136
            DB::connect($config);
137
        }
138 39
        if (!SolrLog::get()->filter($filter)->exists()) {
139
            $logData = [
140 39
                'Message' => $error['message'],
141 39
                'Type'    => $type,
142
            ];
143 39
            $log = array_merge($filter, $logData);
144 39
            SolrLog::create($log)->write();
145 39
            if (Director::is_cli() || Controller::curr()->getRequest()->getVar('unittest')) {
146
                /** @var LoggerInterface $logger */
147 39
                $logger = Injector::inst()->get(LoggerInterface::class);
148 39
                $logger->error($error['message']);
149
            }
150
        }
151 39
    }
152
153
    /**
154
     * Return the Guzzle Client
155
     *
156
     * @return Client
157
     */
158 2
    public function getClient(): Client
159
    {
160 2
        return $this->client;
161
    }
162
163
    /**
164
     * Set the Guzzle client
165
     *
166
     * @param Client $client
167
     * @return SolrLogger
168
     */
169 1
    public function setClient(Client $client): self
170
    {
171 1
        $this->client = $client;
172
173 1
        return $this;
174
    }
175
}
176