Skip to content

Commit 4a5f7ae

Browse files
committed
Add datacollector for debug
1 parent 796ae08 commit 4a5f7ae

File tree

5 files changed

+360
-0
lines changed

5 files changed

+360
-0
lines changed
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Meilisearch\Bundle\DataCollector;
6+
7+
use Meilisearch\Bundle\Debug\TraceableMeilisearchService;
8+
use Symfony\Bundle\FrameworkBundle\DataCollector\AbstractDataCollector;
9+
use Symfony\Component\HttpFoundation\Request;
10+
use Symfony\Component\HttpFoundation\Response;
11+
12+
/**
13+
* @author Antoine Makdessi <[email protected]>
14+
*/
15+
final class MeilisearchDataCollector extends AbstractDataCollector
16+
{
17+
private TraceableMeilisearchService $meilisearchService;
18+
19+
public function __construct(TraceableMeilisearchService $meilisearchService)
20+
{
21+
$this->meilisearchService = $meilisearchService;
22+
}
23+
public function collect(Request $request, Response $response, \Throwable $exception = null): void
24+
{
25+
$data = $this->meilisearchService->getData();
26+
27+
$this->data[$this->getName()] = !empty($data) ? $this->cloneVar($data) : null;
28+
}
29+
30+
public function getName(): string
31+
{
32+
return 'meilisearch';
33+
}
34+
35+
/** @internal */
36+
public function getMeilisearch(): mixed
37+
{
38+
return $this->data[$this->getName()] ?? null;
39+
}
40+
}
Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Meilisearch\Bundle\Debug;
6+
7+
use Doctrine\Persistence\ObjectManager;
8+
use Meilisearch\Bundle\Collection;
9+
use Meilisearch\Bundle\SearchService;
10+
use Symfony\Component\Stopwatch\Stopwatch;
11+
12+
/**
13+
* @author Antoine Makdessi <[email protected]>
14+
*/
15+
final class TraceableMeilisearchService implements SearchService
16+
{
17+
private SearchService $searchService;
18+
private Stopwatch $stopwatch;
19+
private array $data = [];
20+
21+
public function __construct(SearchService $searchService, Stopwatch $stopwatch)
22+
{
23+
$this->searchService = $searchService;
24+
$this->stopwatch = $stopwatch;
25+
}
26+
27+
public function index(ObjectManager $objectManager, $searchable): array
28+
{
29+
$this->stopwatch->start(__METHOD__);
30+
31+
$index = $this->searchService->index(...\func_get_args());
32+
33+
$event = $this->stopwatch->stop(__METHOD__);
34+
35+
$this->data[__FUNCTION__] = [
36+
'_params' => [
37+
'$searchable' => $searchable,
38+
],
39+
'_results' => $index,
40+
'_duration' => $event->getDuration(),
41+
'_memory' => $event->getMemory(),
42+
];
43+
44+
return $index;
45+
}
46+
47+
public function remove(ObjectManager $objectManager, $searchable): array
48+
{
49+
$this->stopwatch->start(__METHOD__);
50+
51+
$remove = $this->searchService->remove(...\func_get_args());
52+
53+
$event = $this->stopwatch->stop(__METHOD__);
54+
55+
$this->data[__FUNCTION__] = [
56+
'_params' => [
57+
'$searchable' => $searchable,
58+
],
59+
'_results' => $remove,
60+
'_duration' => $event->getDuration(),
61+
'_memory' => $event->getMemory(),
62+
];
63+
64+
return $remove;
65+
}
66+
67+
public function clear(string $className): array
68+
{
69+
$this->stopwatch->start(__METHOD__);
70+
71+
$clear = $this->searchService->clear(...\func_get_args());
72+
73+
$event = $this->stopwatch->stop(__METHOD__);
74+
75+
$this->data[__FUNCTION__] = [
76+
'_params' => [
77+
'$className' => $className,
78+
],
79+
'_results' => $clear,
80+
'_duration' => $event->getDuration(),
81+
'_memory' => $event->getMemory(),
82+
];
83+
84+
return $clear;
85+
}
86+
87+
public function deleteByIndexName(string $indexName): ?array
88+
{
89+
$this->stopwatch->start(__METHOD__);
90+
91+
$deleteByIndexName = $this->searchService->deleteByIndexName(...\func_get_args());
92+
93+
$event = $this->stopwatch->stop(__METHOD__);
94+
95+
$this->data[__FUNCTION__] = [
96+
'_params' => [
97+
'$indexName' => $indexName,
98+
],
99+
'_results' => $deleteByIndexName,
100+
'_duration' => $event->getDuration(),
101+
'_memory' => $event->getMemory(),
102+
];
103+
104+
return $deleteByIndexName;
105+
}
106+
107+
public function delete(string $className): ?array
108+
{
109+
$this->stopwatch->start(__METHOD__);
110+
111+
$delete = $this->searchService->delete(...\func_get_args());
112+
113+
$event = $this->stopwatch->stop(__METHOD__);
114+
115+
$this->data[__FUNCTION__] = [
116+
'_params' => [
117+
'$className' => $className,
118+
],
119+
'_results' => $delete,
120+
'_duration' => $event->getDuration(),
121+
'_memory' => $event->getMemory(),
122+
];
123+
124+
return $delete;
125+
}
126+
127+
public function search(ObjectManager $objectManager, string $className, string $query = '', array $searchParams = []): array
128+
{
129+
$this->stopwatch->start(__METHOD__);
130+
131+
$search = $this->searchService->search(...\func_get_args());
132+
133+
$event = $this->stopwatch->stop(__METHOD__);
134+
135+
$this->data[__FUNCTION__] = [
136+
'_params' => [
137+
'$className' => $className,
138+
'$query' => $query,
139+
'$searchParams' => $searchParams,
140+
],
141+
'_results' => $search,
142+
'_duration' => $event->getDuration(),
143+
'_memory' => $event->getMemory(),
144+
];
145+
146+
return $search;
147+
}
148+
149+
public function rawSearch(string $className, string $query = '', array $searchParams = []): array
150+
{
151+
$this->stopwatch->start(__METHOD__);
152+
153+
$rawSearch = $this->searchService->rawSearch(...\func_get_args());
154+
155+
$event = $this->stopwatch->stop(__METHOD__);
156+
157+
$this->data[__FUNCTION__] = [
158+
'_params' => [
159+
'$className' => $className,
160+
'$query' => $query,
161+
'$searchParams' => $searchParams,
162+
],
163+
'_results' => $rawSearch,
164+
'_duration' => $event->getDuration(),
165+
'_memory' => $event->getMemory(),
166+
];
167+
168+
return $rawSearch;
169+
}
170+
171+
public function count(string $className, string $query = '', array $searchParams = []): int
172+
{
173+
$this->stopwatch->start(__METHOD__);
174+
175+
$count = $this->searchService->count(...\func_get_args());
176+
177+
$event = $this->stopwatch->stop(__METHOD__);
178+
179+
$this->data[__FUNCTION__] = [
180+
'_params' => [
181+
'$className' => $className,
182+
'$query' => $query,
183+
'$searchParams' => $searchParams,
184+
],
185+
'_results' => $count,
186+
'_duration' => $event->getDuration(),
187+
'_memory' => $event->getMemory(),
188+
];
189+
190+
return $count;
191+
}
192+
193+
public function isSearchable($className): bool
194+
{
195+
return $this->searchService->isSearchable($className);
196+
}
197+
198+
public function getSearchable(): array
199+
{
200+
return $this->searchService->getSearchable();
201+
}
202+
203+
public function getConfiguration(): Collection
204+
{
205+
return $this->searchService->getConfiguration();
206+
}
207+
208+
public function searchableAs(string $className): string
209+
{
210+
return $this->searchService->searchableAs($className);
211+
}
212+
213+
/** @internal */
214+
public function getData(): array
215+
{
216+
return $this->data;
217+
}
218+
}

src/DependencyInjection/MeilisearchExtension.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@
44

55
namespace Meilisearch\Bundle\DependencyInjection;
66

7+
use Meilisearch\Bundle\DataCollector\MeilisearchDataCollector;
8+
use Meilisearch\Bundle\Debug\TraceableMeilisearchService;
79
use Meilisearch\Bundle\Engine;
810
use Meilisearch\Bundle\MeilisearchBundle;
11+
use Meilisearch\Bundle\SearchService;
912
use Meilisearch\Bundle\Services\MeilisearchService;
1013
use Symfony\Component\Config\FileLocator;
1114
use Symfony\Component\DependencyInjection\ContainerBuilder;
@@ -59,6 +62,20 @@ public function load(array $configs, ContainerBuilder $container): void
5962

6063
$container->setDefinition('meilisearch.service', $searchDefinition->setPublic(true));
6164
$container->setAlias('search.service', 'meilisearch.service')->setPublic(true);
65+
66+
if ($container->getParameter('kernel.debug')) {
67+
$container->register('debug.meilisearch.service', TraceableMeilisearchService::class)
68+
->setDecoratedService(SearchService::class)
69+
->addArgument(new Reference('debug.meilisearch.service.inner'))
70+
->addArgument(new Reference('debug.stopwatch'))
71+
;
72+
$container->register('data_collector.meilisearch', MeilisearchDataCollector::class)
73+
->addArgument(new Reference('debug.meilisearch.service'))
74+
->addTag('data_collector', [
75+
'id' => 'meilisearch',
76+
'template' => '@Meilisearch/DataCollector/meilisearch.html.twig',
77+
]);
78+
}
6279
}
6380

6481
/**
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
{% extends '@WebProfiler/Profiler/layout.html.twig' %}
2+
3+
{% block toolbar %}
4+
{% set _data = collector.meilisearch %}
5+
{% if _data is not null %}
6+
{% set icon %}
7+
{{ include('@Meilisearch/DataCollector/meilisearch.svg') }}
8+
<span class="sf-toolbar-value">Meilisearch</span>
9+
{% endset %}
10+
{{ include('@WebProfiler/Profiler/toolbar_item.html.twig', { link: 'meilisearch' }) }}
11+
{% endif %}
12+
{% endblock %}
13+
14+
{% block menu %}
15+
{% set _data = collector.meilisearch %}
16+
<span class="label{{ _data is null ? ' disabled' }}">
17+
<span class="icon">
18+
{{ include('@Meilisearch/DataCollector/meilisearch.svg') }}
19+
</span>
20+
<strong>Meilisearch</strong>
21+
</span>
22+
{% endblock %}
23+
24+
{% block panel %}
25+
<h2>Meilisearch</h2>
26+
{% set _data = collector.meilisearch %}
27+
{% if _data is not null %}
28+
<div class="sf-tabs">
29+
{% for _name, _d in _data %}
30+
<div class="tab">
31+
<h3 class="tab-title">{{ _name|title }}</h3>
32+
<div class="tab-content">
33+
<div class="metrics">
34+
<div class="metric">
35+
<span class="value">{{ '%.0f'|format(_d._duration) }} <span class="unit">ms</span></span>
36+
<span class="label">Total execution time</span>
37+
</div>
38+
<div class="metric">
39+
<span class="value">{{ '%.2f'|format(_d._memory / 1024 / 1024) }} <span class="unit">MB</span></span>
40+
<span class="label">Peak memory usage</span>
41+
</div>
42+
</div>
43+
<h3>Params</h3>
44+
<table>
45+
{% for _pk, _pv in _d._params %}
46+
<tr>
47+
<td>{{ _pk }}</td>
48+
<td>{{ profiler_dump(_pv) }}</td>
49+
</tr>
50+
{% endfor %}
51+
</table>
52+
<h3>Result</h3>
53+
<table>
54+
{% for _rk, _rv in _d._results %}
55+
<tr>
56+
<td>{{ _rk }}</td>
57+
<td>{{ profiler_dump(_rv) }}</td>
58+
</tr>
59+
{% endfor %}
60+
</table>
61+
</div>
62+
</div>
63+
{% endfor %}
64+
</div>
65+
<p class="help">
66+
You can also see the HTTP Client & Performance{% if constant('Symfony\\Component\\HttpKernel\\Kernel::VERSION') >= '6.1.0' %} & Serializer{% endif %} tabs to learn more.
67+
</p>
68+
{% else %}
69+
<div class="empty">
70+
<p>No Meilisearch data collected.</p>
71+
</div>
72+
{% endif %}
73+
<p>
74+
<a href="https://www.meilisearch.com/docs">Read Meilisearch documentation</a>
75+
<br />
76+
<a href="https://github.com/meilisearch/meilisearch-php">Read Meilisearch PHP SDK documentation</a>
77+
<br />
78+
<a href="https://github.com/meilisearch/meilisearch-symfony">Read Meilisearch Symfony bundle documentation</a>
79+
</p>
80+
{% endblock %}
Lines changed: 5 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)