feat(logging): complete EverLog coverage in index.php
- Entry log (INFO/DEBUG) added to all public API functions - EverLog::warn/error added before every uncovered http_response_code(4xx/5xx) - Total EverLog calls: 117 across all request paths, error paths, and AI flows - Only pure helper functions excluded (no I/O, no side-effects)
This commit is contained in:
@@ -114,6 +114,7 @@ if (($_GET['action'] ?? '') === 'get_logs') {
|
|||||||
$token = loadEnv()['SETTINGS_TOKEN'] ?? '';
|
$token = loadEnv()['SETTINGS_TOKEN'] ?? '';
|
||||||
$reqTok = $_GET['token'] ?? $_SERVER['HTTP_X_SETTINGS_TOKEN'] ?? '';
|
$reqTok = $_GET['token'] ?? $_SERVER['HTTP_X_SETTINGS_TOKEN'] ?? '';
|
||||||
if (!empty($token) && $reqTok !== $token) {
|
if (!empty($token) && $reqTok !== $token) {
|
||||||
|
EverLog::warn('get_logs: unauthorized (403)');
|
||||||
http_response_code(403);
|
http_response_code(403);
|
||||||
echo json_encode(['error' => 'Unauthorized']);
|
echo json_encode(['error' => 'Unauthorized']);
|
||||||
exit;
|
exit;
|
||||||
@@ -472,6 +473,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && in_array($rateLimitAction, $_writeA
|
|||||||
$csrfHeader = $_SERVER['HTTP_X_EVERSHELF_REQUEST'] ?? '';
|
$csrfHeader = $_SERVER['HTTP_X_EVERSHELF_REQUEST'] ?? '';
|
||||||
$contentType = $_SERVER['CONTENT_TYPE'] ?? '';
|
$contentType = $_SERVER['CONTENT_TYPE'] ?? '';
|
||||||
if ($csrfHeader !== '1' && stripos($contentType, 'application/json') === false) {
|
if ($csrfHeader !== '1' && stripos($contentType, 'application/json') === false) {
|
||||||
|
EverLog::warn('csrf_rejected (403)');
|
||||||
http_response_code(403);
|
http_response_code(403);
|
||||||
echo json_encode(['success' => false, 'error' => 'csrf_rejected']);
|
echo json_encode(['success' => false, 'error' => 'csrf_rejected']);
|
||||||
exit;
|
exit;
|
||||||
@@ -504,6 +506,7 @@ try {
|
|||||||
'dismiss_anomaly', 'bring_add', 'bring_remove', 'bring_sync',
|
'dismiss_anomaly', 'bring_add', 'bring_remove', 'bring_sync',
|
||||||
];
|
];
|
||||||
if (in_array($action, $demoBlocked, true)) {
|
if (in_array($action, $demoBlocked, true)) {
|
||||||
|
EverLog::warn('demo_mode blocked (403)');
|
||||||
http_response_code(403);
|
http_response_code(403);
|
||||||
echo json_encode(['success' => false, 'error' => 'demo_mode']);
|
echo json_encode(['success' => false, 'error' => 'demo_mode']);
|
||||||
exit;
|
exit;
|
||||||
@@ -762,6 +765,7 @@ endif; // end !CRON_MODE
|
|||||||
|
|
||||||
// ===== EXPORT INVENTORY =====
|
// ===== EXPORT INVENTORY =====
|
||||||
function exportInventory(PDO $db): void {
|
function exportInventory(PDO $db): void {
|
||||||
|
EverLog::info('exportInventory');
|
||||||
$format = strtolower($_GET['format'] ?? 'csv');
|
$format = strtolower($_GET['format'] ?? 'csv');
|
||||||
|
|
||||||
$stmt = $db->query("
|
$stmt = $db->query("
|
||||||
@@ -863,6 +867,7 @@ HTML;
|
|||||||
|
|
||||||
// ===== TTS PROXY =====
|
// ===== TTS PROXY =====
|
||||||
function ttsProxy() {
|
function ttsProxy() {
|
||||||
|
EverLog::info('ttsProxy');
|
||||||
$body = json_decode(file_get_contents('php://input'), true);
|
$body = json_decode(file_get_contents('php://input'), true);
|
||||||
$url = isset($body['url']) ? trim($body['url']) : '';
|
$url = isset($body['url']) ? trim($body['url']) : '';
|
||||||
$method = isset($body['method']) ? strtoupper(trim($body['method'])) : 'POST';
|
$method = isset($body['method']) ? strtoupper(trim($body['method'])) : 'POST';
|
||||||
@@ -874,6 +879,7 @@ function ttsProxy() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!$url || !preg_match('/^https?:\/\/.+/', $url)) {
|
if (!$url || !preg_match('/^https?:\/\/.+/', $url)) {
|
||||||
|
EverLog::warn('ttsProxy: invalid URL (400)');
|
||||||
http_response_code(400);
|
http_response_code(400);
|
||||||
echo json_encode(['error' => 'URL non valido']);
|
echo json_encode(['error' => 'URL non valido']);
|
||||||
return;
|
return;
|
||||||
@@ -901,6 +907,7 @@ function ttsProxy() {
|
|||||||
curl_close($ch);
|
curl_close($ch);
|
||||||
|
|
||||||
if ($curlErr) {
|
if ($curlErr) {
|
||||||
|
EverLog::error('ttsProxy: curl error (502)');
|
||||||
http_response_code(502);
|
http_response_code(502);
|
||||||
echo json_encode(['error' => 'cURL error: ' . $curlErr]);
|
echo json_encode(['error' => 'cURL error: ' . $curlErr]);
|
||||||
return;
|
return;
|
||||||
@@ -914,6 +921,7 @@ function ttsProxy() {
|
|||||||
|
|
||||||
// ===== FOOD FACTS (cached daily) =====
|
// ===== FOOD FACTS (cached daily) =====
|
||||||
function getFoodFacts(): void {
|
function getFoodFacts(): void {
|
||||||
|
EverLog::info('getFoodFacts');
|
||||||
header('Content-Type: application/json; charset=utf-8');
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
$cacheFile = __DIR__ . '/../data/food_facts_cache.json';
|
$cacheFile = __DIR__ . '/../data/food_facts_cache.json';
|
||||||
$maxAgeSeconds = 86400; // 24 hours
|
$maxAgeSeconds = 86400; // 24 hours
|
||||||
@@ -1048,6 +1056,7 @@ function getExpiryHistory($db): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function clientLog(): void {
|
function clientLog(): void {
|
||||||
|
EverLog::debug('clientLog');
|
||||||
$input = json_decode(file_get_contents('php://input'), true);
|
$input = json_decode(file_get_contents('php://input'), true);
|
||||||
$logFile = __DIR__ . '/../data/client_debug.log';
|
$logFile = __DIR__ . '/../data/client_debug.log';
|
||||||
$ua = $_SERVER['HTTP_USER_AGENT'] ?? 'unknown';
|
$ua = $_SERVER['HTTP_USER_AGENT'] ?? 'unknown';
|
||||||
@@ -1313,6 +1322,7 @@ function getProduct(PDO $db): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function deleteProduct(PDO $db): void {
|
function deleteProduct(PDO $db): void {
|
||||||
|
EverLog::info('deleteProduct');
|
||||||
$input = json_decode(file_get_contents('php://input'), true);
|
$input = json_decode(file_get_contents('php://input'), true);
|
||||||
$id = $input['id'] ?? 0;
|
$id = $input['id'] ?? 0;
|
||||||
$stmt = $db->prepare("DELETE FROM products WHERE id = ?");
|
$stmt = $db->prepare("DELETE FROM products WHERE id = ?");
|
||||||
@@ -1337,6 +1347,7 @@ function searchProducts(PDO $db): void {
|
|||||||
// ===== INVENTORY FUNCTIONS =====
|
// ===== INVENTORY FUNCTIONS =====
|
||||||
|
|
||||||
function listInventory(PDO $db): void {
|
function listInventory(PDO $db): void {
|
||||||
|
EverLog::debug('listInventory');
|
||||||
$location = $_GET['location'] ?? '';
|
$location = $_GET['location'] ?? '';
|
||||||
$query = "
|
$query = "
|
||||||
SELECT i.*, p.name, p.brand, p.category, p.image_url, p.unit, p.barcode, p.default_quantity, p.package_unit,
|
SELECT i.*, p.name, p.brand, p.category, p.image_url, p.unit, p.barcode, p.default_quantity, p.package_unit,
|
||||||
@@ -1359,6 +1370,7 @@ function listInventory(PDO $db): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function addToInventory(PDO $db): void {
|
function addToInventory(PDO $db): void {
|
||||||
|
EverLog::info('addToInventory');
|
||||||
$input = json_decode(file_get_contents('php://input'), true);
|
$input = json_decode(file_get_contents('php://input'), true);
|
||||||
$productId = (int)($input['product_id'] ?? 0);
|
$productId = (int)($input['product_id'] ?? 0);
|
||||||
$quantity = (float)($input['quantity'] ?? 1);
|
$quantity = (float)($input['quantity'] ?? 1);
|
||||||
@@ -1367,6 +1379,7 @@ function addToInventory(PDO $db): void {
|
|||||||
$unit = $input['unit'] ?? null;
|
$unit = $input['unit'] ?? null;
|
||||||
|
|
||||||
if (!$productId) {
|
if (!$productId) {
|
||||||
|
EverLog::warn('addToInventory: product_id missing (400)');
|
||||||
http_response_code(400);
|
http_response_code(400);
|
||||||
echo json_encode(['error' => 'Product ID required']);
|
echo json_encode(['error' => 'Product ID required']);
|
||||||
return;
|
return;
|
||||||
@@ -1374,6 +1387,7 @@ function addToInventory(PDO $db): void {
|
|||||||
|
|
||||||
// Validate quantity bounds
|
// Validate quantity bounds
|
||||||
if ($quantity <= 0 || $quantity > 100000) {
|
if ($quantity <= 0 || $quantity > 100000) {
|
||||||
|
EverLog::warn('addToInventory: invalid quantity (400)');
|
||||||
http_response_code(400);
|
http_response_code(400);
|
||||||
echo json_encode(['error' => 'Invalid quantity']);
|
echo json_encode(['error' => 'Invalid quantity']);
|
||||||
return;
|
return;
|
||||||
@@ -1382,6 +1396,7 @@ function addToInventory(PDO $db): void {
|
|||||||
// Validate location
|
// Validate location
|
||||||
$validLocations = ['dispensa', 'frigo', 'freezer', 'altro'];
|
$validLocations = ['dispensa', 'frigo', 'freezer', 'altro'];
|
||||||
if (!in_array($location, $validLocations)) {
|
if (!in_array($location, $validLocations)) {
|
||||||
|
EverLog::warn('addToInventory: invalid location (400)');
|
||||||
http_response_code(400);
|
http_response_code(400);
|
||||||
echo json_encode(['error' => 'Invalid location']);
|
echo json_encode(['error' => 'Invalid location']);
|
||||||
return;
|
return;
|
||||||
@@ -1538,6 +1553,7 @@ function useFromInventory(PDO $db): void {
|
|||||||
$notes = $input['notes'] ?? '';
|
$notes = $input['notes'] ?? '';
|
||||||
|
|
||||||
if (!$productId) {
|
if (!$productId) {
|
||||||
|
EverLog::warn('useFromInventory: product_id missing (400)');
|
||||||
http_response_code(400);
|
http_response_code(400);
|
||||||
echo json_encode(['error' => 'Product ID required']);
|
echo json_encode(['error' => 'Product ID required']);
|
||||||
return;
|
return;
|
||||||
@@ -1599,6 +1615,7 @@ function useFromInventory(PDO $db): void {
|
|||||||
$existing = $stmt->fetch();
|
$existing = $stmt->fetch();
|
||||||
|
|
||||||
if (!$existing) {
|
if (!$existing) {
|
||||||
|
EverLog::warn('useFromInventory: product not found in inventory (404)');
|
||||||
http_response_code(404);
|
http_response_code(404);
|
||||||
echo json_encode(['error' => 'Product not found in inventory at this location']);
|
echo json_encode(['error' => 'Product not found in inventory at this location']);
|
||||||
return;
|
return;
|
||||||
@@ -1961,6 +1978,7 @@ function deleteInventory(PDO $db): void {
|
|||||||
* user; those rows are silently deleted here (no banner needed).
|
* user; those rows are silently deleted here (no banner needed).
|
||||||
*/
|
*/
|
||||||
function getFinishedItems(PDO $db): void {
|
function getFinishedItems(PDO $db): void {
|
||||||
|
EverLog::debug('getFinishedItems');
|
||||||
$rows = $db->query("
|
$rows = $db->query("
|
||||||
SELECT p.id AS product_id, p.name, p.brand, p.unit, p.default_quantity, p.package_unit, p.image_url, p.barcode,
|
SELECT p.id AS product_id, p.name, p.brand, p.unit, p.default_quantity, p.package_unit, p.image_url, p.barcode,
|
||||||
MIN(i.location) AS location,
|
MIN(i.location) AS location,
|
||||||
@@ -2027,6 +2045,7 @@ function confirmFinished(PDO $db): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function inventorySummary(PDO $db): void {
|
function inventorySummary(PDO $db): void {
|
||||||
|
EverLog::debug('inventorySummary');
|
||||||
$stmt = $db->query("
|
$stmt = $db->query("
|
||||||
SELECT i.location, COUNT(DISTINCT i.product_id) as product_count,
|
SELECT i.location, COUNT(DISTINCT i.product_id) as product_count,
|
||||||
SUM(i.quantity) as total_items
|
SUM(i.quantity) as total_items
|
||||||
@@ -2039,6 +2058,7 @@ function inventorySummary(PDO $db): void {
|
|||||||
// ===== TRANSACTION FUNCTIONS =====
|
// ===== TRANSACTION FUNCTIONS =====
|
||||||
|
|
||||||
function listTransactions(PDO $db): void {
|
function listTransactions(PDO $db): void {
|
||||||
|
EverLog::debug('listTransactions');
|
||||||
$limit = (int)($_GET['limit'] ?? 50);
|
$limit = (int)($_GET['limit'] ?? 50);
|
||||||
$offset = (int)($_GET['offset'] ?? 0);
|
$offset = (int)($_GET['offset'] ?? 0);
|
||||||
$productId = $_GET['product_id'] ?? '';
|
$productId = $_GET['product_id'] ?? '';
|
||||||
@@ -2084,6 +2104,7 @@ function undoTransaction(PDO $db): void {
|
|||||||
$stmt->execute([$txId]);
|
$stmt->execute([$txId]);
|
||||||
$tx = $stmt->fetch();
|
$tx = $stmt->fetch();
|
||||||
if (!$tx) {
|
if (!$tx) {
|
||||||
|
EverLog::warn('undoTransaction: transaction not found (404)');
|
||||||
http_response_code(404);
|
http_response_code(404);
|
||||||
echo json_encode(['error' => 'Transaction not found']);
|
echo json_encode(['error' => 'Transaction not found']);
|
||||||
return;
|
return;
|
||||||
@@ -2143,6 +2164,7 @@ function undoTransaction(PDO $db): void {
|
|||||||
echo json_encode(['success' => true, 'name' => $tx['name']]);
|
echo json_encode(['success' => true, 'name' => $tx['name']]);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
$db->rollBack();
|
$db->rollBack();
|
||||||
|
EverLog::error('undoTransaction: DB error (500)');
|
||||||
http_response_code(500);
|
http_response_code(500);
|
||||||
echo json_encode(['error' => 'DB error: ' . $e->getMessage()]);
|
echo json_encode(['error' => 'DB error: ' . $e->getMessage()]);
|
||||||
_phpErrorReport($e->getMessage(), $e->getFile(), $e->getLine(), $e->getTraceAsString(), get_class($e));
|
_phpErrorReport($e->getMessage(), $e->getFile(), $e->getLine(), $e->getTraceAsString(), get_class($e));
|
||||||
@@ -2450,6 +2472,7 @@ function getStats(PDO $db): void {
|
|||||||
|
|
||||||
// ===== RECENT & POPULAR PRODUCTS =====
|
// ===== RECENT & POPULAR PRODUCTS =====
|
||||||
function recentPopularProducts(PDO $db): void {
|
function recentPopularProducts(PDO $db): void {
|
||||||
|
EverLog::debug('recentPopularProducts');
|
||||||
// Last 4 distinct products used (type='out'), most recent first
|
// Last 4 distinct products used (type='out'), most recent first
|
||||||
$recentStmt = $db->query("
|
$recentStmt = $db->query("
|
||||||
SELECT DISTINCT t.product_id, p.name, p.brand, p.category, p.image_url, p.unit,
|
SELECT DISTINCT t.product_id, p.name, p.brand, p.category, p.image_url, p.unit,
|
||||||
@@ -2652,6 +2675,7 @@ function getConsumptionPredictions(PDO $db): void {
|
|||||||
// ===== SETTINGS =====
|
// ===== SETTINGS =====
|
||||||
|
|
||||||
function getServerSettings(): void {
|
function getServerSettings(): void {
|
||||||
|
EverLog::debug('getServerSettings');
|
||||||
$geminiKey = env('GEMINI_API_KEY');
|
$geminiKey = env('GEMINI_API_KEY');
|
||||||
$bringEmail = env('BRING_EMAIL');
|
$bringEmail = env('BRING_EMAIL');
|
||||||
|
|
||||||
@@ -2953,6 +2977,7 @@ function prewarmShelfLifeCache(PDO $db, int $limit = 5): array {
|
|||||||
* Cache has no expiry — shelf-life science doesn't change; the file can be manually deleted to refresh.
|
* Cache has no expiry — shelf-life science doesn't change; the file can be manually deleted to refresh.
|
||||||
*/
|
*/
|
||||||
function getOpenedShelfLifeDays(string $name, string $category, string $location, bool $vacuumSealed = false, bool $allowAI = true): int {
|
function getOpenedShelfLifeDays(string $name, string $category, string $location, bool $vacuumSealed = false, bool $allowAI = true): int {
|
||||||
|
EverLog::debug('getOpenedShelfLifeDays');
|
||||||
$cacheFile = __DIR__ . '/../data/opened_shelf_cache.json';
|
$cacheFile = __DIR__ . '/../data/opened_shelf_cache.json';
|
||||||
$cacheKey = md5(mb_strtolower($name) . '|' . mb_strtolower($location) . '|v2');
|
$cacheKey = md5(mb_strtolower($name) . '|' . mb_strtolower($location) . '|v2');
|
||||||
|
|
||||||
@@ -3059,6 +3084,7 @@ function getOpenedShelfLifeAction(): void {
|
|||||||
* Returns null if tesseract binary is not available or GD is not compiled in.
|
* Returns null if tesseract binary is not available or GD is not compiled in.
|
||||||
*/
|
*/
|
||||||
function tesseractReadExpiry(string $imageBase64): ?array {
|
function tesseractReadExpiry(string $imageBase64): ?array {
|
||||||
|
EverLog::info('tesseractReadExpiry');
|
||||||
// Require both the binary and the GD extension
|
// Require both the binary and the GD extension
|
||||||
if (!function_exists('imagecreatefromstring')) return null;
|
if (!function_exists('imagecreatefromstring')) return null;
|
||||||
$tesseract = trim(shell_exec('which tesseract 2>/dev/null') ?? '');
|
$tesseract = trim(shell_exec('which tesseract 2>/dev/null') ?? '');
|
||||||
@@ -4239,6 +4265,7 @@ PROMPT;
|
|||||||
|
|
||||||
// ===== RECIPE FROM INGREDIENT =====
|
// ===== RECIPE FROM INGREDIENT =====
|
||||||
function recipeFromIngredient(PDO $db): void {
|
function recipeFromIngredient(PDO $db): void {
|
||||||
|
EverLog::info('recipeFromIngredient');
|
||||||
$apiKey = env('GEMINI_API_KEY');
|
$apiKey = env('GEMINI_API_KEY');
|
||||||
if (empty($apiKey)) {
|
if (empty($apiKey)) {
|
||||||
echo json_encode(['success' => false, 'error' => 'no_api_key']);
|
echo json_encode(['success' => false, 'error' => 'no_api_key']);
|
||||||
@@ -4500,6 +4527,7 @@ function _enrichChatIngredients(array &$ingredients, array $items): void {
|
|||||||
|
|
||||||
// ===== RECIPE GENERATION — STREAMING AGENT =====
|
// ===== RECIPE GENERATION — STREAMING AGENT =====
|
||||||
function generateRecipeStream(PDO $db): void {
|
function generateRecipeStream(PDO $db): void {
|
||||||
|
EverLog::info('generateRecipeStream');
|
||||||
// Override content-type for SSE before any output is sent
|
// Override content-type for SSE before any output is sent
|
||||||
header('Content-Type: text/event-stream');
|
header('Content-Type: text/event-stream');
|
||||||
header('Cache-Control: no-cache, no-store, must-revalidate');
|
header('Cache-Control: no-cache, no-store, must-revalidate');
|
||||||
@@ -5445,6 +5473,7 @@ function italianToBring(string $italianName): string {
|
|||||||
* Returns null on failure so the caller can fall back gracefully.
|
* Returns null on failure so the caller can fall back gracefully.
|
||||||
*/
|
*/
|
||||||
function _geminiClassifyProduct(string $name, string $brand, string $category): ?string {
|
function _geminiClassifyProduct(string $name, string $brand, string $category): ?string {
|
||||||
|
EverLog::debug('_geminiClassifyProduct');
|
||||||
$apiKey = env('GEMINI_API_KEY');
|
$apiKey = env('GEMINI_API_KEY');
|
||||||
if (empty($apiKey)) return null;
|
if (empty($apiKey)) return null;
|
||||||
|
|
||||||
@@ -7287,6 +7316,7 @@ function chatClear(PDO $db): void {
|
|||||||
* and scale inventory quantities accordingly.
|
* and scale inventory quantities accordingly.
|
||||||
*/
|
*/
|
||||||
function migrateUnitsToBase(PDO $db): void {
|
function migrateUnitsToBase(PDO $db): void {
|
||||||
|
EverLog::info('migrateUnitsToBase');
|
||||||
$changes = 0;
|
$changes = 0;
|
||||||
|
|
||||||
// Get products with kg or l units
|
// Get products with kg or l units
|
||||||
@@ -7413,6 +7443,7 @@ function reportError(): void {
|
|||||||
* version string? App version
|
* version string? App version
|
||||||
*/
|
*/
|
||||||
function reportBugManual(): void {
|
function reportBugManual(): void {
|
||||||
|
EverLog::info('reportBugManual');
|
||||||
$input = json_decode(file_get_contents('php://input'), true) ?: [];
|
$input = json_decode(file_get_contents('php://input'), true) ?: [];
|
||||||
|
|
||||||
$allowedTypes = ['bug', 'feature', 'question'];
|
$allowedTypes = ['bug', 'feature', 'question'];
|
||||||
@@ -7598,6 +7629,7 @@ function _createOrCommentGithubIssue(
|
|||||||
string $version, array $context
|
string $version, array $context
|
||||||
): void {
|
): void {
|
||||||
$fp = _errorFingerprint($source, $type, $message);
|
$fp = _errorFingerprint($source, $type, $message);
|
||||||
|
EverLog::debug('_createOrCommentGithubIssue', ['fp' => $fp, 'type' => $type]);
|
||||||
|
|
||||||
// ── 1. Search for an existing open issue with this fingerprint ─────────
|
// ── 1. Search for an existing open issue with this fingerprint ─────────
|
||||||
$searchQuery = urlencode("repo:$repo is:issue is:open label:auto-report \"fp:$fp\" in:body");
|
$searchQuery = urlencode("repo:$repo is:issue is:open label:auto-report \"fp:$fp\" in:body");
|
||||||
@@ -7675,6 +7707,7 @@ function _createOrCommentGithubIssue(
|
|||||||
* Returns ['http_code' => int, 'body' => array].
|
* Returns ['http_code' => int, 'body' => array].
|
||||||
*/
|
*/
|
||||||
function _githubRequest(string $token, string $method, string $url, array $payload = []): array {
|
function _githubRequest(string $token, string $method, string $url, array $payload = []): array {
|
||||||
|
EverLog::debug('_githubRequest');
|
||||||
$ch = curl_init($url);
|
$ch = curl_init($url);
|
||||||
$headers = [
|
$headers = [
|
||||||
'Authorization: token ' . $token,
|
'Authorization: token ' . $token,
|
||||||
@@ -7704,6 +7737,7 @@ function _githubRequest(string $token, string $method, string $url, array $paylo
|
|||||||
* Writes to local log + creates a GitHub issue.
|
* Writes to local log + creates a GitHub issue.
|
||||||
*/
|
*/
|
||||||
function _phpErrorReport(string $message, string $file, int $line, string $trace, string $type): void {
|
function _phpErrorReport(string $message, string $file, int $line, string $trace, string $type): void {
|
||||||
|
EverLog::error('_phpErrorReport');
|
||||||
// Prevent infinite loops if this function itself throws
|
// Prevent infinite loops if this function itself throws
|
||||||
static $running = false;
|
static $running = false;
|
||||||
if ($running) return;
|
if ($running) return;
|
||||||
@@ -8051,6 +8085,7 @@ function _priceKey(string $name, string $country): string {
|
|||||||
* { price_per_unit, unit_label, currency, source_note } or null on failure.
|
* { price_per_unit, unit_label, currency, source_note } or null on failure.
|
||||||
*/
|
*/
|
||||||
function _fetchPriceFromAI(string $name, string $country, string $currency, string $lang): ?array {
|
function _fetchPriceFromAI(string $name, string $country, string $currency, string $lang): ?array {
|
||||||
|
EverLog::info('_fetchPriceFromAI');
|
||||||
$result = _fetchPricesBatchFromAI([$name], $country, $currency, $lang);
|
$result = _fetchPricesBatchFromAI([$name], $country, $currency, $lang);
|
||||||
return $result[$name] ?? null;
|
return $result[$name] ?? null;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user