Merge branch 'f/log'
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2024 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Classes\Cleanup;
|
||||
|
||||
use Espo\Core\Cleanup\Cleanup;
|
||||
use Espo\Core\Field\DateTime;
|
||||
use Espo\Core\Utils\Config;
|
||||
use Espo\Entities\AppLogRecord;
|
||||
use Espo\ORM\EntityManager;
|
||||
use Espo\ORM\Query\DeleteBuilder;
|
||||
|
||||
class AppLog implements Cleanup
|
||||
{
|
||||
private const PERIOD = '30 days';
|
||||
|
||||
public function __construct(
|
||||
private EntityManager $entityManager,
|
||||
private Config $config
|
||||
) {}
|
||||
|
||||
public function process(): void
|
||||
{
|
||||
$query = DeleteBuilder::create()
|
||||
->from(AppLogRecord::ENTITY_TYPE)
|
||||
->where(['createdAt<' => $this->getBefore()->toString()])
|
||||
->build();
|
||||
|
||||
$this->entityManager->getQueryExecutor()->execute($query);
|
||||
}
|
||||
|
||||
private function getBefore(): DateTime
|
||||
{
|
||||
/** @var string $period */
|
||||
$period = $this->config->get('cleanupAppLogPeriod') ?? self::PERIOD;
|
||||
|
||||
return DateTime::createNow()->modify('-' . $period);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2024 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Classes\Select\AppLogRecord\PrimaryFilters;
|
||||
|
||||
use Espo\Core\Select\Primary\Filter;
|
||||
use Espo\ORM\Query\SelectBuilder as QueryBuilder;
|
||||
use Psr\Log\LogLevel;
|
||||
|
||||
class Errors implements Filter
|
||||
{
|
||||
public function apply(QueryBuilder $queryBuilder): void
|
||||
{
|
||||
$queryBuilder->where([
|
||||
'level' => [
|
||||
ucfirst(LogLevel::ERROR),
|
||||
ucfirst(LogLevel::EMERGENCY),
|
||||
ucfirst(LogLevel::CRITICAL),
|
||||
ucfirst(LogLevel::ALERT),
|
||||
]
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2024 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Controllers;
|
||||
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Controllers\Record;
|
||||
use Espo\Core\Api\Request;
|
||||
use Espo\Core\Api\Response;
|
||||
use stdClass;
|
||||
|
||||
class AppLogRecord extends Record
|
||||
{
|
||||
protected function checkAccess(): bool
|
||||
{
|
||||
if (!$this->user->isAdmin()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$this->config->get('restrictedMode')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->config->get('appLogAdminAllowed')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->user->isSuperAdmin();
|
||||
}
|
||||
|
||||
public function postActionCreate(Request $request, Response $response): stdClass
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function putActionUpdate(Request $request, Response $response): stdClass
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function postActionCreateLink(Request $request): bool
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
public function deleteActionRemoveLink(Request $request): bool
|
||||
{
|
||||
throw new Forbidden();
|
||||
}
|
||||
}
|
||||
@@ -308,7 +308,9 @@ class Container implements ContainerInterface
|
||||
return $loader;
|
||||
}
|
||||
|
||||
assert($this->configuration !== null);
|
||||
if ($this->configuration === null) {
|
||||
throw new RuntimeException("Container configuration is not ready.");
|
||||
}
|
||||
|
||||
return $this->configuration->getLoaderClassName($id);
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ use Espo\Core\Binding\BindingContainer;
|
||||
use Espo\Core\Binding\BindingLoader;
|
||||
use Espo\Core\Binding\EspoBindingLoader;
|
||||
|
||||
use Espo\Core\Loaders\ApplicationState as ApplicationStateLoader;
|
||||
use Espo\Core\Utils\File\Manager as FileManager;
|
||||
use Espo\Core\Utils\Config\ConfigFileManager;
|
||||
use Espo\Core\Utils\Config;
|
||||
@@ -71,6 +72,7 @@ class ContainerBuilder
|
||||
'log' => LogLoader::class,
|
||||
'dataManager' => DataManagerLoader::class,
|
||||
'metadata' => MetadataLoader::class,
|
||||
'applicationState' => ApplicationStateLoader::class,
|
||||
];
|
||||
|
||||
public function withBindingLoader(BindingLoader $bindingLoader): self
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2024 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Log\Handler;
|
||||
|
||||
use Espo\Core\Api\Request;
|
||||
use Espo\Core\ApplicationState;
|
||||
use Espo\Core\ORM\EntityManagerProxy;
|
||||
use Espo\Entities\AppLogRecord;
|
||||
use Monolog\Handler\HandlerInterface;
|
||||
use Monolog\Level;
|
||||
use Monolog\LogRecord;
|
||||
use Throwable;
|
||||
|
||||
class DatabaseHandler implements HandlerInterface
|
||||
{
|
||||
public function __construct(
|
||||
private Level $level,
|
||||
private EntityManagerProxy $entityManager,
|
||||
private ApplicationState $applicationState
|
||||
) {}
|
||||
|
||||
public function isHandling(LogRecord $record): bool
|
||||
{
|
||||
if (!$this->applicationState->hasUser()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($record->context['isSql'] ?? false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $record->level->value >= $this->level->value;
|
||||
}
|
||||
|
||||
public function handle(LogRecord $record): bool
|
||||
{
|
||||
if (!$this->isHandling($record)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
$logRecord = $this->entityManager->getRDBRepositoryByClass(AppLogRecord::class)->getNew();
|
||||
|
||||
$level = ucfirst($record->level->toPsrLogLevel());
|
||||
$message = $this->interpolate($record, $record->message);
|
||||
|
||||
$logRecord
|
||||
->setLevel($level)
|
||||
->setMessage($message);
|
||||
|
||||
$this->setException($record, $logRecord);
|
||||
$this->setRequest($record, $logRecord);
|
||||
|
||||
$this->entityManager->saveEntity($logRecord);
|
||||
}
|
||||
catch (Throwable) {
|
||||
// Nowhere to log.
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function interpolate(LogRecord $record, string $line): string
|
||||
{
|
||||
$replace = [];
|
||||
|
||||
foreach ($record->context as $key => $val) {
|
||||
if (!is_array($val) && (!is_object($val) || method_exists($val, '__toString'))) {
|
||||
$replace['{' . $key . '}'] = $val;
|
||||
}
|
||||
}
|
||||
|
||||
return strtr($line, $replace);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param LogRecord[] $records
|
||||
*/
|
||||
public function handleBatch(array $records): void
|
||||
{
|
||||
foreach ($records as $record) {
|
||||
$this->handle($record);
|
||||
}
|
||||
}
|
||||
|
||||
public function close(): void
|
||||
{}
|
||||
|
||||
private function setException(LogRecord $record, AppLogRecord $logRecord): void
|
||||
{
|
||||
$exception = $record->context['exception'] ?? null;
|
||||
|
||||
if (!$exception instanceof Throwable) {
|
||||
return;
|
||||
}
|
||||
|
||||
$logRecord
|
||||
->setExceptionClass(get_class($exception))
|
||||
->setFile($exception->getFile())
|
||||
->setLine($exception->getLine())
|
||||
->setCode($exception->getCode());
|
||||
}
|
||||
|
||||
private function setRequest(LogRecord $record, AppLogRecord $logRecord): void
|
||||
{
|
||||
$request = $record->context['request'] ?? null;
|
||||
|
||||
if (!$request instanceof Request) {
|
||||
return;
|
||||
}
|
||||
|
||||
$logRecord
|
||||
->setRequestMethod($request->getMethod())
|
||||
->setRequestResourcePath($request->getResourcePath());
|
||||
}
|
||||
}
|
||||
@@ -29,8 +29,11 @@
|
||||
|
||||
namespace Espo\Core\Log;
|
||||
|
||||
use Espo\Core\ApplicationState;
|
||||
use Espo\Core\Log\Handler\DatabaseHandler;
|
||||
use Espo\Core\Log\Handler\EspoFileHandler;
|
||||
use Espo\Core\Log\Handler\EspoRotatingFileHandler;
|
||||
use Espo\Core\ORM\EntityManagerProxy;
|
||||
use Espo\Core\Utils\Config;
|
||||
use Espo\Core\Utils\Log;
|
||||
|
||||
@@ -47,7 +50,9 @@ class LogLoader
|
||||
|
||||
public function __construct(
|
||||
private readonly Config $config,
|
||||
private readonly HandlerListLoader $handlerListLoader
|
||||
private readonly HandlerListLoader $handlerListLoader,
|
||||
private readonly EntityManagerProxy $entityManagerProxy,
|
||||
private readonly ApplicationState $applicationState
|
||||
) {}
|
||||
|
||||
public function load(): Log
|
||||
@@ -65,6 +70,10 @@ class LogLoader
|
||||
$handlerList = [$this->createDefaultHandler()];
|
||||
}
|
||||
|
||||
if ($this->config->get('logger.databaseHandler')) {
|
||||
$handlerList[] = $this->createDatabaseHandler();
|
||||
}
|
||||
|
||||
foreach ($handlerList as $handler) {
|
||||
$log->pushHandler($handler);
|
||||
}
|
||||
@@ -105,4 +114,15 @@ class LogLoader
|
||||
{
|
||||
return (bool) $this->config->get('logger.printTrace');
|
||||
}
|
||||
|
||||
private function createDatabaseHandler(): HandlerInterface
|
||||
{
|
||||
$rawLevel = $this->config->get('logger.databaseHandlerLevel') ??
|
||||
$this->config->get('logger.level') ??
|
||||
self::DEFAULT_LEVEL;
|
||||
|
||||
$level = Logger::toMonologLevel($rawLevel);
|
||||
|
||||
return new DatabaseHandler($level, $this->entityManagerProxy, $this->applicationState);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2024 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Entities;
|
||||
|
||||
use Espo\Core\ORM\Entity;
|
||||
|
||||
class AppLogRecord extends Entity
|
||||
{
|
||||
public const ENTITY_TYPE = 'AppLogRecord';
|
||||
|
||||
public function setMessage(string $message): self
|
||||
{
|
||||
$this->set('message', $message);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setLevel(string $level): self
|
||||
{
|
||||
$this->set('level', $level);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setCode(?int $code): self
|
||||
{
|
||||
$this->set('code', $code);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setExceptionClass(?string $exceptionClass): self
|
||||
{
|
||||
$len = $this->getAttributeParam('exceptionClass', 'len');
|
||||
|
||||
if ($exceptionClass && strlen($exceptionClass) > $len) {
|
||||
$exceptionClass = substr($exceptionClass, $len);
|
||||
}
|
||||
|
||||
$this->set('exceptionClass', $exceptionClass);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setFile(?string $file): self
|
||||
{
|
||||
$len = $this->getAttributeParam('file', 'len');
|
||||
|
||||
if ($file && strlen($file) > $len) {
|
||||
$file = substr($file, $len);
|
||||
}
|
||||
|
||||
$this->set('file', $file);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setLine(?int $code): self
|
||||
{
|
||||
$this->set('line', $code);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setRequestMethod(?string $requestMethod): self
|
||||
{
|
||||
$this->set('requestMethod', $requestMethod);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setRequestResourcePath(?string $requestResourcePath): self
|
||||
{
|
||||
$len = $this->getAttributeParam('requestResourcePath', 'len');
|
||||
|
||||
if ($requestResourcePath && strlen($requestResourcePath) > $len) {
|
||||
$requestResourcePath = substr($requestResourcePath, $len);
|
||||
}
|
||||
|
||||
$this->set('requestResourcePath', $requestResourcePath);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -59,7 +59,7 @@ class DefaultSqlExecutor implements SqlExecutor
|
||||
public function execute(string $sql, bool $rerunIfDeadlock = false): PDOStatement
|
||||
{
|
||||
if ($this->logAll) {
|
||||
$this->logger?->info("SQL: " . $sql);
|
||||
$this->logger?->info("SQL: " . $sql, ['isSql' => true]);
|
||||
}
|
||||
|
||||
if (!$rerunIfDeadlock) {
|
||||
@@ -81,7 +81,7 @@ class DefaultSqlExecutor implements SqlExecutor
|
||||
|
||||
if ($counter === 0 || !$this->isExceptionIsDeadlock($e)) {
|
||||
if ($this->logFailed) {
|
||||
$this->logger?->error("SQL failed: " . $sql);
|
||||
$this->logger?->error("SQL failed: " . $sql, ['isSql' => true]);
|
||||
}
|
||||
|
||||
/** @var PDOException $e */
|
||||
|
||||
@@ -236,6 +236,9 @@ return [
|
||||
'cleanupSubscribers' => true,
|
||||
'cleanupAudit' => true,
|
||||
'cleanupAuditPeriod' => '3 months',
|
||||
'cleanupAppLog' => true,
|
||||
'cleanupAppLogPeriod' => '30 days',
|
||||
'appLogAdminAllowed' => false,
|
||||
'currencyFormat' => 2,
|
||||
'currencyDecimalPlaces' => 2,
|
||||
'aclAllowDeleteCreated' => false,
|
||||
|
||||
@@ -111,6 +111,8 @@ return [
|
||||
'passwordChangeRequestNewUserLifetime',
|
||||
'passwordChangeRequestExistingUserLifetime',
|
||||
'passwordRecoveryInternalIntervalPeriod',
|
||||
'cleanupAppLog',
|
||||
'cleanupAppLogPeriod',
|
||||
],
|
||||
'adminItems' => [
|
||||
'devMode',
|
||||
@@ -219,6 +221,7 @@ return [
|
||||
'jobRunInParallel',
|
||||
'jobPoolConcurrencyNumber',
|
||||
'jobPeriodForActiveProcess',
|
||||
'appLogAdminAllowed',
|
||||
'cronMinInterval',
|
||||
'daemonInterval',
|
||||
'daemonProcessTimeout',
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
"User Interface": "User Interface",
|
||||
"Auth Tokens": "Auth Tokens",
|
||||
"Auth Log": "Auth Log",
|
||||
"App Log": "App Log",
|
||||
"Authentication": "Authentication",
|
||||
"Currency": "Currency",
|
||||
"Integrations": "Integrations",
|
||||
@@ -293,6 +294,7 @@
|
||||
"labelManager": "Customize application labels.",
|
||||
"templateManager": "Customize message templates.",
|
||||
"authLog": "Login history.",
|
||||
"appLog": "Application log.",
|
||||
"leadCapture": "API entry points for Web-to-Lead.",
|
||||
"attachments": "All file attachments stored in the system.",
|
||||
"systemRequirements": "System Requirements for EspoCRM.",
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"fields": {
|
||||
"message": "Message",
|
||||
"code": "Code",
|
||||
"level": "Level",
|
||||
"exceptionClass": "Exception Class",
|
||||
"file": "File",
|
||||
"line": "Line",
|
||||
"requestMethod": "Request Method",
|
||||
"requestResourcePath": "Request Resource Path"
|
||||
},
|
||||
"presetFilters": {
|
||||
"errors": "Errors"
|
||||
}
|
||||
}
|
||||
@@ -47,6 +47,7 @@
|
||||
"Preferences": "Preferences",
|
||||
"EmailAddress": "Email Address",
|
||||
"PhoneNumber": "Phone Number",
|
||||
"AppLogRecord": "App Log Record",
|
||||
"AuthLogRecord": "Auth Log Record",
|
||||
"AuthFailLogRecord": "Auth Fail Log Record",
|
||||
"LeadCapture": "Lead Capture Entry Point",
|
||||
@@ -100,6 +101,7 @@
|
||||
"AuthToken": "Auth Tokens",
|
||||
"UniqueId": "Unique IDs",
|
||||
"LastViewed": "Last Viewed",
|
||||
"AppLogRecord": "App Log",
|
||||
"AuthLogRecord": "Auth Log",
|
||||
"AuthFailLogRecord": "Auth Fail Log",
|
||||
"LeadCapture": "Lead Capture",
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
[
|
||||
{
|
||||
"rows": [
|
||||
[{"name": "level"}, false],
|
||||
[{"name": "message"}]
|
||||
]
|
||||
},
|
||||
{
|
||||
"rows": [
|
||||
[{"name": "code"}, false],
|
||||
[{"name": "exceptionClass"}],
|
||||
[{"name": "file"}],
|
||||
[{"name": "line"}, false]
|
||||
]
|
||||
},
|
||||
{
|
||||
"rows": [
|
||||
[{"name": "requestMethod"}, {"name": "requestResourcePath"}]
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,21 @@
|
||||
[
|
||||
{
|
||||
"rows": [
|
||||
[{"name": "level"}, false],
|
||||
[{"name": "message"}]
|
||||
]
|
||||
},
|
||||
{
|
||||
"rows": [
|
||||
[{"name": "code"}, false],
|
||||
[{"name": "exceptionClass"}],
|
||||
[{"name": "file"}],
|
||||
[{"name": "line"}, false]
|
||||
]
|
||||
},
|
||||
{
|
||||
"rows": [
|
||||
[{"name": "requestMethod"}, {"name": "requestResourcePath"}]
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,10 @@
|
||||
[
|
||||
"createdAt",
|
||||
"level",
|
||||
"code",
|
||||
"exceptionClass",
|
||||
"file",
|
||||
"line",
|
||||
"requestMethod",
|
||||
"requestResourcePath"
|
||||
]
|
||||
@@ -0,0 +1,26 @@
|
||||
[
|
||||
{"name": "level", "widthPx": 100},
|
||||
{"name": "code", "widthPx": 80},
|
||||
{"name": "message"},
|
||||
{"name": "createdAt", "width": 13},
|
||||
{
|
||||
"name": "exceptionClass",
|
||||
"width": 20,
|
||||
"hidden": true
|
||||
},
|
||||
{
|
||||
"name": "file",
|
||||
"width": 20,
|
||||
"hidden": true
|
||||
},
|
||||
{
|
||||
"name": "requestMethod",
|
||||
"width": 10,
|
||||
"hidden": true
|
||||
},
|
||||
{
|
||||
"name": "requestResourcePath",
|
||||
"width": 20,
|
||||
"hidden": true
|
||||
}
|
||||
]
|
||||
@@ -331,6 +331,12 @@
|
||||
"label": "Phone Numbers",
|
||||
"iconClass": "fas fa-phone",
|
||||
"description": "phoneNumbers"
|
||||
},
|
||||
{
|
||||
"url": "#Admin/appLog",
|
||||
"label": "App Log",
|
||||
"iconClass": "fas fa-list",
|
||||
"description": "appLog"
|
||||
}
|
||||
],
|
||||
"order": 25
|
||||
|
||||
@@ -27,5 +27,8 @@
|
||||
},
|
||||
"stars": {
|
||||
"className": "Espo\\Classes\\Cleanup\\Stars"
|
||||
},
|
||||
"appLog": {
|
||||
"className": "Espo\\Classes\\Cleanup\\AppLog"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"controller": "controllers/record",
|
||||
"createDisabled": true,
|
||||
"editDisabled": true,
|
||||
"mergeDisabled": true,
|
||||
"recordViews": {
|
||||
"list": "views/admin/app-log-record/record/list"
|
||||
},
|
||||
"filterList": [
|
||||
{
|
||||
"name": "errors"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
{
|
||||
"fields": {
|
||||
"number": {
|
||||
"type": "autoincrement",
|
||||
"dbType": "bigint"
|
||||
},
|
||||
"createdAt": {
|
||||
"type": "datetime",
|
||||
"readOnly": true
|
||||
},
|
||||
"message": {
|
||||
"type": "text",
|
||||
"readOnly": true,
|
||||
"orderDisabled": true
|
||||
},
|
||||
"level": {
|
||||
"type": "enum",
|
||||
"options": [
|
||||
"Debug",
|
||||
"Info",
|
||||
"Notice",
|
||||
"Warning",
|
||||
"Error",
|
||||
"Critical",
|
||||
"Alert",
|
||||
"Emergency"
|
||||
],
|
||||
"style": {
|
||||
"Info": "info",
|
||||
"Notice": "primary",
|
||||
"Warning": "warning",
|
||||
"Error": "danger",
|
||||
"Critical": "danger",
|
||||
"Alert": "danger",
|
||||
"Emergency": "danger"
|
||||
},
|
||||
"maxLength": 9,
|
||||
"readOnly": true,
|
||||
"index": true
|
||||
},
|
||||
"code": {
|
||||
"type": "int",
|
||||
"readOnly": true
|
||||
},
|
||||
"exceptionClass": {
|
||||
"type": "varchar",
|
||||
"maxLength": 512,
|
||||
"readOnly": true
|
||||
},
|
||||
"file": {
|
||||
"type": "varchar",
|
||||
"maxLength": 512,
|
||||
"readOnly": true
|
||||
},
|
||||
"line": {
|
||||
"type": "int",
|
||||
"readOnly": true
|
||||
},
|
||||
"requestMethod": {
|
||||
"type": "enum",
|
||||
"maxLength": 7,
|
||||
"options": [
|
||||
"GET",
|
||||
"POST",
|
||||
"PUT",
|
||||
"UPDATE",
|
||||
"DELETE",
|
||||
"PATCH",
|
||||
"HEAD",
|
||||
"OPTIONS",
|
||||
"TRACE"
|
||||
],
|
||||
"readOnly": true
|
||||
},
|
||||
"requestResourcePath": {
|
||||
"type": "varchar",
|
||||
"maxLength": 255,
|
||||
"readOnly": true
|
||||
},
|
||||
"requestUrl": {
|
||||
"type": "varchar",
|
||||
"maxLength": 512,
|
||||
"readOnly": true
|
||||
}
|
||||
},
|
||||
"links": {},
|
||||
"collection": {
|
||||
"orderBy": "number",
|
||||
"order": "desc",
|
||||
"textFilterFields": ["message"]
|
||||
},
|
||||
"indexes": {},
|
||||
"hooksDisabled": true
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"massActions": {
|
||||
"delete": {
|
||||
"allowed": true
|
||||
}
|
||||
},
|
||||
"actionHistoryDisabled": true
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"entity": true,
|
||||
"layouts": false,
|
||||
"tab": false,
|
||||
"acl": false,
|
||||
"customizable": false
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"primaryFilterClassNameMap": {
|
||||
"errors": "Espo\\Classes\\Select\\AppLogRecord\\PrimaryFilters\\Errors"
|
||||
}
|
||||
}
|
||||
@@ -412,6 +412,29 @@ class AdminController extends Controller {
|
||||
});
|
||||
}
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
actionAppLog() {
|
||||
this.collectionFactory.create('AppLogRecord', collection => {
|
||||
const searchManager = new SearchManager(
|
||||
collection,
|
||||
'list',
|
||||
this.getStorage(),
|
||||
this.getDateTime()
|
||||
);
|
||||
|
||||
searchManager.loadStored();
|
||||
|
||||
collection.where = searchManager.getWhere();
|
||||
collection.maxSize = this.getConfig().get('recordsPerPage') || collection.maxSize;
|
||||
|
||||
this.main('views/list', {
|
||||
scope: 'AppLogRecord',
|
||||
collection: collection,
|
||||
searchManager: searchManager
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
actionIntegrations(options) {
|
||||
const integration = options.name || null;
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2024 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
import ListRecordView from 'views/record/list';
|
||||
|
||||
export default class extends ListRecordView {
|
||||
|
||||
forceSettings = true
|
||||
}
|
||||
|
||||
@@ -55,11 +55,11 @@ class DefaultSidePanelView extends SidePanelView {
|
||||
const allFieldList = this.getFieldManager().getEntityTypeFieldList(this.model.entityType);
|
||||
|
||||
this.hasComplexCreated =
|
||||
allFieldList.includes('createdAt') &&
|
||||
allFieldList.includes('createdAt') ||
|
||||
allFieldList.includes('createdBy');
|
||||
|
||||
this.hasComplexModified =
|
||||
allFieldList.includes('modifiedAt') &&
|
||||
allFieldList.includes('modifiedAt') ||
|
||||
allFieldList.includes('modifiedBy');
|
||||
|
||||
super.setup();
|
||||
|
||||
Reference in New Issue
Block a user