Only record the same error or query once

PHP 8.2로 올라오면서 동일한 오류가 수백~수천 번 반복되어
디버그 데이터가 너무 많은 메모리를 차지하는 문제가 종종 발생하고 있음.

동일한 위치에서 발생한 동일한 오류나 쿼리는 한 번만 기록하고
count를 증가시키도록 하여, 불필요한 메모리 사용을 줄이고
반복되는 오류나 쿼리를 쉽게 찾을 수 있도록 개선함.
This commit is contained in:
Kijin Sung 2023-04-30 23:56:54 +09:00
parent 968bde2c38
commit a1bd9cc2bc
3 changed files with 97 additions and 19 deletions

View file

@ -53,7 +53,7 @@ class Debug
*/
public static function getEntries()
{
return self::$_entries;
return array_values(self::$_entries);
}
/**
@ -73,7 +73,7 @@ class Debug
*/
public static function getErrors()
{
return self::$_errors;
return array_values(self::$_errors);
}
/**
@ -93,7 +93,7 @@ class Debug
*/
public static function getQueries()
{
return self::$_queries;
return array_values(self::$_queries);
}
/**
@ -281,10 +281,21 @@ class Debug
'file' => isset($backtrace[0]['file']) ? $backtrace[0]['file'] : null,
'line' => isset($backtrace[0]['line']) ? $backtrace[0]['line'] : 0,
'backtrace' => $backtrace,
'count' => 1,
'time' => microtime(true),
'type' => 'Debug',
);
self::$_entries[] = $entry;
// Only add the same entry once.
$key = hash_hmac('sha1', serialize([$entry->message, $entry->file, $entry->line]), config('crypto.authentication_key'));
if (isset(self::$_entries[$key]))
{
self::$_entries[$key]->count++;
}
else
{
self::$_entries[$key] = $entry;
}
// Add the entry to the error log.
if (isset(self::$_config['write_error_log']) && self::$_config['write_error_log'] === 'all')
@ -332,15 +343,27 @@ class Debug
$backtrace = debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS);
// Prepare the error entry.
self::$_errors[] = $errinfo = (object)array(
$errinfo = (object)array(
'message' => $message,
'file' => $errfile,
'line' => $errline,
'backtrace' => $backtrace,
'count' => 1,
'time' => microtime(true),
'type' => self::getErrorType($errno),
);
// If the same error is repeated, only increment the counter.
$key = hash_hmac('sha1', serialize([$errinfo->message, $errinfo->file, $errinfo->line]), config('crypto.authentication_key'));
if (isset(self::$_errors[$key]))
{
self::$_errors[$key]->count++;
}
else
{
self::$_errors[$key] = $errinfo;
}
// Add the entry to the error log.
if (isset(self::$_config['write_error_log']) && self::$_config['write_error_log'] === 'all')
{
@ -374,14 +397,36 @@ class Debug
'line' => $query['called_line'],
'method' => $query['called_method'],
'backtrace' => $query['backtrace'] ?: array(),
'count' => 1,
'time' => microtime(true),
'type' => 'Query',
);
self::$_queries[] = $query_object;
// Generate a unique key for this query.
$key = hash_hmac('sha1', serialize([
$query_object->query_id,
$query_object->query_string,
$query_object->query_connection,
$query_object->file,
$query_object->line,
$query_object->method,
]), config('crypto.authentication_key'));
// If the same query is repeated, only increment the counter.
if (isset(self::$_queries[$key]))
{
self::$_queries[$key]->query_time += $query_object->query_time;
self::$_queries[$key]->count++;
}
else
{
self::$_queries[$key] = $query_object;
}
// Record query time.
self::$_query_time += $query_object->query_time;
// Add the entry to the error log if the result wasn't successful.
// Add the query to the error log if the result wasn't successful.
if ($query['result'] === 'error')
{
$error_object = (object)array(
@ -389,11 +434,21 @@ class Debug
'file' => $query_object->file,
'line' => $query_object->line,
'backtrace' => $query_object->backtrace ?: array(),
'count' => 1,
'time' => $query_object->time,
'type' => 'Query Error',
);
self::$_errors[] = $error_object;
// If the same query error is repeated, only increment the counter.
$key = hash_hmac('sha1', serialize(['QUERY ERROR', $error_object->message, $error_object->file, $error_object->line]), config('crypto.authentication_key'));
if (isset(self::$_errors[$key]))
{
self::$_errors[$key]->count++;
}
else
{
self::$_errors[$key] = $error_object;
}
if (self::$_config['write_error_log'] === 'all')
{
@ -402,7 +457,7 @@ class Debug
}
}
// Add the entry to the slow query log.
// Add the query to the slow query log.
if ($query_object->query_time && $query_object->query_time >= (self::$_config['log_slow_queries'] ?? 1))
{
self::$_slow_queries[] = $query_object;
@ -794,9 +849,9 @@ class Debug
'template' => sprintf('%0.4f sec (count: %d)', $GLOBALS['__template_elapsed__'] ?? 0, $GLOBALS['__TemplateHandlerCalled__'] ?? 0),
'trans' => sprintf('%0.4f sec', $GLOBALS['__trans_content_elapsed__'] ?? 0),
),
'entries' => self::$_entries,
'errors' => self::$_errors,
'queries' => self::$_queries,
'entries' => array_values(self::$_entries),
'errors' => array_values(self::$_errors),
'queries' => array_values(self::$_queries),
'slow_queries' => self::$_slow_queries,
'slow_triggers' => self::$_slow_triggers,
'slow_widgets' => self::$_slow_widgets,

View file

@ -98,7 +98,10 @@ $(function() {
backtrace = $('<ul class="debug_backtrace"></ul>').appendTo(entry);
for (j in data.entries[i].backtrace) {
if (data.entries[i].backtrace[j].file) {
backtrace.append($('<li></li>').text(data.entries[i].backtrace[j].file + ":" + data.entries[i].backtrace[j].line));
backtrace.append($('<li></li>').text(
data.entries[i].backtrace[j].file + ":" + data.entries[i].backtrace[j].line +
(j == 0 ? (" (×" + data.entries[i].count + ")") : "")
));
}
}
}
@ -114,7 +117,10 @@ $(function() {
backtrace = $('<ul class="debug_backtrace"></ul>').appendTo(entry);
for (j in data.errors[i].backtrace) {
if (data.errors[i].backtrace[j].file) {
backtrace.append($('<li></li>').text(data.errors[i].backtrace[j].file + ":" + data.errors[i].backtrace[j].line));
backtrace.append($('<li></li>').text(
data.errors[i].backtrace[j].file + ":" + data.errors[i].backtrace[j].line +
(j == 0 ? (" (×" + data.errors[i].count + ")") : "")
));
}
}
}
@ -129,7 +135,10 @@ $(function() {
entry.text(num + ". " + data.queries[i].query_string);
description = $('<ul class="debug_backtrace"></ul>').appendTo(entry);
if (data.queries[i].file && data.queries[i].line) {
description.append($('<li></li>').text("Caller: " + data.queries[i].file + ":" + data.queries[i].line).append("<br>(" + data.queries[i].method + ")"));
description.append($('<li></li>').text("Caller: " +
data.queries[i].file + ":" + data.queries[i].line +
(" (×" + data.queries[i].count + ")")
).append("<br>(" + data.queries[i].method + ")"));
description.append($('<li></li>').text("Connection: " + data.queries[i].query_connection));
description.append($('<li></li>').text("Query ID: " + data.queries[i].query_id));
description.append($('<li></li>').text("Query Time: " + (data.queries[i].query_time ? (data.queries[i].query_time.toFixed(4) + " sec") : "")));

View file

@ -51,11 +51,18 @@ Debug Entries
$entry->message = trim(preg_replace('/\r?\n/', "\n" . ' ', print_r($entry->message, true)));
}
echo sprintf('%02d. %s', ++$entry_count, $entry->message) . "\n";
$is_first_entry = true;
foreach ($entry->backtrace as $key => $backtrace)
{
if (isset($backtrace['file']) && isset($backtrace['line']))
{
echo sprintf(' - %s line %d', $backtrace['file'], $backtrace['line']) . "\n";
echo sprintf(' - %s line %d', $backtrace['file'], $backtrace['line']);
if ($is_first_entry)
{
echo ' (×' . $entry->count . ')';
$is_first_entry = false;
}
echo "\n";
}
}
}
@ -74,11 +81,18 @@ PHP Errors and Warnings
foreach ($data->errors as $error)
{
echo sprintf('%02d. %s: %s', ++$error_count, $error->type, $error->message) . "\n";
$is_first_error = true;
foreach ($error->backtrace as $key => $backtrace)
{
if (isset($backtrace['file']) && isset($backtrace['line']))
{
echo sprintf(' - %s line %d', $backtrace['file'], $backtrace['line']) . "\n";
echo sprintf(' - %s line %d', $backtrace['file'], $backtrace['line']);
if ($is_first_error)
{
echo ' (×' . $error->count . ')';
$is_first_error = false;
}
echo "\n";
}
}
}
@ -101,7 +115,7 @@ Database Queries
echo sprintf('%02d. %s', ++$query_count, $query->query_string) . "\n";
if (empty($query->backtrace))
{
echo sprintf(' - Caller: %s', $query_caller) . "\n";
echo sprintf(' - Caller: %s', $query_caller) . ' (×' . $query->count . ')' . "\n";
}
echo sprintf(' - Connection: %s', $query->query_connection) . "\n";
echo sprintf(' - Query ID: %s', $query->query_id) . "\n";
@ -109,7 +123,7 @@ Database Queries
echo sprintf(' - Result: %s', $query_result) . "\n";
if (!empty($query->backtrace))
{
echo sprintf(' - Call Stack: %s', $query_caller) . "\n";
echo sprintf(' - Call Stack: %s', $query_caller) . ' (×' . $query->count . ')' . "\n";
foreach ($query->backtrace ?? [] as $key => $backtrace)
{
if (isset($backtrace['file']) && isset($backtrace['line']))