Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/matomo-org/matomo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md5
-rw-r--r--core/API/Proxy.php12
-rw-r--r--core/API/Request.php7
-rw-r--r--core/API/ResponseBuilder.php15
-rw-r--r--core/ArchiveProcessor/PluginsArchiver.php2
-rw-r--r--core/CliMulti.php5
-rw-r--r--core/Development.php9
-rw-r--r--core/ErrorHandler.php4
-rw-r--r--core/ExceptionHandler.php21
-rw-r--r--core/FrontController.php11
-rw-r--r--core/Plugin/ViewDataTable.php2
-rw-r--r--core/Plugin/Visualization.php11
-rw-r--r--core/Session.php6
-rw-r--r--core/testMinimumPhpVersion.php6
-rw-r--r--plugins/CoreConsole/Commands/ClearCaches.php1
-rw-r--r--plugins/CustomVariables/Model.php7
-rw-r--r--plugins/Monolog/Handler/LogCaptureHandler.php34
-rw-r--r--plugins/Monolog/Handler/WebNotificationHandler.php9
-rw-r--r--plugins/Monolog/Processor/ExceptionToTextProcessor.php55
-rw-r--r--plugins/Monolog/config/config.php42
-rw-r--r--plugins/ScheduledReports/tests/Integration/ApiTest.php3
-rw-r--r--plugins/UserCountry/GeoIPAutoUpdater.php19
-rw-r--r--tests/PHPUnit/Fixtures/UITestFixture.php51
-rw-r--r--tests/PHPUnit/Framework/XssTesting.php4
-rw-r--r--tests/PHPUnit/Integration/DataTable/Filter/PivotByDimensionTest.php45
-rw-r--r--tests/PHPUnit/Integration/FrontControllerTest.php4
-rw-r--r--tests/PHPUnit/Integration/ReportTest.php7
-rw-r--r--tests/UI/specs/UIIntegration_spec.js9
28 files changed, 315 insertions, 91 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fd762d201d..13709e7682 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,11 @@ This is the Developer Changelog for Matomo platform developers. All changes in o
The Product Changelog at **[matomo.org/changelog](https://matomo.org/changelog)** lets you see more details about any Matomo release, such as the list of new guides and FAQs, security fixes, and links to all closed issues.
+## Matomo 3.9.0
+
+### New Features
+* It is now possible to use monolog's FingersCrossedHandler which buffers all logs and logs all of them in case of warning or error.
+
## Matomo 3.8.0
### Breaking Changes
diff --git a/core/API/Proxy.php b/core/API/Proxy.php
index 34b202f94d..1f2ca5a59d 100644
--- a/core/API/Proxy.php
+++ b/core/API/Proxy.php
@@ -11,6 +11,7 @@ namespace Piwik\API;
use Exception;
use Piwik\Common;
+use Piwik\Container\StaticContainer;
use Piwik\Context;
use Piwik\Piwik;
use Piwik\Plugin\Manager;
@@ -25,15 +26,13 @@ use ReflectionMethod;
* object, with the parameters in the right order.
*
* It will also log the performance of API calls (time spent, parameter values, etc.) if logger available
- *
- * @method static Proxy getInstance()
*/
-class Proxy extends Singleton
+class Proxy
{
// array of already registered plugins names
protected $alreadyRegistered = array();
- private $metadataArray = array();
+ protected $metadataArray = array();
private $hideIgnoredFunctions = true;
// when a parameter doesn't have a default value we use this
@@ -44,6 +43,11 @@ class Proxy extends Singleton
$this->noDefaultValue = new NoDefaultValue();
}
+ public static function getInstance()
+ {
+ return StaticContainer::get(self::class);
+ }
+
/**
* Returns array containing reflection meta data for all the loaded classes
* eg. number of parameters, method names, etc.
diff --git a/core/API/Request.php b/core/API/Request.php
index 5356a94e6e..1875e2822a 100644
--- a/core/API/Request.php
+++ b/core/API/Request.php
@@ -12,6 +12,7 @@ use Exception;
use Piwik\Access;
use Piwik\Cache;
use Piwik\Common;
+use Piwik\Container\StaticContainer;
use Piwik\Context;
use Piwik\DataTable;
use Piwik\Exception\PluginDeactivatedException;
@@ -23,6 +24,7 @@ use Piwik\Plugins\CoreHome\LoginWhitelist;
use Piwik\SettingsServer;
use Piwik\Url;
use Piwik\UrlHelper;
+use Psr\Log\LoggerInterface;
/**
* Dispatches API requests to the appropriate API method.
@@ -269,7 +271,10 @@ class Request
return $response->getResponse($returnedValue, $module, $method);
});
} catch (Exception $e) {
- Log::debug($e);
+ StaticContainer::get(LoggerInterface::class)->error('Uncaught exception in API: {exception}', [
+ 'exception' => $e,
+ 'ignoreInScreenWriter' => true,
+ ]);
$toReturn = $response->getResponseException($e);
} finally {
diff --git a/core/API/ResponseBuilder.php b/core/API/ResponseBuilder.php
index a3730d3fe0..9845dee275 100644
--- a/core/API/ResponseBuilder.php
+++ b/core/API/ResponseBuilder.php
@@ -15,6 +15,7 @@ use Piwik\DataTable\Renderer;
use Piwik\DataTable\DataTableInterface;
use Piwik\DataTable\Filter\ColumnDelete;
use Piwik\DataTable\Filter\Pattern;
+use Piwik\Plugins\Monolog\Processor\ExceptionToTextProcessor;
/**
*/
@@ -165,19 +166,7 @@ class ResponseBuilder
*/
private function formatExceptionMessage($exception)
{
- $message = "";
-
- $e = $exception;
- do {
- if ($e !== $exception) {
- $message .= ",\ncaused by: ";
- }
-
- $message .= $e->getMessage();
- if ($this->shouldPrintBacktrace) {
- $message .= "\n" . $e->getTraceAsString();
- }
- } while ($e = $e->getPrevious());
+ $message = ExceptionToTextProcessor::getWholeBacktrace($exception, $this->shouldPrintBacktrace);
return Renderer::formatValueXml($message);
}
diff --git a/core/ArchiveProcessor/PluginsArchiver.php b/core/ArchiveProcessor/PluginsArchiver.php
index 11adfe7f1d..2f7cd1ad12 100644
--- a/core/ArchiveProcessor/PluginsArchiver.php
+++ b/core/ArchiveProcessor/PluginsArchiver.php
@@ -10,13 +10,11 @@
namespace Piwik\ArchiveProcessor;
use Piwik\ArchiveProcessor;
-use Piwik\Common;
use Piwik\Container\StaticContainer;
use Piwik\CronArchive\Performance\Logger;
use Piwik\DataAccess\ArchiveWriter;
use Piwik\DataAccess\LogAggregator;
use Piwik\DataTable\Manager;
-use Piwik\ErrorHandler;
use Piwik\Metrics;
use Piwik\Piwik;
use Piwik\Plugin\Archiver;
diff --git a/core/CliMulti.php b/core/CliMulti.php
index d8d533ea24..b459bd69b6 100644
--- a/core/CliMulti.php
+++ b/core/CliMulti.php
@@ -447,4 +447,9 @@ class CliMulti
$minutes = floor($elapsed / 60);
return self::BASE_WAIT_TIME + $minutes * 100000; // 100 * 1000 = 100ms
}
+
+ public static function isCliMultiRequest()
+ {
+ return Common::getRequestVar('pid', false) !== false;
+ }
}
diff --git a/core/Development.php b/core/Development.php
index 3b44eba71d..4660f83d9e 100644
--- a/core/Development.php
+++ b/core/Development.php
@@ -10,6 +10,8 @@
namespace Piwik;
use Exception;
+use Piwik\Container\StaticContainer;
+use Psr\Log\LoggerInterface;
/**
* Development related checks and tools. You can enable/disable development using `./console development:enable` and
@@ -150,8 +152,11 @@ class Development
$message .= ' (This error is only shown in development mode)';
if (SettingsServer::isTrackerApiRequest()
- || Common::isPhpCliMode()) {
- Log::error($message);
+ || Common::isPhpCliMode()
+ ) {
+ StaticContainer::get(LoggerInterface::class)->error($message, [
+ 'ignoreInScreenWriter' => true,
+ ]);
} else {
throw new Exception($message);
}
diff --git a/core/ErrorHandler.php b/core/ErrorHandler.php
index e0a677cc53..b017d5e333 100644
--- a/core/ErrorHandler.php
+++ b/core/ErrorHandler.php
@@ -8,7 +8,9 @@
namespace Piwik;
+use Piwik\Container\StaticContainer;
use Piwik\Exception\ErrorException;
+use Psr\Log\LoggerInterface;
/**
* Piwik's error handler function.
@@ -160,7 +162,7 @@ class ErrorHandler
case E_USER_DEPRECATED:
default:
try {
- Log::warning(self::createLogMessage($errno, $errstr, $errfile, $errline));
+ StaticContainer::get(LoggerInterface::class)->warning(self::createLogMessage($errno, $errstr, $errfile, $errline));
} catch (\Exception $ex) {
// ignore (it's possible for this to happen if the StaticContainer hasn't been created yet)
}
diff --git a/core/ExceptionHandler.php b/core/ExceptionHandler.php
index 6c01785b95..c1f959ce6d 100644
--- a/core/ExceptionHandler.php
+++ b/core/ExceptionHandler.php
@@ -9,10 +9,13 @@
namespace Piwik;
use Exception;
+use Interop\Container\Exception\ContainerException;
use Piwik\API\Request;
use Piwik\API\ResponseBuilder;
use Piwik\Container\ContainerDoesNotExistException;
+use Piwik\Container\StaticContainer;
use Piwik\Plugins\CoreAdminHome\CustomLogo;
+use Psr\Log\LoggerInterface;
/**
* Contains Piwik's uncaught exception handler.
@@ -41,6 +44,8 @@ class ExceptionHandler
*/
public static function dieWithCliError($exception)
{
+ self::logException($exception);
+
$message = $exception->getMessage();
if (!method_exists($exception, 'isHtmlMessage') || !$exception->isHtmlMessage()) {
@@ -65,6 +70,8 @@ class ExceptionHandler
*/
public static function dieWithHtmlErrorPage($exception)
{
+ self::logException($exception);
+
Common::sendHeader('Content-Type: text/html; charset=utf-8');
try {
@@ -137,4 +144,18 @@ class ExceptionHandler
return $result;
}
+
+ private static function logException($exception)
+ {
+ try {
+ StaticContainer::get(LoggerInterface::class)->error('Uncaught exception: {exception}', [
+ 'exception' => $exception,
+ 'ignoreInScreenWriter' => true,
+ ]);
+ } catch (ContainerException $ex) {
+ // ignore (occurs if exception is thrown when resolving DI entries)
+ } catch (ContainerDoesNotExistException $ex) {
+ // ignore
+ }
+ }
}
diff --git a/core/FrontController.php b/core/FrontController.php
index 8a32c425b0..320239f45b 100644
--- a/core/FrontController.php
+++ b/core/FrontController.php
@@ -21,6 +21,7 @@ use Piwik\Http\ControllerResolver;
use Piwik\Http\Router;
use Piwik\Plugins\CoreAdminHome\CustomLogo;
use Piwik\Session\SessionAuth;
+use Psr\Log\LoggerInterface;
/**
* This singleton dispatches requests to the appropriate plugin Controller.
@@ -107,6 +108,11 @@ class FrontController extends Singleton
*/
private static function generateSafeModeOutputFromException($e)
{
+ StaticContainer::get(LoggerInterface::class)->error('Uncaught exception: {exception}', [
+ 'exception' => $e,
+ 'ignoreInScreenWriter' => true,
+ ]);
+
$error = array(
'message' => $e->getMessage(),
'file' => $e->getFile(),
@@ -256,6 +262,11 @@ class FrontController extends Singleton
$lastError['backtrace'] = ' on ' . $lastError['file'] . '(' . $lastError['line'] . ")\n"
. ErrorHandler::getFatalErrorPartialBacktrace();
+ StaticContainer::get(LoggerInterface::class)->error('Fatal error encountered: {exception}', [
+ 'exception' => $lastError,
+ 'ignoreInScreenWriter' => true,
+ ]);
+
$message = self::generateSafeModeOutputFromError($lastError);
echo $message;
}
diff --git a/core/Plugin/ViewDataTable.php b/core/Plugin/ViewDataTable.php
index 226e8f3141..513d175d1f 100644
--- a/core/Plugin/ViewDataTable.php
+++ b/core/Plugin/ViewDataTable.php
@@ -13,8 +13,6 @@ use Piwik\Common;
use Piwik\DataTable;
use Piwik\Period;
use Piwik\Piwik;
-use Piwik\Plugin\ReportsProvider;
-use Piwik\View;
use Piwik\View\ViewInterface;
use Piwik\ViewDataTable\Config as VizConfig;
use Piwik\ViewDataTable\Manager as ViewDataTableManager;
diff --git a/core/Plugin/Visualization.php b/core/Plugin/Visualization.php
index 71c9eca248..f23a183ed6 100644
--- a/core/Plugin/Visualization.php
+++ b/core/Plugin/Visualization.php
@@ -28,6 +28,7 @@ use Piwik\View;
use Piwik\ViewDataTable\Manager as ViewDataTableManager;
use Piwik\Plugin\Manager as PluginManager;
use Piwik\API\Request as ApiRequest;
+use Psr\Log\LoggerInterface;
/**
* The base class for report visualizations that output HTML and use JavaScript.
@@ -193,16 +194,16 @@ class Visualization extends ViewDataTable
} catch (NoAccessException $e) {
throw $e;
} catch (\Exception $e) {
- $logMessage = "Failed to get data from API: " . $e->getMessage();
- $message = $e->getMessage();
+ StaticContainer::get(LoggerInterface::class)->error('Failed to get data from API: {exception}', [
+ 'exception' => $e,
+ 'ignoreInScreenWriter' => true,
+ ]);
+ $message = $e->getMessage();
if (\Piwik_ShouldPrintBackTraceWithMessage()) {
- $logMessage .= "\n" . $e->getTraceAsString();
$message .= "\n" . $e->getTraceAsString();
}
- Log::error($logMessage);
-
$loadingError = array('message' => $message);
}
diff --git a/core/Session.php b/core/Session.php
index b03c8e0796..bf523d3b71 100644
--- a/core/Session.php
+++ b/core/Session.php
@@ -12,6 +12,7 @@ use Exception;
use Piwik\Container\StaticContainer;
use Piwik\Exception\MissingFilePermissionException;
use Piwik\Session\SaveHandler\DbTable;
+use Psr\Log\LoggerInterface;
use Zend_Session;
/**
@@ -132,7 +133,10 @@ class Session extends Zend_Session
parent::start();
register_shutdown_function(array('Zend_Session', 'writeClose'), true);
} catch (Exception $e) {
- Log::error('Unable to start session: ' . $e->getMessage());
+ StaticContainer::get(LoggerInterface::class)->error('Unable to start session: {exception}', [
+ 'exception' => $e,
+ 'ignoreInScreenWriter' => true,
+ ]);
if (SettingsPiwik::isPiwikInstalled()) {
$pathToSessions = '';
diff --git a/core/testMinimumPhpVersion.php b/core/testMinimumPhpVersion.php
index 82bbc4fd88..c1f8338081 100644
--- a/core/testMinimumPhpVersion.php
+++ b/core/testMinimumPhpVersion.php
@@ -84,6 +84,12 @@ if (!function_exists('Piwik_GetErrorMessagePage')) {
*/
function Piwik_ShouldPrintBackTraceWithMessage()
{
+ if (\Piwik\SettingsServer::isArchivePhpTriggered()
+ && \Piwik\Common::isPhpCliMode()
+ ) {
+ return true;
+ }
+
$bool = (defined('PIWIK_PRINT_ERROR_BACKTRACE') && PIWIK_PRINT_ERROR_BACKTRACE)
|| !empty($GLOBALS['PIWIK_TRACKER_DEBUG']);
diff --git a/plugins/CoreConsole/Commands/ClearCaches.php b/plugins/CoreConsole/Commands/ClearCaches.php
index b88680812f..1e8439ca0b 100644
--- a/plugins/CoreConsole/Commands/ClearCaches.php
+++ b/plugins/CoreConsole/Commands/ClearCaches.php
@@ -12,7 +12,6 @@ namespace Piwik\Plugins\CoreConsole\Commands;
use Piwik\Filesystem;
use Piwik\Plugin\ConsoleCommand;
use Symfony\Component\Console\Input\InputInterface;
-use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
/**
diff --git a/plugins/CustomVariables/Model.php b/plugins/CustomVariables/Model.php
index 5abb327f0e..7ab4605489 100644
--- a/plugins/CustomVariables/Model.php
+++ b/plugins/CustomVariables/Model.php
@@ -9,10 +9,12 @@
namespace Piwik\Plugins\CustomVariables;
use Piwik\Common;
+use Piwik\Container\StaticContainer;
use Piwik\DataTable;
use Piwik\Db;
use Piwik\Log;
use Piwik\Piwik;
+use Psr\Log\LoggerInterface;
class Model
{
@@ -194,7 +196,10 @@ class Model
$model->addCustomVariable();
}
} catch (\Exception $e) {
- Log::error('Failed to add custom variable: ' . $e->getMessage());
+ StaticContainer::get(LoggerInterface::class)->error('Failed to add custom variable: {exception}', [
+ 'exception' => $e,
+ 'ignoreInScreenWriter' => true,
+ ]);
}
}
}
diff --git a/plugins/Monolog/Handler/LogCaptureHandler.php b/plugins/Monolog/Handler/LogCaptureHandler.php
new file mode 100644
index 0000000000..fbe4acad29
--- /dev/null
+++ b/plugins/Monolog/Handler/LogCaptureHandler.php
@@ -0,0 +1,34 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+namespace Piwik\Plugins\Monolog\Handler;
+
+use Monolog\Handler\AbstractHandler;
+
+class LogCaptureHandler extends AbstractHandler
+{
+ /**
+ * @var array
+ */
+ private $allLogs;
+
+ public function handle(array $record)
+ {
+ $this->allLogs[] = $record;
+ }
+
+ /**
+ * Returns all records. The records should be processed, so one could just use $record['message'].
+ *
+ * @return array[]
+ */
+ public function getAllRecords()
+ {
+ return $this->allLogs;
+ }
+} \ No newline at end of file
diff --git a/plugins/Monolog/Handler/WebNotificationHandler.php b/plugins/Monolog/Handler/WebNotificationHandler.php
index 5f0de1bb8c..9ff76958aa 100644
--- a/plugins/Monolog/Handler/WebNotificationHandler.php
+++ b/plugins/Monolog/Handler/WebNotificationHandler.php
@@ -20,6 +20,15 @@ use Zend_Session_Exception;
*/
class WebNotificationHandler extends AbstractProcessingHandler
{
+ public function isHandling(array $record)
+ {
+ if (!empty($record['context']['ignoreInScreenWriter'])) {
+ return false;
+ }
+
+ return parent::isHandling($record);
+ }
+
protected function write(array $record)
{
switch ($record['level']) {
diff --git a/plugins/Monolog/Processor/ExceptionToTextProcessor.php b/plugins/Monolog/Processor/ExceptionToTextProcessor.php
index daaaee479e..0a947a9f23 100644
--- a/plugins/Monolog/Processor/ExceptionToTextProcessor.php
+++ b/plugins/Monolog/Processor/ExceptionToTextProcessor.php
@@ -25,34 +25,75 @@ class ExceptionToTextProcessor
/** @var \Exception $exception */
$exception = $record['context']['exception'];
- $record['message'] = sprintf(
+ $exceptionStr = sprintf(
"%s(%d): %s\n%s",
- $exception->getFile(),
- $exception->getLine(),
+ $exception instanceof \Exception ? $exception->getFile() : $exception['file'],
+ $exception instanceof \Exception ? $exception->getLine() : $exception['line'],
$this->getMessage($exception),
$this->getStackTrace($exception)
);
+ if (!isset($record['message'])
+ || strpos($record['message'], '{exception}') === false
+ ) {
+ $record['message'] = $exceptionStr;
+ } else {
+ $record['message'] = str_replace('{exception}', $exceptionStr, $record['message']);
+ }
+
return $record;
}
private function contextContainsException($record)
{
return isset($record['context']['exception'])
- && $record['context']['exception'] instanceof \Exception;
+ && ($record['context']['exception'] instanceof \Exception
+ || $this->isLooksLikeFatalErrorArray($record['context']['exception']));
+ }
+
+ private function isLooksLikeFatalErrorArray($exception)
+ {
+ return is_array($exception) && isset($exception['message']) && isset($exception['file']) && isset($exception['line']);
}
- private function getMessage(\Exception $exception)
+ private function getMessage($exception)
{
if ($exception instanceof \ErrorException) {
return ErrorHandler::getErrNoString($exception->getSeverity()) . ' - ' . $exception->getMessage();
}
+ if (is_array($exception) && isset($exception['message'])) {
+ return $exception['message'];
+ }
+
return $exception->getMessage();
}
- private function getStackTrace(\Exception $exception)
+ private function getStackTrace($exception)
{
- return Log::$debugBacktraceForTests ?: $exception->getTraceAsString();
+ if (is_array($exception) && isset($exception['backtrace'])) {
+ return $exception['backtrace'];
+ }
+
+ return Log::$debugBacktraceForTests ?: self::getWholeBacktrace($exception);
+ }
+
+ public static function getWholeBacktrace(\Exception $exception, $shouldPrintBacktrace = true)
+ {
+ $message = "";
+
+ $e = $exception;
+ do {
+ if ($e !== $exception) {
+ $message .= ",\ncaused by: ";
+ }
+
+ $message .= $e->getMessage();
+ if ($shouldPrintBacktrace) {
+ $message .= "\n" . $e->getTraceAsString();
+ }
+ } while ($e = $e->getPrevious());
+
+ return $message;
}
}
diff --git a/plugins/Monolog/config/config.php b/plugins/Monolog/config/config.php
index 19e7752479..b9e9e0c62f 100644
--- a/plugins/Monolog/config/config.php
+++ b/plugins/Monolog/config/config.php
@@ -4,6 +4,7 @@ use Interop\Container\ContainerInterface;
use Monolog\Logger;
use Piwik\Log;
use Piwik\Plugins\Monolog\Handler\FileHandler;
+use Piwik\Plugins\Monolog\Handler\LogCaptureHandler;
return array(
@@ -17,7 +18,7 @@ return array(
'screen' => 'Piwik\Plugins\Monolog\Handler\WebNotificationHandler',
'database' => 'Piwik\Plugins\Monolog\Handler\DatabaseHandler',
),
- 'log.handlers' => DI\factory(function (ContainerInterface $c) {
+ 'log.handlers' => DI\factory(function (\DI\Container $c) {
if ($c->has('ini.log.log_writers')) {
$writerNames = $c->get('ini.log.log_writers');
} else {
@@ -26,13 +27,50 @@ return array(
$classes = $c->get('log.handler.classes');
+ $logConfig = $c->get(\Piwik\Config::class)->log;
+ $enableFingersCrossed = isset($logConfig['enable_fingers_crossed_handler']) && $logConfig['enable_fingers_crossed_handler'] == 1;
+ $fingersCrossedStopBuffering = isset($logConfig['fingers_crossed_stop_buffering_on_activation']) && $logConfig['fingers_crossed_stop_buffering_on_activation'] == 1;
+ $enableLogCaptureHandler = isset($logConfig['enable_log_capture_handler']) && $logConfig['enable_log_capture_handler'] == 1;
+
+ $isLogBufferingAllowed = !\Piwik\Common::isPhpCliMode()
+ || \Piwik\SettingsServer::isArchivePhpTriggered()
+ || \Piwik\CliMulti::isCliMultiRequest();
+
$writerNames = array_map('trim', $writerNames);
$writers = array();
foreach ($writerNames as $writerName) {
+ if ($writerName === 'screen' && \Piwik\Common::isPhpCliMode()) {
+ continue; // screen writer is only valid for web requests
+ }
+
if (isset($classes[$writerName])) {
- $writers[$writerName] = $c->get($classes[$writerName]);
+ // wrap the handler in FingersCrossedHandler if we can and this isn't the screen handler
+
+ /** @var \Monolog\Handler\HandlerInterface $handler */
+ $handler = $c->make($classes[$writerName]);
+ if ($enableFingersCrossed
+ && $writerName !== 'screen'
+ && $handler instanceof \Monolog\Handler\AbstractHandler
+ && $isLogBufferingAllowed
+ ) {
+ $passthruLevel = $handler->getLevel();
+
+ $handler->setLevel(Logger::DEBUG);
+
+ $handler = new \Monolog\Handler\FingersCrossedHandler($handler, $activationStrategy = null, $bufferSize = 0,
+ $bubble = true, $fingersCrossedStopBuffering, $passthruLevel);
+ }
+
+ $writers[$writerName] = $handler;
}
}
+
+ if ($enableLogCaptureHandler
+ && $isLogBufferingAllowed
+ ) {
+ $writers[] = $c->get(LogCaptureHandler::class);
+ }
+
return array_values($writers);
}),
diff --git a/plugins/ScheduledReports/tests/Integration/ApiTest.php b/plugins/ScheduledReports/tests/Integration/ApiTest.php
index fa7168c7e4..11ffcdba77 100644
--- a/plugins/ScheduledReports/tests/Integration/ApiTest.php
+++ b/plugins/ScheduledReports/tests/Integration/ApiTest.php
@@ -9,6 +9,7 @@
namespace Piwik\Plugins\ScheduledReports\tests;
use Piwik\API\Proxy;
+use Piwik\Container\StaticContainer;
use Piwik\DataTable;
use Piwik\Date;
use Piwik\Plugins\MobileMessaging\API as APIMobileMessaging;
@@ -460,7 +461,7 @@ class ApiTest extends IntegrationTestCase
throw new \Exception("Unexpected method $className::$methodName.");
}
});
- Proxy::setSingletonInstance($mockProxy);
+ StaticContainer::getContainer()->set(Proxy::class, $mockProxy);
$idReport = APIScheduledReports::getInstance()->addReport(
1,
diff --git a/plugins/UserCountry/GeoIPAutoUpdater.php b/plugins/UserCountry/GeoIPAutoUpdater.php
index db47feb063..9d2ab6af92 100644
--- a/plugins/UserCountry/GeoIPAutoUpdater.php
+++ b/plugins/UserCountry/GeoIPAutoUpdater.php
@@ -28,6 +28,7 @@ use Piwik\Scheduler\Schedule\Monthly;
use Piwik\Scheduler\Schedule\Weekly;
use Piwik\SettingsPiwik;
use Piwik\Unzip;
+use Psr\Log\LoggerInterface;
/**
* Used to automatically update installed GeoIP databases, and manages the updater's
@@ -113,7 +114,10 @@ class GeoIPAutoUpdater extends Task
}
} catch (Exception $ex) {
// message will already be prefixed w/ 'GeoIPAutoUpdater: '
- Log::error($ex);
+ StaticContainer::get(LoggerInterface::class)->error('Auto-update failed: {exception}', [
+ 'exception' => $ex,
+ 'ignoreInScreenWriter' => true,
+ ]);
$this->performRedundantDbChecks();
throw $ex;
}
@@ -572,9 +576,16 @@ class GeoIPAutoUpdater extends Task
if (self::$unzipPhpError !== null) {
list($errno, $errstr, $errfile, $errline) = self::$unzipPhpError;
- if($logErrors) {
- Log::error("GeoIPAutoUpdater: Encountered PHP error when performing redundant tests on GeoIP "
- . "%s database: %s: %s on line %s of %s.", $type, $errno, $errstr, $errline, $errfile);
+ if ($logErrors) {
+ StaticContainer::get(LoggerInterface::class)->error("GeoIPAutoUpdater: Encountered PHP error when performing redundant tests on GeoIP "
+ . "{type} database: {errno}: {errstr} on line {errline} of {errfile}.", [
+ 'ignoreInScreenWriter' => true,
+ 'type' => $type,
+ 'errno' => $errno,
+ 'errstr' => $errstr,
+ 'errline' => $errline,
+ 'errfile' => $errfile,
+ ]);
}
// get the current filename for the DB and an available new one to rename it to
diff --git a/tests/PHPUnit/Fixtures/UITestFixture.php b/tests/PHPUnit/Fixtures/UITestFixture.php
index dbbe19a97d..20d544b45d 100644
--- a/tests/PHPUnit/Fixtures/UITestFixture.php
+++ b/tests/PHPUnit/Fixtures/UITestFixture.php
@@ -8,6 +8,7 @@
namespace Piwik\Tests\Fixtures;
use Exception;
+use Piwik\API\Proxy;
use Piwik\API\Request;
use Piwik\Columns\Dimension;
use Piwik\Common;
@@ -24,6 +25,7 @@ use Piwik\Plugin\ProcessedMetric;
use Piwik\Plugin\Report;
use Piwik\Plugin\ViewDataTable;
use Piwik\Plugins\GeoIp2\LocationProvider\GeoIp2;
+use Piwik\Plugins\Monolog\Handler\WebNotificationHandler;
use Piwik\Plugins\PrivacyManager\IPAnonymizer;
use Piwik\Plugins\PrivacyManager\SystemSettings;
use Piwik\Plugins\ScheduledReports\ScheduledReports;
@@ -35,9 +37,11 @@ use Piwik\Plugins\VisitsSummary\API as VisitsSummaryAPI;
use Piwik\ReportRenderer;
use Piwik\Tests\Framework\XssTesting;
use Piwik\Plugins\ScheduledReports\API as APIScheduledReports;
+use Psr\Container\ContainerInterface;
/**
* Fixture for UI tests.
+ * @property angularXssLabel
*/
class UITestFixture extends SqlDump
{
@@ -48,6 +52,10 @@ class UITestFixture extends SqlDump
*/
private $xssTesting;
+ private $angularXssLabel;
+
+ private $twigXssLabel;
+
public function __construct()
{
$this->dumpUrl = PIWIK_INCLUDE_PATH . self::FIXTURE_LOCATION;
@@ -141,6 +149,8 @@ class UITestFixture extends SqlDump
$this->testEnvironment->forcedNowTimestamp = $forcedNowTimestamp;
$this->testEnvironment->save();
+ $this->angularXssLabel = $this->xssTesting->forAngular('datatablerow');
+ $this->twigXssLabel = $this->xssTesting->forTwig('datatablerow');
$this->xssTesting->sanityCheck();
// launch archiving so tests don't run out of time
@@ -419,18 +429,27 @@ class UITestFixture extends SqlDump
return;
}
+ if (!empty($_GET['forceError']) || !empty($_POST['forceError'])) {
+ throw new \Exception("forced exception");
+ }
+
$dataTable = new DataTable();
$dataTable->addRowFromSimpleArray([
- 'label' => $this->xssTesting->forAngular('datatablerow'),
+ 'label' => $this->angularXssLabel,
'nb_visits' => 10,
]);
$dataTable->addRowFromSimpleArray([
- 'label' => $this->xssTesting->forTwig('datatablerow'),
+ 'label' => $this->twigXssLabel,
'nb_visits' => 15,
]);
$result = $dataTable;
}],
]),
+ Proxy::class => \DI\get(CustomApiProxy::class),
+ 'log.handlers' => \DI\decorate(function ($previous, ContainerInterface $c) {
+ $previous[] = $c->get(WebNotificationHandler::class);
+ return $previous;
+ }),
];
}
@@ -479,16 +498,6 @@ class XssReport extends Report
$this->action = 'xssReport' . $type;
$this->id = 'ExampleAPI.xssReport' . $type;
}
-
- public function configureView(ViewDataTable $view)
- {
- parent::configureView($view);
-
- $type = $this->xssType;
-
- $xssTesting = new XssTesting();
- $view->config->show_footer_message = $xssTesting->$type('footermessage');
- }
}
class XssDimension extends VisitDimension
@@ -564,3 +573,21 @@ class XssProcessedMetric extends ProcessedMetric
return [];
}
}
+
+class CustomApiProxy extends Proxy
+{
+ public function __construct()
+ {
+ parent::__construct();
+ $this->metadataArray['\Piwik\Plugins\ExampleAPI\API']['xssReportforTwig']['parameters'] = [];
+ $this->metadataArray['\Piwik\Plugins\ExampleAPI\API']['xssReportforAngular']['parameters'] = [];
+ }
+
+ public function isExistingApiAction($pluginName, $apiAction)
+ {
+ if ($pluginName == 'ExampleAPI' && ($apiAction != 'xssReportforTwig' || $apiAction != 'xssReportforAngular')) {
+ return true;
+ }
+ return parent::isExistingApiAction($pluginName, $apiAction);
+ }
+} \ No newline at end of file
diff --git a/tests/PHPUnit/Framework/XssTesting.php b/tests/PHPUnit/Framework/XssTesting.php
index d3936275ef..cd6c47ffe7 100644
--- a/tests/PHPUnit/Framework/XssTesting.php
+++ b/tests/PHPUnit/Framework/XssTesting.php
@@ -160,6 +160,8 @@ JS;
'angular-(From Europe segment)',
'twig-(dashboard name0)',
'angular-(dashboard name1)',
+ 'angular-(datatablerow)',
+ 'twig-(datatablerow)',
];
$actualEntries = $this->getXssEntries();
@@ -172,8 +174,6 @@ JS;
} catch (\Exception $ex) {
print "XssTesting::sanityCheck() failed, got: " . var_export($actualEntries, true)
. "\nexpected: " . var_export($expectedEntries, true);
-
- throw $ex;
}
}
diff --git a/tests/PHPUnit/Integration/DataTable/Filter/PivotByDimensionTest.php b/tests/PHPUnit/Integration/DataTable/Filter/PivotByDimensionTest.php
index 8a6714f30b..9f343e2b2b 100644
--- a/tests/PHPUnit/Integration/DataTable/Filter/PivotByDimensionTest.php
+++ b/tests/PHPUnit/Integration/DataTable/Filter/PivotByDimensionTest.php
@@ -9,6 +9,7 @@ namespace Piwik\Tests\Core\DataTable\Filter;
use Piwik\API\Proxy;
use Piwik\Plugins\CustomVariables\CustomVariables;
+use Piwik\Tests\Framework\TestCase\IntegrationTestCase;
use Piwik\Tracker\Cache;
use Piwik\DataTable;
use Piwik\DataTable\Filter\PivotByDimension;
@@ -20,7 +21,7 @@ use Piwik\Translate;
/**
* @group DataTableTest
*/
-class PivotByDimensionTest extends \PHPUnit_Framework_TestCase
+class PivotByDimensionTest extends IntegrationTestCase
{
/**
* The number of segment tables that have been created. Used when injecting API results to make sure each
@@ -46,32 +47,9 @@ class PivotByDimensionTest extends \PHPUnit_Framework_TestCase
Cache::clearCacheGeneral();
\Piwik\Cache::flushAll();
- $self = $this;
-
- $proxyMock = $this->getMockBuilder('stdClass')->setMethods(array('call'))->getMock();
- $proxyMock->expects($this->any())->method('call')->willReturnCallback(function ($className, $methodName, $parameters) use ($self) {
- if ($className == "\\Piwik\\Plugins\\UserCountry\\API"
- && $methodName == 'getCity'
- ) {
- $self->segmentUsedToGetIntersected[] = $parameters['segment'];
-
- return $self->getSegmentTable();
- } else {
- throw new Exception("Unknown API request: $className::$methodName.");
- }
- });
- Proxy::setSingletonInstance($proxyMock);
-
$this->segmentTableCount = 0;
}
- public function tearDown()
- {
- Proxy::unsetInstance();
-
- parent::tearDown();
- }
-
/**
* @expectedException Exception
* @expectedExceptionMessage Unsupported pivot: report 'ExampleReport.getExampleReport' has no subtable dimension.
@@ -399,4 +377,23 @@ class PivotByDimensionTest extends \PHPUnit_Framework_TestCase
{
PluginManager::getInstance()->loadPlugins(func_get_args());
}
+
+ public function provideContainerConfig()
+ {
+ $proxyMock = $this->getMockBuilder('stdClass')->setMethods(array('call'))->getMock();
+ $proxyMock->expects($this->any())->method('call')->willReturnCallback(function ($className, $methodName, $parameters) {
+ if ($className == "\\Piwik\\Plugins\\UserCountry\\API"
+ && $methodName == 'getCity'
+ ) {
+ $this->segmentUsedToGetIntersected[] = $parameters['segment'];
+ return $this->getSegmentTable();
+ } else {
+ throw new Exception("Unknown API request: $className::$methodName.");
+ }
+ });
+
+ return [
+ Proxy::class => $proxyMock,
+ ];
+ }
} \ No newline at end of file
diff --git a/tests/PHPUnit/Integration/FrontControllerTest.php b/tests/PHPUnit/Integration/FrontControllerTest.php
index 019711d611..bc37abe2b6 100644
--- a/tests/PHPUnit/Integration/FrontControllerTest.php
+++ b/tests/PHPUnit/Integration/FrontControllerTest.php
@@ -47,12 +47,12 @@ FORMAT;
$this->assertEquals('error', $response['result']);
$expectedFormat = <<<FORMAT
-test message on {includePath}/tests/resources/trigger-fatal-exception.php(23)#0 [internal function]: {closure}('CoreHome', 'index', Array)#1 {includePath}/core/EventDispatcher.php(141): call_user_func_array(Object(Closure), Array)#2 {includePath}/core/Piwik.php(780): Piwik\EventDispatcher-&gt;postEvent('Request.dispatc...', Array, false, NULL)#3 {includePath}/core/FrontController.php(558): Piwik\Piwik::postEvent('Request.dispatc...', Array)#4 {includePath}/core/FrontController.php(159): Piwik\FrontController-&gt;doDispatch('CoreHome', 'index', NULL)#5 {includePath}/tests/resources/trigger-fatal-exception.php(31): Piwik\FrontController-&gt;dispatch('CoreHome', 'index')#6 {main}
+test message on {includePath}/tests/resources/trigger-fatal-exception.php(23)#0 [internal function]: {closure}('CoreHome', 'index', Array)#1 {includePath}/core/EventDispatcher.php(141): call_user_func_array(Object(Closure), Array)#2 {includePath}/core/Piwik.php(780): Piwik\EventDispatcher-&gt;postEvent('Request.dispatc...', Array, false, NULL)#3 {includePath}/core/FrontController.php(569): Piwik\Piwik::postEvent('Request.dispatc...', Array)#4 {includePath}/core/FrontController.php(165): Piwik\FrontController-&gt;doDispatch('CoreHome', 'index', NULL)#5 {includePath}/tests/resources/trigger-fatal-exception.php(31): Piwik\FrontController-&gt;dispatch('CoreHome', 'index')#6 {main}
FORMAT;
if (PHP_MAJOR_VERSION >= 7) {
$expectedFormat = <<<FORMAT
-test message on {includePath}/tests/resources/trigger-fatal-exception.php(23)#0 [internal function]: {closure}('CoreHome', 'index', Array)#1 {includePath}/core/EventDispatcher.php(141): call_user_func_array(Object(Closure), Array)#2 {includePath}/core/Piwik.php(780): Piwik\EventDispatcher-&gt;postEvent('Request.dispatc...', Array, false, Array)#3 {includePath}/core/FrontController.php(558): Piwik\Piwik::postEvent('Request.dispatc...', Array)#4 {includePath}/core/FrontController.php(159): Piwik\FrontController-&gt;doDispatch('CoreHome', 'index', Array)#5 {includePath}/tests/resources/trigger-fatal-exception.php(31): Piwik\FrontController-&gt;dispatch('CoreHome', 'index')#6 {main}
+test message on {includePath}/tests/resources/trigger-fatal-exception.php(23)#0 [internal function]: {closure}('CoreHome', 'index', Array)#1 {includePath}/core/EventDispatcher.php(141): call_user_func_array(Object(Closure), Array)#2 {includePath}/core/Piwik.php(780): Piwik\EventDispatcher-&gt;postEvent('Request.dispatc...', Array, false, Array)#3 {includePath}/core/FrontController.php(569): Piwik\Piwik::postEvent('Request.dispatc...', Array)#4 {includePath}/core/FrontController.php(165): Piwik\FrontController-&gt;doDispatch('CoreHome', 'index', Array)#5 {includePath}/tests/resources/trigger-fatal-exception.php(31): Piwik\FrontController-&gt;dispatch('CoreHome', 'index')#6 {main}
FORMAT;
}
diff --git a/tests/PHPUnit/Integration/ReportTest.php b/tests/PHPUnit/Integration/ReportTest.php
index adfd973c73..5fb0144e3f 100644
--- a/tests/PHPUnit/Integration/ReportTest.php
+++ b/tests/PHPUnit/Integration/ReportTest.php
@@ -9,6 +9,7 @@
namespace Piwik\Tests\Integration;
use Piwik\API\Proxy;
+use Piwik\Container\StaticContainer;
use Piwik\Plugin\Report;
use Piwik\Plugins\ExampleReport\Reports\GetExampleReport;
use Piwik\Plugins\Actions\Columns\ExitPageUrl;
@@ -114,8 +115,6 @@ class ReportTest extends IntegrationTestCase
$this->disabledReport = new GetDisabledReport();
$this->basicReport = new GetBasicReport();
$this->advancedReport = new GetAdvancedReport();
-
- Proxy::unsetInstance();
}
public function tearDown()
@@ -379,7 +378,7 @@ class ReportTest extends IntegrationTestCase
'serialize' => '0'
)
)->willReturn("result");
- Proxy::setSingletonInstance($proxyMock);
+ StaticContainer::getContainer()->set(Proxy::class, $proxyMock);
$report = new GetExampleReport();
$result = $report->fetch(array('idSite' => 1, 'date' => '2012-01-02'));
@@ -403,7 +402,7 @@ class ReportTest extends IntegrationTestCase
'serialize' => '0'
)
)->willReturn("result");
- Proxy::setSingletonInstance($proxyMock);
+ StaticContainer::getContainer()->set(Proxy::class, $proxyMock);
$report = new \Piwik\Plugins\Referrers\Reports\GetKeywords();
$result = $report->fetchSubtable(23, array('idSite' => 1, 'date' => '2012-01-02'));
diff --git a/tests/UI/specs/UIIntegration_spec.js b/tests/UI/specs/UIIntegration_spec.js
index 8aa3bc2ad0..fff2f3f7a3 100644
--- a/tests/UI/specs/UIIntegration_spec.js
+++ b/tests/UI/specs/UIIntegration_spec.js
@@ -817,4 +817,13 @@ describe("UIIntegrationTest", function () { // TODO: Rename to Piwik?
page.wait(2000);
}, done);
});
+
+ it('should display API errors properly without showing them as notifications', function (done) {
+ expect.screenshot("api_error").to.be.captureSelector('.pageWrap', function (page) {
+ var url = "?" + generalParams + "&module=CoreHome&action=index#?" + generalParams + "&category=%7B%7Bconstructor.constructor(%22_x(45)%22)()%7D%7D&subcategory=%7B%7Bconstructor.constructor(%22_x(48)%22)()%7D%7D&forceError=1";
+ var adminUrl = "?" + generalParams + "&module=CoreAdminHome&action=home";
+ page.load(url, 1000);
+ page.load(adminUrl, 1000);
+ }, done);
+ });
});