Skip to content

Commit

Permalink
Merge branch '6.x' into refactor/flashbag-service-deprecated
Browse files Browse the repository at this point in the history
  • Loading branch information
theus77 authored Dec 21, 2023
2 parents ae7644c + 13c383a commit 335290e
Show file tree
Hide file tree
Showing 19 changed files with 2,040 additions and 2,094 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public function searchOne(null|string|array $type, array $body, ?string $indexRe
/**
* @param mixed[] $headers
*/
public function httpException(int $statusCode, ?string $message = '', array $headers = [], ?int $code = 0): never
public function httpException(int $statusCode, string $message = '', array $headers = [], int $code = 0): never
{
throw new HttpException($statusCode, $message, null, $headers, $code);
}
Expand Down
12 changes: 6 additions & 6 deletions EMS/client-helper-bundle/src/Helper/Search/Search.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Elastica\Query\BoolQuery;
use EMS\ClientHelperBundle\Helper\Elasticsearch\ClientRequest;
use EMS\ClientHelperBundle\Helper\Request\RequestHelper;
use EMS\CommonBundle\Elasticsearch\QueryStringEscaper;
use EMS\CommonBundle\Elasticsearch\Response\Response;
use EMS\Helpers\Standard\Json;
use Symfony\Component\HttpFoundation\Request;
Expand Down Expand Up @@ -166,12 +167,11 @@ public function getQuerySearch(string $queryString): ?BoolQuery
return null;
}

$jsonQueryString = Json::encode($this->querySearch);
$jsonQuerySearch = Json::encode($this->querySearch);
$jsonQuerySearch = u($jsonQuerySearch)->replace('%query%', Json::escape($queryString))->toString();
$jsonQuerySearch = RequestHelper::replace($this->request, $jsonQuerySearch);

$queryString = u($jsonQueryString)->replace('%query%', $queryString)->toString();
$queryString = RequestHelper::replace($this->request, $queryString);

$querySearch = Json::decode($queryString);
$querySearch = Json::decode($jsonQuerySearch);

if (!isset($querySearch['bool'])) {
throw new \RuntimeException('Query search should be a bool query');
Expand Down Expand Up @@ -200,7 +200,7 @@ public function hasQueryString(): bool

public function getQueryString(): ?string
{
return $this->queryString;
return $this->queryString ? QueryStringEscaper::escape($this->queryString) : null;
}

/**
Expand Down
22 changes: 14 additions & 8 deletions EMS/common-bundle/src/DataCollector/ElasticaDataCollector.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@

class ElasticaDataCollector extends DataCollector
{
public function __construct(private readonly ElasticaLogger $logger, private readonly ElasticaService $elasticaService)
{
public function __construct(
private readonly ElasticaLogger $logger,
private readonly ElasticaService $elasticaService
) {
}

public function collect(Request $request, Response $response, ?\Throwable $exception = null): void
Expand All @@ -34,18 +36,15 @@ public function getVersion(): string
return $this->data['version'];
}

/**
* @return mixed
*/
public function getQueryCount()
public function getQueryCount(): int
{
return $this->data['nb_queries'];
}

/**
* @return mixed
* @return array<mixed>
*/
public function getQueries()
public function getQueries(): array
{
return $this->data['queries'];
}
Expand All @@ -60,6 +59,13 @@ public function getTime(): int
return $time;
}

public function countErrors(): int
{
$queries = $this->data['queries'] ?? [];

return \count(\array_filter($queries, static fn (array $q) => isset($q['exception'])));
}

public function getExecutionTime(): float
{
$time = 0;
Expand Down
46 changes: 12 additions & 34 deletions EMS/common-bundle/src/Elasticsearch/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
namespace EMS\CommonBundle\Elasticsearch;

use Elastica\Client as BaseClient;
use Elastica\Connection;
use Elastica\Exception\ClientException;
use Elastica\Exception\ResponseException;
use Elastica\Request;
use Elastica\Response;
use Symfony\Component\Stopwatch\Stopwatch;
Expand All @@ -24,11 +24,14 @@ class Client extends BaseClient
*/
public function request($path, $method = Request::GET, $data = [], array $query = [], $contentType = Request::DEFAULT_CONTENT_TYPE): Response
{
if (null !== $this->stopwatch) {
$this->stopwatch->start('es_request', 'fos_elastica');
}
$this->stopwatch?->start('es_request', 'fos_elastica');

$response = parent::request($path, $method, $data, $query, $contentType);
try {
$response = parent::request($path, $method, $data, $query, $contentType);
} catch (ResponseException $e) {
$this->getLogger()?->logResponse($e->getResponse(), $e->getRequest(), $e);
throw $e;
}
$responseData = $response->getData();

$transportInfo = $response->getTransferInfo();
Expand All @@ -44,11 +47,8 @@ public function request($path, $method = Request::GET, $data = [], array $query
throw new ClientException($message);
}

$this->logQuery($response, $connection, $path, $method, $query, $data);

if ($this->stopwatch) {
$this->stopwatch->stop('es_request');
}
$this->getLogger()?->logResponse($response, $lastRequest);
$this->stopwatch?->stop('es_request');

return $response;
}
Expand All @@ -58,30 +58,8 @@ public function setStopwatch(?Stopwatch $stopwatch = null): void
$this->stopwatch = $stopwatch;
}

/**
* @param array<mixed>|string $data
* @param array<mixed> $query
*/
private function logQuery(Response $elasticaResponse, Connection $connection, string $path, string $method, array $query, array|string $data): void
public function getLogger(): ?ElasticaLogger
{
if (!$this->_logger instanceof ElasticaLogger || !$this->_logger->isEnabled()) {
return;
}

$connectionArray = [
'host' => $connection->getHost(),
'port' => $connection->getPort(),
'transport' => $connection->getTransport(),
'headers' => $connection->hasConfig('headers') ? $connection->getConfig('headers') : [],
];

$responseData = $elasticaResponse->getData();

$queryTime = $elasticaResponse->getQueryTime();
$engineMS = $responseData['took'] ?? 0;

$itemCount = $responseData['hits']['total']['value'] ?? $responseData['hits']['total'] ?? 0;

$this->_logger->logQuery($path, $method, $data, $queryTime, $connectionArray, $query, $engineMS, $itemCount);
return $this->_logger instanceof ElasticaLogger && $this->_logger->isEnabled() ? $this->_logger : null;
}
}
90 changes: 48 additions & 42 deletions EMS/common-bundle/src/Elasticsearch/ElasticaLogger.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

namespace EMS\CommonBundle\Elasticsearch;

use Elastica\Exception\ResponseException;
use Elastica\Request;
use Elastica\Response;
use EMS\CommonBundle\Contracts\Elasticsearch\QueryLoggerInterface;
use EMS\Helpers\Standard\Json;
use Psr\Log\AbstractLogger;
Expand All @@ -15,8 +18,10 @@ class ElasticaLogger extends AbstractLogger implements QueryLoggerInterface
private array $queries = [];
private bool $enabled = true;

public function __construct(private readonly ?LoggerInterface $logger = null, private readonly bool $debug = false)
{
public function __construct(
private readonly ?LoggerInterface $logger = null,
private readonly bool $debug = false
) {
}

public function isEnabled(): bool
Expand All @@ -34,70 +39,71 @@ public function enable(): void
$this->enabled = true;
}

public function getNbQueries(): int
{
return \count($this->queries);
}

/**
* @param array<mixed>|string $data Arguments
* @param array<mixed> $connection Host, port, transport, and headers of the query
* @param array<mixed> $query Arguments
* @return array<mixed>
*/
public function logQuery(string $path, string $method, array|string $data, float $queryTime, array $connection = [], array $query = [], int $engineTime = 0, int $itemCount = 0): void
public function getQueries(): array
{
return $this->queries;
}

/**
* @param array<mixed> $context
*/
public function log($level, $message, array $context = []): void
{
if (null !== $this->logger && $this->isEnabled()) {
$this->logger->log($level, $message, $context);
}
}

public function logResponse(Response $response, Request $request, ?ResponseException $responseException = null): void
{
$responseData = $response->getData();
$queryTime = $response->getQueryTime();
$connection = $request->getConnection();
$data = $request->getData();

$executionMS = $queryTime * 1000;

if ($this->debug) {
if (\is_string($data)) {
$jsonStrings = \explode("\n", $data);
$data = [];
foreach ($jsonStrings as $json) {
if ('' != $json) {
$data[] = Json::decode($json);
}
}
$data = \array_filter(\array_map(static fn ($v) => Json::isJson($v) ? Json::decode($v) : null, $jsonStrings));
} else {
$data = [$data];
}

$this->queries[] = [
'path' => $path,
'method' => $method,
'path' => $request->getPath(),
'method' => $request->getMethod(),
'data' => $data,
'executionMS' => $executionMS,
'engineMS' => $engineTime,
'connection' => $connection,
'queryString' => $query,
'itemCount' => $itemCount,
'engineMS' => $responseData['took'] ?? 0,
'exception' => $responseException,
'connection' => [
'host' => $connection->getHost(),
'port' => $connection->getPort(),
'transport' => $connection->getTransport(),
'headers' => $connection->hasConfig('headers') ? $connection->getConfig('headers') : [],
],
'queryString' => $request->getQuery(),
'itemCount' => $responseData['hits']['total']['value'] ?? $responseData['hits']['total'] ?? 0,
'backtrace' => (new \Exception())->getTraceAsString(),
];
}

if (null !== $this->logger) {
$message = \sprintf('%s (%s) %0.2f ms', $path, $method, $executionMS);
$message = \sprintf('%s (%s) %0.2f ms', $request->getPath(), $request->getMethod(), $executionMS);
$this->logger->info($message, (array) $data);
}
}

public function getNbQueries(): int
{
return \count($this->queries);
}

/**
* @return array<mixed>
*/
public function getQueries(): array
{
return $this->queries;
}

/**
* @param array<mixed> $context
*/
public function log($level, $message, array $context = []): void
{
if (null !== $this->logger && $this->isEnabled()) {
$this->logger->log($level, $message, $context);
}
}

public function reset(): void
{
$this->queries = [];
Expand Down
17 changes: 17 additions & 0 deletions EMS/common-bundle/src/Elasticsearch/QueryStringEscaper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

declare(strict_types=1);

namespace EMS\CommonBundle\Elasticsearch;

class QueryStringEscaper
{
private const REGEX_RESERVED_CHARACTERS = '/[\\+\\-\\=\\&\\|\\!\\(\\)\\{\\}\\[\\]\\^\\\"\\~\\*\\<\\>\\?\\:\\\\\\/]/';

public static function escape(string $queryString): string
{
$result = \preg_replace(self::REGEX_RESERVED_CHARACTERS, \addslashes('\\$0'), $queryString);

return $result ?: $queryString;
}
}
Loading

0 comments on commit 335290e

Please sign in to comment.