mirror of
https://we.phorge.it/source/arcanist.git
synced 2024-12-22 21:40:54 +01:00
Add a simple primitive for managing PHP runtime error logs
Summary: Ref T13624. If we want to send PHP errors to a log, using the "error_log" configuration option catches the broadest set of errors across versions of PHP. Configuring this disables errors on `stderr`, since they're sent to the log instead. We'd like them to go to both places; provide a simple wrapper for this. Also do a bit of writability testing. Test Plan: Wrote errors to a new log, see followup changes. Maniphest Tasks: T13624 Differential Revision: https://secure.phabricator.com/D21578
This commit is contained in:
parent
e95afd1d00
commit
6d60422dbb
3 changed files with 104 additions and 1 deletions
|
@ -744,6 +744,7 @@ phutil_register_library_map(array(
|
|||
'PhutilEnglishCanadaLocale' => 'internationalization/locales/PhutilEnglishCanadaLocale.php',
|
||||
'PhutilErrorHandler' => 'error/PhutilErrorHandler.php',
|
||||
'PhutilErrorHandlerTestCase' => 'error/__tests__/PhutilErrorHandlerTestCase.php',
|
||||
'PhutilErrorLog' => 'filesystem/PhutilErrorLog.php',
|
||||
'PhutilErrorTrap' => 'error/PhutilErrorTrap.php',
|
||||
'PhutilEvent' => 'events/PhutilEvent.php',
|
||||
'PhutilEventConstants' => 'events/constant/PhutilEventConstants.php',
|
||||
|
@ -1816,6 +1817,7 @@ phutil_register_library_map(array(
|
|||
'PhutilEnglishCanadaLocale' => 'PhutilLocale',
|
||||
'PhutilErrorHandler' => 'Phobject',
|
||||
'PhutilErrorHandlerTestCase' => 'PhutilTestCase',
|
||||
'PhutilErrorLog' => 'Phobject',
|
||||
'PhutilErrorTrap' => 'Phobject',
|
||||
'PhutilEvent' => 'Phobject',
|
||||
'PhutilEventConstants' => 'Phobject',
|
||||
|
|
|
@ -52,7 +52,7 @@ final class Filesystem extends Phobject {
|
|||
* Make assertions about the state of path in preparation for
|
||||
* writeFile() and writeFileIfChanged().
|
||||
*/
|
||||
private static function assertWritableFile($path) {
|
||||
public static function assertWritableFile($path) {
|
||||
$path = self::resolvePath($path);
|
||||
$dir = dirname($path);
|
||||
|
||||
|
|
101
src/filesystem/PhutilErrorLog.php
Normal file
101
src/filesystem/PhutilErrorLog.php
Normal file
|
@ -0,0 +1,101 @@
|
|||
<?php
|
||||
|
||||
|
||||
final class PhutilErrorLog
|
||||
extends Phobject {
|
||||
|
||||
private $logName;
|
||||
private $logPath;
|
||||
|
||||
public function setLogName($log_name) {
|
||||
$this->logName = $log_name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLogName() {
|
||||
return $this->logName;
|
||||
}
|
||||
|
||||
public function setLogPath($log_path) {
|
||||
$this->logPath = $log_path;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLogPath() {
|
||||
return $this->logPath;
|
||||
}
|
||||
|
||||
public function activateLog() {
|
||||
$log_path = $this->getLogPath();
|
||||
|
||||
if ($log_path !== null) {
|
||||
// Test that the path is writable.
|
||||
$write_exception = null;
|
||||
try {
|
||||
Filesystem::assertWritableFile($log_path);
|
||||
} catch (FilesystemException $ex) {
|
||||
$write_exception = $ex;
|
||||
}
|
||||
|
||||
// If we hit an exception, try to create the containing directory.
|
||||
if ($write_exception) {
|
||||
$log_dir = dirname($log_path);
|
||||
if (!Filesystem::pathExists($log_dir)) {
|
||||
try {
|
||||
Filesystem::createDirectory($log_dir, 0755, true);
|
||||
} catch (FilesystemException $ex) {
|
||||
throw new PhutilProxyException(
|
||||
pht(
|
||||
'Unable to write log "%s" to path "%s". The containing '.
|
||||
'directory ("%s") does not exist or is not readable, and '.
|
||||
'could not be created.',
|
||||
$this->getLogName(),
|
||||
$log_path,
|
||||
$log_dir),
|
||||
$ex);
|
||||
}
|
||||
}
|
||||
|
||||
// If we created the parent directory, test if the path is writable
|
||||
// again.
|
||||
try {
|
||||
Filesystem::assertWritableFile($log_path);
|
||||
$write_exception = null;
|
||||
} catch (FilesystemException $ex) {
|
||||
$write_exception = $ex;
|
||||
}
|
||||
}
|
||||
|
||||
// If we ran into a write exception and couldn't resolve it, fail.
|
||||
if ($write_exception) {
|
||||
throw new PhutilProxyException(
|
||||
pht(
|
||||
'Unable to write log "%s" to path "%s" because the path is not '.
|
||||
'writable.',
|
||||
$this->getLogName(),
|
||||
$log_path),
|
||||
$write_exception);
|
||||
}
|
||||
}
|
||||
|
||||
ini_set('error_log', $log_path);
|
||||
PhutilErrorHandler::setErrorListener(array($this, 'onError'));
|
||||
}
|
||||
|
||||
public function onError($event, $value, array $metadata) {
|
||||
// If we've set "error_log" to a real file, so messages won't be output to
|
||||
// stderr by default. Copy them to stderr.
|
||||
|
||||
if ($this->logPath === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$message = idx($metadata, 'default_message');
|
||||
|
||||
if (strlen($message)) {
|
||||
$message = tsprintf("%B\n", $message);
|
||||
@fwrite(STDERR, $message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue