diff --git a/dashboard/js/script.js b/dashboard/js/script.js index 875fadd..f4fdbe2 100644 --- a/dashboard/js/script.js +++ b/dashboard/js/script.js @@ -401,6 +401,7 @@ function populateRequestLog(requests) { ${r.request_url} ${time.toFixed(3)} ms ${r.response_code} + ${r.ip} ${botStatus} @@ -188,6 +205,7 @@ Request URL Total Time (ms) Response Code + IP Bot Details @@ -301,6 +319,6 @@ - + \ No newline at end of file diff --git a/src/Apm.php b/src/Apm.php index 040f6fd..3d50f69 100644 --- a/src/Apm.php +++ b/src/Apm.php @@ -105,9 +105,17 @@ public function bindEventsToFlightInstance(Engine $app): void $this->metrics['start_memory'] = memory_get_usage(); $this->metrics['request_method'] = $request->method; $this->metrics['request_url'] = $request->url; + $this->metrics['ip'] = $request->proxy_ip ?: $request->ip; + $this->metrics['user_agent'] = $request->user_agent ?? ''; + $this->metrics['host'] = $request->host ?? ''; + if(function_exists('session_id')) { + $this->metrics['session_id'] = session_status() === PHP_SESSION_ACTIVE ? session_id() : null; + } else { + $this->metrics['session_id'] = null; + } // Check if the request is from a bot - $userAgent = $request->headers['User-Agent'] ?? ''; + $userAgent = $request->user_agent ?? ''; $this->metrics['is_bot'] = $this->isBot($userAgent); }); @@ -176,6 +184,7 @@ public function bindEventsToFlightInstance(Engine $app): void // are logged, while a value of 0.1 means only 10% of requests are logged. if (rand(0, 9999) / 10000 <= $this->sampleRate) { foreach($this->pdoConnections as $pdo) { + /** @var PdoWrapper $pdo */ if(method_exists($pdo, 'logQueries')) { $pdo->logQueries(); } diff --git a/src/apm/migration/sqlite/0003-request-metadata.sql b/src/apm/migration/sqlite/0003-request-metadata.sql new file mode 100644 index 0000000..626d32a --- /dev/null +++ b/src/apm/migration/sqlite/0003-request-metadata.sql @@ -0,0 +1,12 @@ +-- Add request metadata columns to apm_requests +ALTER TABLE apm_requests ADD COLUMN ip TEXT; +ALTER TABLE apm_requests ADD COLUMN user_agent TEXT; +ALTER TABLE apm_requests ADD COLUMN host TEXT; +ALTER TABLE apm_requests ADD COLUMN session_id TEXT; + +-- Create indexes for the new columns +CREATE INDEX IF NOT EXISTS idx_apm_requests_ip ON apm_requests(ip); +CREATE INDEX IF NOT EXISTS idx_apm_requests_host ON apm_requests(host); +CREATE INDEX IF NOT EXISTS idx_apm_requests_session_id ON apm_requests(session_id); +-- Index on user_agent can help with bot filtering +CREATE INDEX IF NOT EXISTS idx_apm_requests_user_agent ON apm_requests(user_agent); diff --git a/src/apm/presenter/SqlitePresenter.php b/src/apm/presenter/SqlitePresenter.php index 3e5c490..3b0c004 100644 --- a/src/apm/presenter/SqlitePresenter.php +++ b/src/apm/presenter/SqlitePresenter.php @@ -184,6 +184,12 @@ public function getRequestsData(string $threshold, int $page, int $perPage, stri $minTime = $_GET['min_time'] ?? ''; $requestId = $_GET['request_id'] ?? ''; + // New metadata filters + $ip = $_GET['ip'] ?? ''; + $host = $_GET['host'] ?? ''; + $sessionId = $_GET['session_id'] ?? ''; + $userAgent = $_GET['user_agent'] ?? ''; + // Build main query with conditions for URL and response code $conditions = ['timestamp >= ?']; $params = [$threshold]; @@ -222,6 +228,27 @@ public function getRequestsData(string $threshold, int $page, int $perPage, stri $conditions[] = 'total_time >= ?'; $params[] = $minTimeSeconds; } + + // Add new metadata filters + if (!empty($ip)) { + $conditions[] = 'ip = ?'; + $params[] = "$ip"; + } + + if (!empty($host)) { + $conditions[] = 'host = ?'; + $params[] = "$host"; + } + + if (!empty($sessionId)) { + $conditions[] = 'session_id = ?'; + $params[] = "$sessionId"; + } + + if (!empty($userAgent)) { + $conditions[] = 'user_agent LIKE ?'; + $params[] = "%$userAgent%"; + } // Build the base query with all conditions $whereClause = implode(' AND ', $conditions); @@ -292,7 +319,7 @@ public function getRequestsData(string $threshold, int $page, int $perPage, stri $placeholders = implode(',', array_fill(0, count($paginatedRequestIds), '?')); // Get the actual request data - $requestQuery = "SELECT request_id, timestamp, request_url, total_time, response_code, is_bot FROM apm_requests + $requestQuery = "SELECT request_id, timestamp, request_url, total_time, response_code, is_bot, ip, user_agent, host, session_id FROM apm_requests WHERE request_id IN ($placeholders) ORDER BY timestamp DESC"; $stmt = $this->db->prepare($requestQuery); $stmt->execute($paginatedRequestIds); diff --git a/src/apm/writer/SqliteWriter.php b/src/apm/writer/SqliteWriter.php index 445e020..a4aee87 100644 --- a/src/apm/writer/SqliteWriter.php +++ b/src/apm/writer/SqliteWriter.php @@ -123,15 +123,19 @@ protected function storeMainMetrics(array $metrics): string response_code, response_size, response_build_time, - is_bot - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + is_bot, + ip, + user_agent, + host, + session_id + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) '); - $isBot = (int) $metrics['is_bot']; + $isBot = (int) $metrics['is_bot']; $stmt->execute([ $requestId, - gmdate('Y-m-d H:i:s', (int) $metrics['start_time']), + gmdate('Y-m-d H:i:s', (int) $metrics['start_time']), $metrics['request_method'] ?? null, $metrics['request_url'] ?? null, $metrics['total_time'] ?? null, @@ -139,7 +143,11 @@ protected function storeMainMetrics(array $metrics): string $metrics['response_code'] ?? null, $metrics['response_size'] ?? null, $metrics['response_build_time'] ?? null, - $isBot + $isBot, + $metrics['ip'] ?? null, + $metrics['user_agent'] ?? null, + $metrics['host'] ?? null, + $metrics['session_id'] ?? null ]); return $requestId;