Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use Tracy for error handling #1298

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,14 +98,15 @@
- RSS spout now prefers the feed logo to website favicon. ([#1152](https://github.com/fossar/selfoss/pull/1152))
- RSS spout now tries to use favicon from the feed domain when there is no logo or home page favicon. ([#1152](https://github.com/fossar/selfoss/pull/1152))
- Setting `DEBUG` to `1` in `src/common.php` no longer logs HTTP bodies, only headers. Set it to `2` if you need the bodies as well. ([#1152](https://github.com/fossar/selfoss/pull/1152))
- PHP startup errors are now logged, instead of having F3 crash with Error 500 ([#1195](https://github.com/fossar/selfoss/pull/1195))
- The debugging level (previously set by modifying `src/common.php`) can be changed in the `config.ini` using `debug` key. ([#1261](https://github.com/fossar/selfoss/pull/1261))
- In order to support offline mode, we moved much of the UI to the browser. ([#1150](https://github.com/fossar/selfoss/pull/1150), [#1184](https://github.com/fossar/selfoss/pull/1184), [#1215](https://github.com/fossar/selfoss/pull/1215), [#1216](https://github.com/fossar/selfoss/pull/1216))
- We carried out a significant internal refactoring ([#1164](https://github.com/fossar/selfoss/pull/1164), [#1190](https://github.com/fossar/selfoss/pull/1190))
- Removed Instapaper spout since it has been broken since its acquisition. Sources using it were migrated to “RSS Feed (with content extraction)”. ([#1245](https://github.com/fossar/selfoss/pull/1245))
- Placeholders are now used for images before they are loaded to avoid content jumping around ([#1204](https://github.com/fossar/selfoss/pull/1204))
- Search button is now always on the screen, avoiding the need to scroll to top to be able to use it. ([#1231](https://github.com/fossar/selfoss/issues/1231))
- Button for opening articles, tags, sources and filters in the sidebar, as well as the source and tag links in articles are now real links, allowing to open them in a new tab by middle-clicking them. ([#1216](https://github.com/fossar/selfoss/issues/1216), [#695](https://github.com/fossar/selfoss/issues/695))
- Configuration is no longer managed by F3 framework. ([#1261](https://github.com/fossar/selfoss/pull/1261))
- [F3 framework](https://fatfreeframework.com) is no longer used. So long… ([#1261](https://github.com/fossar/selfoss/pull/1261), [#1295](https://github.com/fossar/selfoss/pull/1295), [#1296](https://github.com/fossar/selfoss/pull/1296))
- [Tracy](https://tracy.nette.org/) is now used for error handling, resulting in much nicer error messages. ([#1296](https://github.com/fossar/selfoss/pull/1296))


## 2.18 – 2018-03-05
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ Very special thanks to all contributors of pull requests here on [GitHub](https:

Special thanks to the great programmers of these libraries used by selfoss:

* [FatFree PHP Framework](https://fatfreeframework.com/)
* [SimplePie](http://simplepie.org/)
* [jQuery](https://jquery.com/)
* [WideImage](http://wideimage.sourceforge.net/)
Expand All @@ -100,6 +99,7 @@ Special thanks to the great programmers of these libraries used by selfoss:
* [Spectrum Colorpicker](https://github.com/bgrins/spectrum)
* [Graby](https://github.com/j0k3r/graby)
* [FullTextRSS filters](http://help.fivefilters.org/customer/portal/articles/223153-site-patterns)
* [Tracy](https://tracy.nette.org/)

Icon made by http://blackbooze.com/

Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
"require": {
"php": ">= 5.6",
"ext-gd": "*",
"bcosca/fatfree-core": "^3.7.0",
"bramus/router": "^1.6",
"danielstjules/stringy": "^3.1",
"fossar/guzzle-transcoder": "^0.2.0",
Expand All @@ -23,6 +22,7 @@
"php-http/guzzle6-adapter": "^1.0",
"simplepie/simplepie": "^1.3",
"smottt/wideimage": "^1.1",
"tracy/tracy": "^2.5",
"violet/streaming-json-encoder": "^1.1",
"willwashburn/phpamo": "^1.0"
},
Expand Down
107 changes: 71 additions & 36 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions docs/content/docs/administration/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,16 @@ Port for database connections. By default `3306` will be used for MySQL and `543
A UNIX domain socket used for connecting to the MySQL database server. Usually, you want to use `db_host=localhost`, which should use the default socket path (typically `/run/mysqld/mysqld.sock` for MySQL or `/run/postgresql` for PostgreSQL) but if you need to specify a different location, you can. This is orthogonal to `db_host` option.
</div>

### `debug`
<div class="config-option">

Level of detail for diagnostics. Enable this for debug traces if you encounter selfoss internal errors or are developing selfoss.

* `0` (default) – Debugging is disabled, warnings will only be [logged](#logger-level).
* `1` – Debugging is enabled, any error or warning will terminate the application and cause debugging information to be printed into the web browser.
* `2` – Same as `1` but additional information (HTTP requests) will be logged when fetching feed content.
</div>

### `logger_destination`
<div class="config-option">

Expand Down
83 changes: 21 additions & 62 deletions src/common.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,42 +3,40 @@
use Dice\Dice;
use helpers\Configuration;
use helpers\DatabaseConnection;
use function helpers\sendError;
use Monolog\Formatter\LineFormatter;
use Monolog\Handler\ErrorLogHandler;
use Monolog\Handler\NullHandler;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
use Tracy\Debugger;

require __DIR__ . '/constants.php';
require_once __DIR__ . '/helpers/responses.php';

$autoloader = @include BASEDIR . '/vendor/autoload.php'; // we will show custom error
if ($autoloader === false) {
header('Content-type: text/plain');
echo 'The PHP dependencies are missing. Did you run `composer install` in the selfoss directory?';
exit;
}

$startup_error = error_get_last();

// F3 crashes when there were PHP startups error even though
// they might not affect the program (e.g. unable to load an extension).
// It also sets its own error_reporting value and uses the previous one
// as a signal to disable the initialization failure check.
error_reporting(0);

$f3 = Base::instance();

// Disable deprecation warnings.
// Dice uses ReflectionParameter::getClass(), which is deprecated in PHP 8
// but we have not set an error handler yet because it needs a Logger instantiated by Dice.
error_reporting(E_ALL & ~E_DEPRECATED);

$f3->set('AUTOLOAD', false);
$f3->set('BASEDIR', BASEDIR);
// Catch any errors and hopefully log them.
Debugger::$errorTemplate = __DIR__ . '/error.500.phtml';
Debugger::enable(Debugger::PRODUCTION);

$configuration = new Configuration(__DIR__ . '/../config.ini', $_ENV);

$f3->set('DEBUG', $configuration->debug);
$f3->set('cache', $configuration->cache);
if ($configuration->debug !== 0) {
// Enable strict mode to loudly fail on any error or warning.
// We ignore deprecation warnings because Dice uses deprecated
// ReflectionParameter::getClass(), which we cannot do anything about.
Debugger::$strictMode = E_ALL & ~E_DEPRECATED;
// Switch to development mode so that traces are displayed.
Debugger::enable(Debugger::DEVELOPMENT);
// Dispatch will not run in production mode preventing bar from loading.
Debugger::dispatch();
}

$dice = new Dice();

Expand Down Expand Up @@ -83,8 +81,7 @@
$dice->addRule(daos\TagsInterface::class, $shared);

if ($configuration->isChanged('dbSocket') && $configuration->isChanged('dbHost')) {
echo 'You cannot set both `db_socket` and `db_host` options.' . PHP_EOL;
exit;
sendError('You cannot set both `db_socket` and `db_host` options.' . PHP_EOL);
}

// Database connection
Expand Down Expand Up @@ -231,8 +228,7 @@ function($pattern, $text) {
} elseif ($logger_destination === 'error_log') {
$handler = new ErrorLogHandler(ErrorLogHandler::OPERATING_SYSTEM, $configuration->loggerLevel);
} else {
echo 'The `logger_destination` option needs to be either `error_log` or a file path prefixed by `file:`.';
exit;
sendError('The `logger_destination` option needs to be either `error_log` or a file path prefixed by `file:`.');
}

$formatter = new LineFormatter(null, null, true, true);
Expand All @@ -241,42 +237,5 @@ function($pattern, $text) {
}
$log->pushHandler($handler);

if (isset($startup_error)) {
$log->warn('PHP likely encountered a startup error: ', [$startup_error]);
}

// init error handling
$f3->set('ONERROR',
function(Base $f3) use ($configuration, $log, $handler) {
$exception = $f3->get('EXCEPTION');

try {
if ($exception) {
$log->error($exception->getMessage(), ['exception' => $exception]);
} else {
$log->error($f3->get('ERROR.text'));
}

if ($configuration->debug !== 0) {
echo 'An error occurred' . ': ';
echo $f3->get('ERROR.text') . "\n";
echo $f3->get('ERROR.trace');
} else {
if ($handler instanceof StreamHandler) {
echo 'An error occured, please check the log file “' . $handler->getUrl() . '”.' . PHP_EOL;
} elseif ($handler instanceof ErrorLogHandler) {
echo 'An error occured, please check your system logs.' . PHP_EOL;
} else {
echo 'An error occurred' . PHP_EOL;
}
}
} catch (Exception $e) {
echo 'Unable to write logs.' . PHP_EOL;
echo $e->getMessage() . PHP_EOL;
}
}
);

if ($configuration->debug !== 0) {
ini_set('display_errors', '0');
}
// Try to log errors encountered by error handler.
Debugger::setLogger($dice->create(helpers\TracyLogger::class));
2 changes: 2 additions & 0 deletions src/controllers/Index.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,13 @@ public function home() {
$home = BASEDIR . '/public/index.html';
if (!file_exists($home)) {
http_response_code(500);
header('Content-type: text/plain');
echo 'Please build the assets using `npm run build` or obtain a pre-built packages from https://selfoss.aditu.de.';
exit;
}

// show as full html page
header('Content-type: text/html');
readfile($home);

return;
Expand Down
9 changes: 5 additions & 4 deletions src/controllers/Opml/Export.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@ private function writeSource(array $source) {
public function export() {
$this->authentication->needsLoggedIn();

// save content as file and suggest file name
$exportName = 'selfoss-subscriptions-' . date('YmdHis') . '.xml';
header('Content-Disposition: attachment; filename="' . $exportName . '"');
header('Content-Type: text/xml; charset=UTF-8');

$this->logger->debug('start OPML export');
$this->writer->openMemory();
$this->writer->setIndent(true);
Expand Down Expand Up @@ -166,10 +171,6 @@ public function export() {
$this->writer->endDocument();
$this->logger->debug('finished OPML export');

// save content as file and suggest file name
$exportName = 'selfoss-subscriptions-' . date('YmdHis') . '.xml';
header('Content-Disposition: attachment; filename="' . $exportName . '"');
header('Content-Type: text/xml; charset=UTF-8');
echo $this->writer->outputMemory();
}
}
1 change: 1 addition & 0 deletions src/controllers/Opml/ImportPage.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public function __construct(Authentication $authentication) {
*/
public function show() {
$this->authentication->needsLoggedIn();
header('Content-type: text/html');
readfile(BASEDIR . '/public/opml.html');
}
}
4 changes: 4 additions & 0 deletions src/controllers/Sources/Update.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ public function __construct(Authentication $authentication, ContentLoader $conte
* @return void
*/
public function updateAll() {
header('Content-type: text/plain');

// only allow access for localhost and loggedin users
if (!$this->authentication->allowedToUpdate()) {
exit('unallowed access');
Expand All @@ -47,6 +49,8 @@ public function updateAll() {
* @return void
*/
public function update($id) {
header('Content-type: text/plain');

// only allow access for localhost and authenticated users
if (!$this->authentication->allowedToUpdate()) {
exit('unallowed access');
Expand Down
2 changes: 1 addition & 1 deletion src/controllers/Sources/Write.php
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ public function write($id = null) {

$validation = $this->sourcesDao->validate($title, $spout, $data);
if ($validation !== true) {
$this->view->error(json_encode($validation));
$this->view->jsonError($validation);
}

// add/edit source
Expand Down
Loading