arkaitzgarro/elastic-apm-laravel

View on GitHub
src/Collectors/DBQueryCollector.php

Summary

Maintainability
A
1 hr
Test Coverage
A
95%
<?php

namespace AG\ElasticApmLaravel\Collectors;

use AG\ElasticApmLaravel\Contracts\DataCollector;
use Illuminate\Database\Events\QueryExecuted;
use Jasny\DB\MySQL\QuerySplitter;

/**
 * Collects info about the database executed queries.
 */
class DBQueryCollector extends EventDataCollector implements DataCollector
{
    public function getName(): string
    {
        return 'query-collector';
    }

    public function registerEventListeners(): void
    {
        $this->app->events->listen(QueryExecuted::class, function (QueryExecuted $query) {
            $this->onQueryExecutedEvent($query);
        });
    }

    private function onQueryExecutedEvent(QueryExecuted $query): void
    {
        if ('auto' === $this->config->get('elastic-apm-laravel.spans.querylog.enabled')) {
            if ($query->time < $this->config->get('elastic-apm-laravel.spans.querylog.threshold')) {
                return;
            }
        }

        $start_time = $this->event_clock->microtime() - $this->start_time->microseconds() - $query->time / 1000;
        $end_time = $start_time + $query->time / 1000;

        $query = [
            'name' => $this->getQueryName($query->sql),
            'type' => 'db.mysql.query',
            'action' => 'query',
            'start' => $start_time,
            'end' => $end_time,
            'context' => [
                'db' => [
                    'statement' => (string) $query->sql,
                    'type' => 'sql',
                ],
            ],
        ];

        $this->addMeasure(
            $query['name'],
            $query['start'],
            $query['end'],
            $query['type'],
            $query['action'],
            $query['context']
        );
    }

    private function getQueryName(string $sql): string
    {
        $fallback = 'Eloquent Query';

        try {
            $query_type = QuerySplitter::getQueryType($sql);
            $tables = QuerySplitter::splitTables($sql);

            if (isset($query_type) && is_array($tables)) {
                // Query type and tables
                return $query_type . ' ' . join(', ', array_values($tables));
            }

            return $fallback;
        } catch (\Exception $e) {
            return $fallback;
        }
    }
}